fxml에서 MenuBar만 생성하고 controller에서 MenuBar에 Menu를 추가하는 화면을 만들어보려 한다.
menu클릭 시 화면을 탭 형식으로 로드하는 형식으로 화면을 만들 생각이다.
fxml에서 AnchorPane안에 MenuBar을 생성 후 fx:id에 menuBar를 추가한다.
menuItem들은 controller에서 추가할 것이다.
<AnchorPane>
<children>
<MenuBar fx:id="menuBar" />
</children>
</Anchorpane>
fxml에서 생성한 fx:id의 menuBar를 controller에서 변수 선언한다.
Menu를 초기화 하고 메뉴에 들어갈 MenuItem들을 만들고 setOnAction 이벤트를 추가한다.
menuItem을 Menu에 담고 Menu을 fxml에서 만든 menuBar에 담는다.
mItem 이벤트의 createTab메소드는 메뉴를 클릭 시 탭 형식으로 화면을 보여주기 위한 메소드이다.
@FXML
private MenuBar menuBar;
private static Map<String, DraggableTab> tabMap = new HashMap<String, DraggableTab>();
@Override
public void initialize(URL location, ResourceBundle resources) {
Menu m1 = new Menu("메뉴1");
Menu m2 = new Menu("메뉴2");
Menu m3 = new Menu("메뉴3");
MenuItem mItem1 = new MenuItem("메뉴1_1");
mItem1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
createTab("", "", "");
}
});
MenuItem mItem2 = new MenuItem("메뉴2_1");
mItem2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
createTab("", "", "");
}
});
MenuItem mItem3 = new MenuItem("메뉴3_1");
mItem3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
createTab("", "", "");
}
});
m1.getItems().addAll(mItem1);
m2.getItems().addAll(mItem2);
m3.getItems().addAll(mItem3);
menuBar.getMenus().addAll(m1, m2, m3);
}
DraggbleTab을 생성하는 소스이다.
private void createTab(String viewName, String name, String viewPath) {
try{
if(!tabMap.containsKey(viewName) || tabMap.get(viewName).getTabPane() == null) {
tab = new DraggableTab(name);
view = FXMLLoader.load(getClass().getClassLoader().getResource(viewPath));
tab.setContent(view);
tabMap.put(viewName, tab);
tabs.getTabs().add(tab);
tabs.getSelectionModel().select(tab);
tab.setOnClosed(e -> tabMap.remove(view));
} else {
tabs.getSelectionModel().select(tabMap.get(viewName));
tabMap.get(viewName).getTabPane().getScene().getWindow().requestFocus();
}
} catch(Exception e) {
}
}
DraggableTab 클래스 소스이다.
탭을 드래그로 분리 및 이동을 할 수 있도록 도와주는 소스이다.
이 소스를 활용해서 탭형식의 화면을 만들고 분리할 수 있도록 했다.
public DraggableTab(String text) {
nameLabel = new Label(text);
setGraphic(nameLabel);
detachable = true;
dragStage = new Stage();
dragStage.initStyle(StageStyle.UNDECORATED);
StackPane dragStagePane = new StackPane();
dragStagePane.setStyle("-fx-background-color:#DDDDDD;");
dragText = new Text(text);
StackPane.setAlignment(dragText, Pos.CENTER);
dragStagePane.getChildren().add(dragText);
dragStage.setScene(new Scene(dragStagePane));
nameLabel.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
dragStage.setWidth(nameLabel.getWidth() + 10);
dragStage.setHeight(nameLabel.getHeight() + 10);
dragStage.setX(t.getScreenX());
dragStage.setY(t.getScreenY());
dragStage.show();
Point2D screenPoint = new Point2D(t.getScreenX(), t.getScreenY());
tabPanes.add(getTabPane());
InsertData data = getInsertData(screenPoint);
if(data == null || data.getInsertPane().getTabs().isEmpty()) {
markerStage.hide();
}
else {
int index = data.getIndex();
boolean end = false;
if(index == data.getInsertPane().getTabs().size()) {
end = true;
index--;
}
Rectangle2D rect = getAbsoluteRect(data.getInsertPane().getTabs().get(index));
if(end) {
markerStage.setX(rect.getMaxX() + 13);
}
else {
markerStage.setX(rect.getMinX());
}
markerStage.setY(rect.getMaxY() + 10);
markerStage.show();
}
}
});
nameLabel.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
markerStage.hide();
dragStage.hide();
if(!t.isStillSincePress()) {
Point2D screenPoint = new Point2D(t.getScreenX(), t.getScreenY());
TabPane oldTabPane = getTabPane();
int oldIndex = oldTabPane.getTabs().indexOf(DraggableTab.this);
tabPanes.add(oldTabPane);
InsertData insertData = getInsertData(screenPoint);
if(insertData != null) {
int addIndex = insertData.getIndex();
if(oldTabPane == insertData.getInsertPane() && oldTabPane.getTabs().size() == 1) {
return;
}
oldTabPane.getTabs().remove(DraggableTab.this);
if(oldIndex < addIndex && oldTabPane == insertData.getInsertPane()) {
addIndex--;
}
if(addIndex > insertData.getInsertPane().getTabs().size()) {
addIndex = insertData.getInsertPane().getTabs().size();
}
insertData.getInsertPane().getTabs().add(addIndex, DraggableTab.this);
insertData.getInsertPane().selectionModelProperty().get().select(addIndex);
return;
}
if(!detachable) {
return;
}
final Stage newStage = new Stage();
final TabPane pane = new TabPane();
tabPanes.add(pane);
newStage.setOnHiding(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
tabPanes.remove(pane);
}
});
getTabPane().getTabs().remove(DraggableTab.this);
pane.getTabs().add(DraggableTab.this);
pane.getTabs().addListener(new ListChangeListener<Tab>() {
#Override
public void onChanged(ListChangeListener.Change<? extends Tab> change) {
if(pane.getTabs().isEmpty()) {
newStage.hide();
}
}
});
newStage.setScene(new Scene(pane));
newStage.initStyle(StageStyle.UTILITY);
newStage.setX(t.getScreenX());
newStage.setY(t.getScreenY());
newStage.show();
pane.requestLayout();
pane.requestFocus();
}
}
});
}
/**
* Set whether it's possible to detach the tab from its pane and move it to
* another pane or another window. Defaults to true.
* <p>
* #param detachable true if the tab should be detachable, false otherwise.
*/
public void setDetachable(boolean detachable) {
this.detachable = detachable;
}
/**
* Set the label text on this draggable tab. This must be used instead of
* setText() to set the label, otherwise weird side effects will result!
* <p>
* #param text the label text for this tab.
*/
public void setLabelText(String text) {
nameLabel.setText(text);
dragText.setText(text);
}
private InsertData getInsertData(Point2D screenPoint) {
for(TabPane tabPane : tabPanes) {
Rectangle2D tabAbsolute = getAbsoluteRect(tabPane);
if(tabAbsolute.contains(screenPoint)) {
int tabInsertIndex = 0;
if(!tabPane.getTabs().isEmpty()) {
Rectangle2D firstTabRect = getAbsoluteRect(tabPane.getTabs().get(0));
if(firstTabRect.getMaxY()+60 < screenPoint.getY() || firstTabRect.getMinY() > screenPoint.getY()) {
return null;
}
Rectangle2D lastTabRect = getAbsoluteRect(tabPane.getTabs().get(tabPane.getTabs().size() - 1));
if(screenPoint.getX() < (firstTabRect.getMinX() + firstTabRect.getWidth() / 2)) {
tabInsertIndex = 0;
}
else if(screenPoint.getX() > (lastTabRect.getMaxX() - lastTabRect.getWidth() / 2)) {
tabInsertIndex = tabPane.getTabs().size();
}
else {
for(int i = 0; i < tabPane.getTabs().size() - 1; i++) {
Tab leftTab = tabPane.getTabs().get(i);
Tab rightTab = tabPane.getTabs().get(i + 1);
if(leftTab instanceof DraggableTab && rightTab instanceof DraggableTab) {
Rectangle2D leftTabRect = getAbsoluteRect(leftTab);
Rectangle2D rightTabRect = getAbsoluteRect(rightTab);
if(betweenX(leftTabRect, rightTabRect, screenPoint.getX())) {
tabInsertIndex = i + 1;
break;
}
}
}
}
}
return new InsertData(tabInsertIndex, tabPane);
}
}
return null;
}
private Rectangle2D getAbsoluteRect(Control node) {
return new Rectangle2D(node.localToScene(node.getLayoutBounds().getMinX(), node.getLayoutBounds().getMinY()).getX() + node.getScene().getWindow().getX(),
node.localToScene(node.getLayoutBounds().getMinX(), node.getLayoutBounds().getMinY()).getY() + node.getScene().getWindow().getY(),
node.getWidth(),
node.getHeight());
}
private Rectangle2D getAbsoluteRect(Tab tab) {
Control node = ((DraggableTab) tab).getLabel();
return getAbsoluteRect(node);
}
private Label getLabel() {
return nameLabel;
}
private boolean betweenX(Rectangle2D r1, Rectangle2D r2, double xPoint) {
double lowerBound = r1.getMinX() + r1.getWidth() / 2;
double upperBound = r2.getMaxX() - r2.getWidth() / 2;
return xPoint >= lowerBound && xPoint <= upperBound;
}
private static class InsertData {
private final int index;
private final TabPane insertPane;
public InsertData(int index, TabPane insertPane) {
this.index = index;
this.insertPane = insertPane;
}
public int getIndex() {
return index;
}
public TabPane getInsertPane() {
return insertPane;
}
}
}
'JavaFX' 카테고리의 다른 글
[JavaFX] JavaFX hibernate error : xxx is not mapped (0) | 2020.03.18 |
---|---|
[JavaFX] JavaFX 공통 페이징 처리 목록 만들기 (0) | 2020.03.16 |
[JavaFX] JavaFX 모든 윈도우 창 닫기 (0) | 2020.03.10 |
[JavaFX] JavaFX CSS 사용해서 UI 꾸미기 (0) | 2020.03.06 |
[JavaFX] JavaFX TableView Data 추가 TableView 컬럼 합치기 (0) | 2020.02.14 |