├── .gitignore ├── Hero-model-view-1024x555(2).png ├── JMetroSample-DansoftOwner_FXTaskbarProgressBar.jpg ├── JMetroSample-KEITHAYA_Tutorial.jpg ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── logo rounded with text v3 (300px).png ├── settings.gradle ├── transit-samples ├── build.gradle └── src │ └── main │ ├── java │ ├── com │ │ └── pixelduke │ │ │ └── samples │ │ │ └── transit │ │ │ ├── ColorPickerThrowsRuntimeException.java │ │ │ ├── ControlsSample.java │ │ │ ├── DatePickerAlignmentTestSample.java │ │ │ ├── DialogSample.java │ │ │ ├── DialogWithTextFieldSample.java │ │ │ ├── JMetroAppliedToParent.java │ │ │ ├── MDL2IconFontSample.java │ │ │ ├── MenuSample.java │ │ │ ├── OverridingStylesheetSample.java │ │ │ ├── OverridingStylesheetsMethodException.java │ │ │ ├── PanesWithBackgroundStyleClassSample.java │ │ │ ├── ScrollPaneSample.java │ │ │ ├── SegmentedButtonInsideToolBarSample.java │ │ │ ├── SplitPaneSample.java │ │ │ ├── SplitPaneSimpleSample.java │ │ │ ├── StatusBarSample.java │ │ │ ├── TabPaneSample.java │ │ │ ├── TabPaneWithUnderlineStyleSample.java │ │ │ ├── TableViewSample.java │ │ │ ├── TableViewWithSubheadersSample.java │ │ │ ├── TextFieldAndPasswordFieldShrinkGlitch.java │ │ │ ├── TextFieldDarkStyleIssue.java │ │ │ ├── TextFieldTextSample.java │ │ │ ├── TextNodesSample.java │ │ │ ├── ToggleSwitchThumbDisplacementBug.java │ │ │ ├── ToolbarWithControlsSample.java │ │ │ ├── TreeTableViewSample.java │ │ │ ├── TreeTableViewWithSubheaders.java │ │ │ ├── TreeViewSample.java │ │ │ ├── controlssample │ │ │ ├── ProgressBarController.java │ │ │ ├── ProgressIndicatorController.java │ │ │ └── SpinnerController.java │ │ │ ├── logo │ │ │ └── Logo.java │ │ │ ├── panessample │ │ │ ├── PanesSampleController.java │ │ │ └── PanesWithBackgroundStyleClassController.java │ │ │ └── themetester │ │ │ ├── AlignmentTestController.java │ │ │ ├── SamplePage.java │ │ │ ├── SamplePageChartHelper.java │ │ │ ├── SamplePageHelpers.java │ │ │ ├── SamplePageNavigation.java │ │ │ ├── SamplePageTableHelper.java │ │ │ ├── SamplePageTreeHelper.java │ │ │ ├── SamplePageTreeTableHelper.java │ │ │ └── ThemeTester.java │ └── module-info.java │ └── resources │ └── com │ └── pixelduke │ └── samples │ └── transit │ ├── ScrollPane Sample.fxml │ ├── Transit Accordion.fxml │ ├── Transit Button.fxml │ ├── Transit CheckBox.fxml │ ├── Transit ChoiceBox.fxml │ ├── Transit ColorPicker.fxml │ ├── Transit ComboBox.fxml │ ├── Transit ContextMenu.fxml │ ├── Transit DatePicker.fxml │ ├── Transit Hyperlink.fxml │ ├── Transit ListView.fxml │ ├── Transit MenuButton.fxml │ ├── Transit Panes.fxml │ ├── Transit PanesWithBackgroundStyleClass.fxml │ ├── Transit PasswordField.fxml │ ├── Transit ProgressBar.fxml │ ├── Transit ProgressIndicator.fxml │ ├── Transit RadioButton.fxml │ ├── Transit Rating.fxml │ ├── Transit ScrollBar.fxml │ ├── Transit ScrollPane.fxml │ ├── Transit Slider.fxml │ ├── Transit Spinner.fxml │ ├── Transit SplitMenuButton.fxml │ ├── Transit TextArea.fxml │ ├── Transit TextField.fxml │ ├── Transit TitledPane.fxml │ ├── Transit ToggleButton.fxml │ ├── Transit ToggleSwitch.fxml │ ├── Transit Tooltip.fxml │ ├── copy-16.png │ ├── images.jpg │ ├── logo │ ├── logo_16px.png │ └── logo_32px.png │ ├── mdl2-icon-font-sample.css │ ├── new.png │ ├── overriding-sample.css │ ├── play-16.png │ ├── settings-16.png │ ├── textFieldDarkStyleIssue.fxml │ ├── themetester │ ├── AlignmentTest.fxml │ ├── CombinationTest.fxml │ ├── ScottSelvia.fxml │ ├── TestApp.css │ ├── recorder-icon-48.png │ ├── reload_12x14.png │ └── ui-mosaic.fxml │ ├── tick-box-16.png │ ├── transit-toggle-switch.css │ ├── trash-16.png │ └── unchecked-checkbox-16.png └── transit ├── build.gradle └── src └── main ├── java ├── com │ └── pixelduke │ │ └── transit │ │ ├── FlatAlert.java │ │ ├── FlatChoiceDialog.java │ │ ├── FlatDialog.java │ │ ├── FlatTextInputDialog.java │ │ ├── MDL2IconCollection.java │ │ ├── MDL2IconFont.java │ │ ├── Style.java │ │ ├── TransitStyleClass.java │ │ └── TransitTheme.java └── module-info.java └── resources └── com └── pixelduke └── transit ├── base.css ├── base_extras.css ├── base_other_libraries.css ├── dark_theme.css ├── light_theme.css └── whiteIcon.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.class 3 | 4 | # Package Files # 5 | *.jar 6 | *.war 7 | *.ear 8 | 9 | # Scene builder backup files 10 | *.bak 11 | 12 | # windows thumbnail files 13 | *.db 14 | 15 | # Scenic view auxiliary file 16 | scenicView.properties 17 | 18 | # Intellij IDEA files 19 | .idea/ 20 | *.iml 21 | out/ 22 | 23 | # Gradle 24 | !gradle-wrapper.jar 25 | .gradle/ 26 | .nb-gradle/ 27 | build/ 28 | -------------------------------------------------------------------------------- /Hero-model-view-1024x555(2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukke/Transit/8276e5c91d8e95be42610d360e2b75c31e1b63ca/Hero-model-view-1024x555(2).png -------------------------------------------------------------------------------- /JMetroSample-DansoftOwner_FXTaskbarProgressBar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukke/Transit/8276e5c91d8e95be42610d360e2b75c31e1b63ca/JMetroSample-DansoftOwner_FXTaskbarProgressBar.jpg -------------------------------------------------------------------------------- /JMetroSample-KEITHAYA_Tutorial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukke/Transit/8276e5c91d8e95be42610d360e2b75c31e1b63ca/JMetroSample-KEITHAYA_Tutorial.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | logo 3 |

4 | 5 |

6 | Modern JavaFX theme that changes looks and enhances functionality 7 |

8 |
9 | 10 | ## Real World Examples 11 | ![Sample CAD app using JMetro](./Hero-model-view-1024x555(2).png) 12 | ![Sample DansoftOnwer FXTaskbarProgressBar](./JMetroSample-DansoftOwner_FXTaskbarProgressBar.jpg) 13 | 14 | ## Documentation 15 | Documentation of Transit can be found in this link: [Transit Java, JavaFX theme documentation](https://pixelduke.com/transit-java-javafx-theme/). 16 | 17 | ## Strengths and Key Principles 18 | * Modern look and feel 19 | * Zero tight coupling with this library: 20 | * No new controls. Functionality is added "behind the curtains" to existing JavaFX controls through the Skin API (FXSkins library) 21 | * Setting and unsetting is seamless and easy (only 1 line of code) even on already existing apps that don't use this theme 22 | * Transit has style definitions for both standard JavaFX controls and known libraries (ControlsFX) 23 | * Looks integrated on Windows (80%/90% of desktop users use Windows) and also works well on other OSes 24 | * Light and Dark versions; 25 | * Easily override and customize colors by overriding JavaFX CSS variables 26 | * Samples and theme tester app on samples sub-project 27 | * Lots of real-world, recognized Java apps already using it (NASA's applications, applications used in the White House, etc.) (JMetro and Transit) 28 | * Everything is accomplished with just using JavaFX alone. No need for other "CSS extension" technologies. 29 | * Leverages lessons learned developing JMetro theme 30 | 31 | This is a “pluggable” JavaFX theme (like JMetro). 32 | This means there’s zero coupling because this theme doesn’t define any new Controls and the developer only needs to run 1 line of 33 | code to set the theme (this is all the coupling you’ll get). 34 | Setting and unsetting is seamless and easy even on already existing apps that don't use this theme. 35 | It adds features to the existing JavaFX controls that you regularly use (controls from the standard JavaFX API or from known third 36 | party libraries) by leveraging the JavaFX Skin API. This is achieved through the [FXSkins library](https://pixelduke.com/fxskins/) which Transit depends on. 37 | 38 | Check [documentation](https://pixelduke.com/transit-java-javafx-theme/) for a deeper dive. 39 | 40 | ## Getting Transit 41 | You can get it through Maven Central. 42 | 43 | Here are examples for Gradle and Maven (replace the version number with the version you want): 44 | 45 | #### Gradle 46 | ```groovy 47 | implementation 'com.pixelduke:transit:2.0.0' 48 | ``` 49 | 50 | #### Maven 51 | ```xml 52 | 53 | com.pixelduke 54 | transit 55 | 2.0.0 56 | 57 | ``` 58 | 59 | ## Source code 60 | As of the writing of this document, the code is being compiled on Java 17 and JavaFX 20. 61 | 62 | The transit-samples subproject has samples that you can run and check out how to use FXSkins. 63 | 64 | ## Running the sample demos 65 | To run the demos, enter the following command in the Command Prompt / Terminal, inside the project directory: 66 | ``` 67 | gradlew run 68 | ``` 69 | Be sure to have your JAVA_HOME environment variable correctly set. 70 | To choose which of the demos to run, change the "gradle.build" script file inside "transit-samples" folder and uncomment which 71 | Application derived class you'd like to execute. 72 | 73 | ## Pull Requests (PR) 74 | We welcome contributions via PR. 75 | Before submitting a PR please file an issue for prior discussion. This will avoid you wasting time with a PR that 76 | might not be approved because, for instance, might be outside the intended scope of the project. 77 | 78 | ### Filing bugs 79 | When filing bugs it's most often good practice to attach a small sample app (as small, simple and with the fewest lines of code as possible). This app when executed, should show the bug happening. 80 | The reason for this is the limited amount of resources and time I have and also because in the process of filing a bug, developers sometimes discover that the bug isn't in the library but somewhere else. 81 | Without a small example app, the issue might be closed prematurely. 82 | 83 | ## Feedback request 84 | Please send pictures of your application that is using **transit**, or a site that shows your application. Or share it through Twitter (you can reference 85 | me through my Twitter handle @P_Duke if you'd like). 86 | This is very important for me to know how users are effectively using it and make adjustments accordingly to make Transit better. 87 | Also, and if you allow it, showcase example uses. 88 | Seeing this library get used also always motivates me to keep working on it. 89 | 90 | ## License 91 | Transit uses the ['GNU General Public License, version 2, with the Classpath Exception'](https://openjdk.java.net/legal/gplv2+ce.html) 92 | 93 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | group = 'com.pixelduke' 3 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukke/Transit/8276e5c91d8e95be42610d360e2b75c31e1b63ca/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if %ERRORLEVEL% equ 0 goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if %ERRORLEVEL% equ 0 goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /logo rounded with text v3 (300px).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukke/Transit/8276e5c91d8e95be42610d360e2b75c31e1b63ca/logo rounded with text v3 (300px).png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'transit' 2 | include 'transit', 'transit-samples' 3 | -------------------------------------------------------------------------------- /transit-samples/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'application' 3 | id 'org.openjfx.javafxplugin' version '0.0.13' 4 | } 5 | 6 | javafx { 7 | version = "22" 8 | modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.swing', 'javafx.web', 'javafx.graphics' ] 9 | } 10 | 11 | application { 12 | applicationDefaultJvmArgs = [ 13 | "--add-opens=javafx.controls/javafx.scene.control.skin=com.pixelduke.fxskins", 14 | "--add-opens=javafx.graphics/javafx.stage=com.pixelduke.fxthemes", 15 | "--add-exports=javafx.graphics/com.sun.javafx.tk.quantum=com.pixelduke.fxthemes" 16 | ] 17 | 18 | mainModule = 'com.pixelduke.samples.transit' 19 | 20 | /* Controls that have cells */ 21 | mainClass.set('com.pixelduke.samples.transit.TableViewSample') 22 | // mainClassName = 'com.pixelduke.samples.transit.TreeTableViewSample' 23 | // mainClassName = 'com.pixelduke.samples.transit.TreeViewSample' 24 | //mainClass.set('com.pixelduke.samples.transit.TreeTableViewWithSubheaders') 25 | //mainClass.set('com.pixelduke.samples.transit.TableViewWithSubheadersSample') 26 | 27 | // mainClass.set('com.pixelduke.samples.transit.PanesWithBackgroundStyleClassSample') 28 | 29 | // mainClass.set('com.pixelduke.samples.transit.TabPaneWithUnderlineStyleSample') 30 | //mainClass.set('com.pixelduke.samples.transit.TextNodesSample') 31 | //mainClass.set('com.pixelduke.samples.transit.StatusBarSample') 32 | //mainClass.set('com.pixelduke.samples.transit.ToolbarWithControlsSample') 33 | //mainClass.set('com.pixelduke.samples.transit.SplitPaneSample') 34 | //mainClass.set('com.pixelduke.samples.transit.SplitPaneSimpleSample') 35 | //mainClass.set('com.pixelduke.samples.transit.SegmentedButtonInsideToolBarSample') 36 | //mainClass.set('com.pixelduke.samples.transit.TextFieldTextSample') 37 | 38 | // mainClassName = 'com.pixelduke.samples.transit.DialogSample' 39 | 40 | //mainClass.set('com.pixelduke.samples.transit.MDL2IconFontSample') 41 | 42 | // mainClassName = 'com.pixelduke.samples.transit.ControlsSample' 43 | // mainClass = 'com.pixelduke.samples.transit.themetester.ThemeTester' 44 | 45 | // mainClassName = 'com.pixelduke.samples.transit.DatePickerAlignmentTestSample' 46 | 47 | 48 | //mainClass.set('com.pixelduke.samples.transit.ColorPickerThrowsRuntimeException') 49 | // mainClass.set('com.pixelduke.samples.transit.TextFieldAndPasswordFieldShrinkGlitch') 50 | //mainClass.set('com.pixelduke.samples.transit.ToggleSwitchThumbDisplacementBug') 51 | //mainClass.set('com.pixelduke.samples.transit.TextFieldDarkStyleIssue') 52 | //mainClass.set('com.pixelduke.samples.transit.JMetroAppliedToParent') 53 | // mainClass.set('com.pixelduke.samples.transit.JMetroDirectoryChooserTest') 54 | 55 | // mainClassName = 'com.pixelduke.samples.transit.DialogWithTextFieldSample' 56 | 57 | // mainClassName = 'com.pixelduke.samples.transit.OverridingStylesheetSample' 58 | 59 | /* Testing for errors */ 60 | // mainClassName = 'com.pixelduke.samples.transit.OverridingStylesheetsMethodException' 61 | } 62 | 63 | dependencies { 64 | implementation project(':transit') 65 | implementation 'org.controlsfx:controlsfx:11.1.0' 66 | 67 | implementation files('lib/scenicview.jar') 68 | } 69 | 70 | repositories { 71 | mavenCentral() 72 | } 73 | -------------------------------------------------------------------------------- /transit-samples/src/main/java/com/pixelduke/samples/transit/ColorPickerThrowsRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.pixelduke.samples.transit; 2 | 3 | import com.pixelduke.transit.TransitTheme; 4 | import com.pixelduke.transit.Style; 5 | import javafx.application.Application; 6 | import javafx.scene.Scene; 7 | import javafx.scene.control.ColorPicker; 8 | import javafx.scene.layout.Pane; 9 | import javafx.stage.Stage; 10 | 11 | public class ColorPickerThrowsRuntimeException extends Application { 12 | 13 | @Override 14 | public void start(Stage stage) { 15 | System.setProperty("prism.lcdtext", "false"); 16 | 17 | Scene scene = new Scene(new Pane(new ColorPicker()), 800, 600); 18 | stage.setScene(scene); 19 | TransitTheme transitTheme = new TransitTheme(scene, Style.DARK); 20 | stage.show(); 21 | } 22 | 23 | public static void main(String[] args) { 24 | launch(args); 25 | } 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /transit-samples/src/main/java/com/pixelduke/samples/transit/DatePickerAlignmentTestSample.java: -------------------------------------------------------------------------------- 1 | package com.pixelduke.samples.transit; 2 | 3 | import com.pixelduke.transit.TransitTheme; 4 | import javafx.application.Application; 5 | import javafx.scene.Scene; 6 | import javafx.scene.control.DatePicker; 7 | import javafx.scene.layout.HBox; 8 | import javafx.stage.Stage; 9 | import com.pixelduke.transit.TransitStyleClass; 10 | import com.pixelduke.transit.Style; 11 | 12 | public class DatePickerAlignmentTestSample extends Application { 13 | 14 | @Override 15 | public void start(Stage stage) { 16 | System.setProperty("prism.lcdtext", "false"); 17 | 18 | DatePicker datePicker1 = new DatePicker(); 19 | DatePicker datePicker2 = new DatePicker(); 20 | 21 | HBox container = new HBox(datePicker1, datePicker2); 22 | container.getStyleClass().add(TransitStyleClass.BACKGROUND); 23 | Scene scene = new Scene(container, 800, 600); 24 | stage.setScene(scene); 25 | new TransitTheme(scene, Style.LIGHT); 26 | stage.show(); 27 | } 28 | 29 | public static void main(String[] args) { 30 | launch(args); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /transit-samples/src/main/java/com/pixelduke/samples/transit/DialogWithTextFieldSample.java: -------------------------------------------------------------------------------- 1 | package com.pixelduke.samples.transit; 2 | 3 | import com.pixelduke.transit.FlatDialog; 4 | import com.pixelduke.transit.TransitTheme; 5 | import com.pixelduke.transit.Style; 6 | import javafx.application.Application; 7 | import javafx.geometry.Insets; 8 | import javafx.geometry.Pos; 9 | import javafx.scene.Scene; 10 | import javafx.scene.control.*; 11 | import javafx.scene.layout.BorderPane; 12 | import javafx.scene.layout.HBox; 13 | import javafx.scene.layout.VBox; 14 | import javafx.stage.Stage; 15 | 16 | import java.util.Optional; 17 | 18 | public class DialogWithTextFieldSample extends Application { 19 | private ToggleButton withOwner; 20 | private ComboBox