개발 환경 설정
- JavaFX 개발 환경 설정(넷빈즈 8.2, 오라클 JDK 1.8, Scene Builder)
- Scene Builder에 라이브러리 추가 하는 방법(JFoeniX, FontAwesomeFX)
- 넷빈즈 프로젝트 외부 라이브러리(jar) 등록하는 방법
탭 제목을 클릭할때마다 해당 탭이 상위로 올라오면서, 마치 메뉴처럼 구성된 UI 디자인입니다.
결과
프로젝트 다운로드
JavaFXVerticalMenuJFXTabpane.zip
2.48MB
프로젝트 구조
소스 코드
Main.java
package com.ozxexe.verticalmenu;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("main_view.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 600, 450));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java
package com.ozxexe.verticalmenu;
import com.jfoenix.controls.JFXTabPane;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Side;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.TextAlignment;
import java.io.IOException;
import java.net.URL;
public class Controller {
@FXML
private JFXTabPane tabContainer;
@FXML
private Tab userProfileTab;
@FXML
private AnchorPane userProfileContainer;
@FXML
private Tab settingsTab;
@FXML
private AnchorPane settingsContainer;
@FXML
private Tab logoutTab;
private double tabWidth = 90.0;
public static int lastSelectedTabIndex = 0;
/// Life cycle
@FXML
public void initialize() {
configureView();
}
/// Private
private void configureView() {
tabContainer.setTabMinWidth(tabWidth);
tabContainer.setTabMaxWidth(tabWidth);
tabContainer.setTabMinHeight(tabWidth);
tabContainer.setTabMaxHeight(tabWidth);
tabContainer.setRotateGraphic(true);
EventHandler<Event> replaceBackgroundColorHandler = event -> {
lastSelectedTabIndex = tabContainer.getSelectionModel().getSelectedIndex();
Tab currentTab = (Tab) event.getTarget();
if (currentTab.isSelected()) {
currentTab.setStyle("-fx-background-color: -fx-focus-color;");
} else {
currentTab.setStyle("-fx-background-color: -fx-accent;");
}
};
EventHandler<Event> logoutHandler = event -> {
Tab currentTab = (Tab) event.getTarget();
if (currentTab.isSelected()) {
tabContainer.getSelectionModel().select(lastSelectedTabIndex);
// TODO: logout action
// good place to show Dialog window with Yes / No question
System.out.println("Logging out!");
}
};
configureTab(userProfileTab, "User\nProfile", "/com/ozxexe/verticalmenu/resources/images/user-profile.png", userProfileContainer, getClass().getResource("userprofile.fxml"), replaceBackgroundColorHandler);
configureTab(settingsTab, "Settings", "/com/ozxexe/verticalmenu/resources/images/settings.png", settingsContainer, getClass().getResource("settings.fxml"), replaceBackgroundColorHandler);
configureTab(logoutTab, "Logout", "/com/ozxexe/verticalmenu/resources/images/logout.png", null, null, logoutHandler);
userProfileTab.setStyle("-fx-background-color: -fx-focus-color;");
}
private void configureTab(Tab tab, String title, String iconPath, AnchorPane containerPane, URL resourceURL, EventHandler<Event> onSelectionChangedEvent) {
double imageWidth = 40.0;
ImageView imageView = new ImageView(new Image(iconPath));
imageView.setFitHeight(imageWidth);
imageView.setFitWidth(imageWidth);
Label label = new Label(title);
label.setMaxWidth(tabWidth - 20);
label.setPadding(new Insets(5, 0, 0, 0));
label.setStyle("-fx-text-fill: black; -fx-font-size: 8pt; -fx-font-weight: normal;");
label.setTextAlignment(TextAlignment.CENTER);
BorderPane tabPane = new BorderPane();
tabPane.setRotate(90.0);
tabPane.setMaxWidth(tabWidth);
tabPane.setCenter(imageView);
tabPane.setBottom(label);
tab.setText("");
tab.setGraphic(tabPane);
tab.setOnSelectionChanged(onSelectionChangedEvent);
if (containerPane != null && resourceURL != null) {
try {
Parent contentView = FXMLLoader.load(resourceURL);
containerPane.getChildren().add(contentView);
AnchorPane.setTopAnchor(contentView, 0.0);
AnchorPane.setBottomAnchor(contentView, 0.0);
AnchorPane.setRightAnchor(contentView, 0.0);
AnchorPane.setLeftAnchor(contentView, 0.0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
main_view.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTabPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>
<StackPane prefHeight="431.0" prefWidth="661.0" stylesheets="@resources/styles/global.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ozxexe.verticalmenu.Controller">
<children>
<JFXTabPane fx:id="tabContainer" prefHeight="128.0" prefWidth="308.0" side="LEFT" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab fx:id="userProfileTab" closable="false" text="User Profile">
<content>
<AnchorPane fx:id="userProfileContainer" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</Tab>
<Tab fx:id="settingsTab" closable="false" text="Settings">
<content>
<AnchorPane fx:id="settingsContainer" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</Tab>
<Tab fx:id="logoutTab" closable="false" text="Logout">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</Tab>
</tabs>
</JFXTabPane>
</children>
</StackPane>
settings.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.4" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label layoutX="283.0" layoutY="192.0" text="SETTGINS" />
</children>
</AnchorPane>
userprofile.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.4" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button layoutX="119.0" layoutY="99.0" mnemonicParsing="false" text="USER PROFILE" />
</children>
</AnchorPane>
global.css
.root {
-fx-base: white;
-fx-color: -fx-base;
-fx-font-family: "Montserrat";
-fx-accent: rgb(246, 246, 246);
-fx-default-button: -fx-accent;
-jfx-primary-color: -fx-accent;
-jfx-light-primary-color: -fx-accent;
-jfx-dark-primary-color: -fx-accent;
-fx-focus-color: rgb(222, 222, 222);
-jfx-secondary-color: -fx-focus-color;
-jfx-light-secondary-color: -fx-focus-color;
-jfx-dark-secondary-color: -fx-focus-color;
}
/*******************************************************************************
* *
* JFX Tab Pane *
* *
******************************************************************************/
.jfx-tab-pane .headers-region {
-fx-background-color: -fx-accent;
}
.jfx-tab-pane .tab-header-background {
-fx-background-color: -fx-accent;
}
.jfx-tab-pane .tab-selected-line {
-fx-stroke: -fx-accent;
}
.jfx-tab-pane .tab-header-area .jfx-rippler {
-jfx-rippler-fill: -fx-focus-color;
}
.tab-selected-line {
-fx-background-color: -fx-focus-color;
}
팁
Controller.java
의 tabPane.setRotate(90.0);
코드를 제거하고, main_view.fxml
의 JFXTabPane
속성 side="LEFT"
제거 또는 TOP
을 변경한 결과는 다음과 같습니다.
참고사이트
Vertical, stateful JFXTabPane with icons in JavaFX
In this post, I will show you how to build a custom vertical tab bar with icons using JFXTabPane. Our main goal over here is to create a side menu with 1 tab being single state logout button. Let's take a look at the final result:
synappse.co
Synappse/tutorials
A place for all code used in our blog and youtube videos. - Synappse/tutorials
github.com
'Java | JavaFX' 카테고리의 다른 글
JavaFX 제목표시줄(타이틀바) 없애는 방법 예제 (0) | 2019.12.26 |
---|---|
JavaFX 마우스 오버 시, 슬라이드 메뉴 예제 (0) | 2019.12.26 |
JavaFX 웹 스타일 네이게이션 메뉴 예제(TranslateTransition) (0) | 2019.12.26 |
개발을 편의를 위해 설치해야 하는 유틸 프로그램 (0) | 2019.12.25 |
Scene Builder에 라이브러리 추가 하는 방법(JFoeniX, FontAwesomeFX) (1) | 2019.12.25 |