A lightweight RCP framework for JavaFX applications.

Related tags

GUI WorkbenchFX
Overview

WorkbenchFX

Travis CI Build Status Codecov.io Code Coverage Maven Central FOSSA Status

The one and only framework to build large JavaFX Applications!

screenshot of an application created with WorkbenchFX

Maven

To use this framework as part of your Maven build simply add the following dependency to your pom.xml file:

Java 8

<dependency>
  <groupId>com.dlsc.workbenchfx</groupId>
  <artifactId>workbenchfx-core</artifactId>
  <version>8.1.0</version>
</dependency>

Java 11

<dependency>
  <groupId>com.dlsc.workbenchfx</groupId>
  <artifactId>workbenchfx-core</artifactId>
  <version>11.1.0</version>
</dependency>

Gradle

To use this framework as part of your gradle build simply add the following to your build.gradle file and use the following dependency definition:

Java 8

dependencies {
    compile group: 'com.dlsc.workbenchfx', name: 'workbenchfx-core', version: '8.1.0'
}

Java 11

dependencies {
    compile group: 'com.dlsc.workbenchfx', name: 'workbenchfx-core', version: '11.1.0'
}

Table of Contents

What is WorkbenchFX?

WorkbenchFX is an out of the box solution to build large applications from multiple views, called modules. It offers you good user experience and a beautiful design.

As a developer, you often start with the views, so you can quickly show your progress to your customer. After that, some question may arise such as:

  • "How do I bring all those views together?"
  • "How do I build the navigation between those views?"
  • "How do I establish a good user experience?"

Exactly when those questions appear, WorkbenchFX comes into play: With WorkbenchFX you can focus on designing your views and meanwhile we're building the application around them.

WorkbenchFX also scales with growing requirements. In the beginning you just want to navigate through the views, but later on you probably would want to use a menu or a toolbar. Even that is supported by WorkbenchFX and you don't have to build anything by yourself.

If you still manage to start outgrowing the workbench, you can even replace whole parts of it with your own implementations, without having to rewrite the whole workbench.

Advantages

  • Less error-prone
  • Less code needed
  • Easy to learn
  • Easy to understand
  • Easy to use, especially for developers which have not much experience in working with JavaFX
  • A well designed, adaptable UI, inspired by the material design standards
  • Multiple, independent workbench modules, displayed in Tabs combine into one great application
  • The jdk8 branch works well with JPRO
  • FXML & Scene Builder support

Main Components

The most important components are noted in the picture and the corresponding table below:

screenshot of the addModulePage

Nr. Component Description
_ WorkbenchModule A Workbench consists of multiple modules. It contains a title, an icon and the content to be displayed in it. It represents the views mentioned in chapter What is WorkbenchFX?
2 Tile For each WorkbenchModule a Tile will be created. Clicking on the Tile opens the corresponding module
3 Tab A Tab will be displayed for each open module. Clicking on a Tab opens and shows the view of the corresponding module. Pressing the 'x' button closes the module
4 Tab bar The upper section of the window, where the Tabs of the current open modules are displayed
5 Add button The button used to open a new module. It opens an overview of all available modules
6 AddModulePage Stores all the Pages on which the Tiles are displayed
7 Page When more modules are loaded than defined in the modulesPerPage() attribute, the Workbench creates multiple Pages on which the Tiles are displayed
8 Pagination dots Are only displayed when having multiple Pages and can be used for navigating through them
9 Toolbar It contains ToolbarItems. If the bar does not contain any items, the toolbar will be hidden automatically
10 ToolbarItem Depending on the defined attributes, the item behaves like a JavaFX Label, Button or MenuButton (more about ToolbarItems: ToolbarItem)
11 Menu button It opens the NavigationDrawer. The position of the button varies depending on the amount of items to be displayed in the toolbar and the NavigationDrawer. If the NavigationDrawer does not contain any items, the button will not be displayed at all. If any items are in the toolbar, it will be displayed on the left side of the toolbar, otherwise on the left side of the tab bar

screenshot of the navigationDrawer

Nr. Component Description
12 NavigationDrawer It displays a logo which can be set in the stylesheet (described in chapter Setting a Logo) and the defined MenuItems. The default hover behavior over its items can be changed using the method call navigationDrawer.setMenuHoverBehavior(). It can be closed by clicking on the GlassPane or by pressing the back arrow button
13 GlassPane The GlassPane prevents click events on the components below and adds a scrim to the background. Unless a blocking (modal) overlay is being displayed, clicking on the GlassPane closes the overlay (more about the blocking attribute: Custom Overlay, Custom Dialog)

screenshot of the drawer

Nr. Component Description
14 Drawer It is possible to use workbench.showDrawer() to show drawers with custom content. All four sides of the window are supported (more about Drawers: Drawer)

screenshot of the dialog

Nr. Component Description
15 DialogControl Dialogs can be shown using a variety of predefined dialog types like showInformationDialog(), showErrorDialog, etc. Calling workbench.showDialog(WorkbenchDialog) shows a custom dialog (more about dialogs: Dialog)

screenshot of the moduleToolbar

Nr. Component Description
16 Module toolbar Displays the module's toolbar items (Workbench Module). The toolbar will automatically be shown as soon as there are items to be displayed and it will be hidden when there are none

For further information about the components, refer to the Javadoc

Documentation

The detailed documentation can be found in: workbenchfx-demo/src/main/resources/com/dlsc/workbenchfx/modules/webview/index.html

It can also be read by opening the Documentation module in ExtendedDemo or the CustomDemo.

Basic Structure

Workbench Concept

WorkbenchFX uses the builder pattern to create the Workbench object, since it allows to use optional features in a flexible way. The minimal usage requires only to specify the WorkbenchModule objects to be used in the Workbench. Afterwards, optional features can be defined using their respective method call before calling build().

For better illustration, the basic concept of creating a Workbench object is shown below:

Workbench workbench = 
    Workbench.builder( // Using the static method call
        new CustomWorkbenchModule() // class CustomWorkbenchModule extends WorkbenchModule
        ...
    )
    // .toolbarRight(...) // optional usage of additional features like navigationDrawer(), modulesPerPage(), etc.
    .build(); // The build call creates, initializes and returns the Workbench object

Note:

  • The result of the build() call is a Control which can be set in a scene
  • For use with FXML & Scene Builder, there is also a default constructor new Workbench(). However, in this case, modules and other optional features need to be defined separately afterwards

Module Lifecycle

The lifecycle methods are implicitly being called by the workbench. You must not call any of the lifecycle methods by yourself. To close and open modules use only workbench.openModule() and workbench.closeModule().

The abstract class WorkbenchModule contains four different lifecycle methods which can be overridden:

Method Description
init() Gets called when the module is being opened from the overview for the first time
activate() Gets called whenever the currently displayed content is being switched to this module
deactivate() Gets called whenever this module's currently displayed content is being switched to the content of another module
destroy() Gets called when this module is explicitly being closed by the user by clicking on the 'x' symbol in the Tab

When extending WorkbenchModule, it is only required to implement the activate() method. (Extending the WorkbenchModule)

Overriding all other lifecycle methods is optional and only needs to be done to perform additional actions in the lifecycle. Besides a call to super(), no further workbench-related code is required when overriding a lifecycle method.

Note:

  • For further information, refer to our documentation or the Javadoc
  • The full documentation about the module lifecycle can be found in the documentation file workbenchfx-demo/src/main/resources/com/dlsc/workbenchfx/modules/webview/index.html, in the section WorkbenchModule Lifecycle

Demos

We created several demos to visualize the capabilities of WorkbenchFX in the workbenchfx-demo folder:

File Description
SimpleDemo.java Shows the simplest usage of WorkbenchFX with only three modules and no optional features used
ExtendedDemo.java Shows a simple workbench application with most of the features used in a simple way.
CustomDemo.java A workbench application which uses all features, to demonstrate the full capability of WorkbenchFX
FXMLDemo.java A minimal example of how to use WorkbenchFX with FXML & Scene Builder

Getting started

Extending the WorkbenchModule

It is required to create a new class and extend WorkbenchModule, in order to create a custom module:

public class CustomModule extends WorkbenchModule {
  
}

It is then required to call the super() constructor and pass in a String as the name and either an Image, FontAwesomeIcon or MaterialDesignIcon as an icon for the module (icon cheatsheets: materialdesignicons.com, fontawesome.com):

public CustomModule() {
  super("My first Workbench module", MaterialDesignIcon.THUMB_UP); // a name and an icon is required
}

Furthermore, overriding the activate() method is also required. This lifecycle method will be called when clicking on the Tile to open the module (see Module Lifecycle):

@Override
public Node activate() {
  return new Label("Hello World"); // return here the actual content to display
}

The minimal implementation of a custom WorkbenchModule finally looks like the code snippet below. Returning a Hello World Label represents the view which will be displayed in the final application. For further information, refer to the Javadoc.

public class CustomModule extends WorkbenchModule {
  public CustomModule() {
      super("My first Workbench module", MaterialDesignIcon.THUMB_UP); // A name and an icon is required
  }
  @Override
  public Node activate() {
      return new Label("Hello World"); // return here the actual content to display
  }
}

Creating the Workbench

After extending the WorkbenchModule, the Workbench can be created. To do this, access the WorkbenchBuilder by calling Workbench.builder(), passing in the previously created module as an object and build the Workbench by calling workbench.build():

// Creating the Workbench
Workbench customWorkbench = Workbench.builder( // Getting a WorkbenchBuilder
    new CustomModule()                         // Adding the CustomModule
).build();                                     // Building the Workbench

For the final application, it can then be used in a Scene as follows:

public class CustomDemo extends Application {
  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    
    Workbench customWorkbench = Workbench.builder(
        new CustomModule()
    ).build();
    
    Scene myScene = new Scene(customWorkbench);
    primaryStage.setScene(myScene);
    primaryStage.setWidth(700);
    primaryStage.setHeight(450);
    primaryStage.show();
  }
}

This code snippet results in the following application:

custom workbench

The default implementation comes with a clickable Tile to open the module. Opening the module, creates a Tab with the defined icon and text. The content returned in the activate() method is displayed in the center. By clicking on the add button, you can get back to the AddModulePage. Closing the opened module is achieved through clicking on the close button in the Tab.

Single Module Layout

If the workbench consists of only one module, a single module layout is used to display the module. In the single module layout, the tab bar and the add module button are not visible and the module is automatically opened on startup.
This results in a very basic application as can be seen below

single module layout

Optional Methods

WorkbenchBuilder

These optional method calls are called after adding the custom modules to the builder:

Workbench workbench = Workbench.builder(...)
.modulesPerPage(6) // call the optional methods
.build();

The following methods are optionally available to further configure the Workbench:

Method in WorkbenchBuilder Description
modulesPerPage() Defines the amount of Tiles that should be shown per Page in AddModulePage. The default value is set to 6
navigationDrawerItems() Allows to add MenuItems which are then displayed in the NavigationDrawer.
toolbarLeft() Allows to add ToolbarItems on the left side of the toolbar on top of the Tabs
toolbarRight() Allows to add ToolbarItems on the right side of the toolbar on top of the Tabs

When the default layout of Page, Tab, Tile or NavigationDrawer don't fulfill the desired requirements, it is possible to replace them:

Method in WorkbenchBuilder Description
navigationDrawer() Allows setting a custom implementation of the NavigationDrawer control, which will then be used
pageFactory() Requires a Callback function which takes a Workbench and then returns a custom implementation of a Page control
tabFactory() Requires a Callback function which takes a Workbench and then returns a custom implementation of a Tab control
tileFactory() Requires a Callback function which takes a Workbench and then returns a custom implementation of a Tile control

Workbench

After the build() call on WorkbenchBuilder, the Workbench is created. The following selective calls might be of interest:

Method in Workbench Description
showNavigationDrawer() Shows the NavigationDrawer
getNavigationDrawer() Returns the NavigationDrawer
getNavigationDrawerItems() Returns the ObservableList of the drawer's ToolbarItems
openModule() Opens the specified module
getModules() Returns a list of all modules stored in the workbench
show...Dialog() Shows a predefined dialog
showDialog() Shows a custom dialog
showDrawer() Shows a custom drawer
getToolbarControlsLeft() Returns the list of items on the left of the Toolbar
getToolbarControlsRight() Returns the list of items on the right of the Toolbar
showOverlay() Shows a custom overlay
hideOverlay() Hides a custom overlay

WorkbenchModule

The WorkbenchModule also provides useful functionality. It is possible to add ToolbarItems to the toolbar of the module (just like in the workbench):

Method (WorkbenchModule) Description
getWorkbench() In the init() call, the Workbench is stored in the module. Calling this enables to call methods on the Workbench within the WorkbenchModule.
getToolbarControlsLeft() Returns a list of ToolbarItems. Adding items to the list will automatically create a toolbar between the tab bar and the module content and show the items on the left side
getToolbarControlsRight() Returns a list of ToolbarItems. Adding items to the list will automatically create a toolbar between the tab bar and the module content and show the items on the right side
close() Will immediately close the module, without calling destroy() first (see Module Lifecycle)

Using the Components

ToolbarItem

The ToolbarItems which can be set in the toolbars of either the workbench or the module are styled and behave differently based on their content. If for example the item contains a String as text and a MenuItem it is automatically assumed that the styling and behavior of a MenuButton is needed. If on the other hand only an IconView is defined, it is assumed, the behavior of a Label is desired.

Adding different attributes to the ToolbarItem results in different representations: They can also be seen in the toolbar of the CustomDemo

Syntax Representation
// Label with text
ToolbarItem toolbarItem = new ToolbarItem("Hello World");
// Label with graphic
ToolbarItem toolbarItem = new ToolbarItem(
  new MaterialDesignIconView(MaterialDesignIcon.THUMB_UP)
);
// Label with text and graphic
ToolbarItem toolbarItem = new ToolbarItem(
  "Hello World",
  new MaterialDesignIconView(MaterialDesignIcon.THUMB_UP)
);
// Button with text
ToolbarItem toolbarItem = new ToolbarItem(
  "Hello World", event -> System.out.println("Hello World")
);
// Button with graphic
ToolbarItem toolbarItem = new ToolbarItem(
  new MaterialDesignIconView(MaterialDesignIcon.THUMB_UP),
  event -> System.out.println("Hello World")
);
// Button with text and graphic
ToolbarItem toolbarItem = new ToolbarItem(
  "Hello World",
  new MaterialDesignIconView(MaterialDesignIcon.THUMB_UP),
  event -> System.out.println("Hello World")
);
// MenuButton with text
ToolbarItem toolbarItem = new ToolbarItem(
  "Hello World",
  new MenuItem("Content 1"), new MenuItem("Content 2")
);
// MenuButton with graphic
ToolbarItem toolbarItem = new ToolbarItem(
  new MaterialDesignIconView(MaterialDesignIcon.THUMB_UP),
  new MenuItem("Content 1"), new MenuItem("Content 2")
);
// MenuButton with text and graphic
ToolbarItem toolbarItem = new ToolbarItem(
  "Hello World",
  new MaterialDesignIconView(MaterialDesignIcon.THUMB_UP),
  new MenuItem("Content 1"), new MenuItem("Content 2")
);
// MenuButton with a MenuItem containing custom content
ToolbarItem toolbarItem = new ToolbarItem(
  "Account",
  new MaterialDesignIconView(MaterialDesignIcon.ACCOUNT),
  new MenuItem("",
    new HBox(
      new Label("Login: "),
      new TextField(),
      new Button("", new MaterialDesignIconView(
        MaterialDesignIcon.PLUS))
    )
  )
);

Dialog

A demo of the dialogs can be found in the DialogTestModule of the Custom Demo

Predefined Dialog Types

WorkbenchFX comes with a lot of predefined dialog types. Using them is as simple as calling workbench.show...Dialog() with the desired dialog type. After clicking on one of the Buttons of a dialog, the corresponding ButtonType is returned as the result of the dialog. Therefore it is required to define a Consumer<ButtonType> for every dialog to validate the answer. A few examples on how to use them are listed below:

// Precondition
Workbench workbench = Workbench.builder(...).build; // Creating the workbench
Button dialogBtn = new Button("Show Dialog"); // Assuming the button is used in a module
Syntax Outcome
// Confirmation Dialog
dialogBtn.setOnAction(event ->
  workbench.showConfirmationDialog(
    "Continue without saving?",
    "Are you sure you want to continue without saving"
      + "your document?",
    buttonType -> { // Proceed and validate the result }
  )
);
// Error Dialog
dialogBtn.setOnAction(event ->
  workbench.showErrorDialog(
    "Button click failed!",
    "During the click of this button, something went"
      + "horribly wrong.",
    buttonType -> { // Proceed and validate the result }
  )
);
// Error Dialog with exception
dialogBtn = null; // Provokes an exception
try {
  dialogBtn.setOnAction(
    event -> System.out.println("Throws NPE!"));
} catch (NullPointerException exception) {
  workbench.showErrorDialog(
    "Button click failed!",
    "During the click of this button, something went "
      + "horribly wrong. Please forward the content "
      + "below to anyone but the WorkbenchFX "
      + "developers to track down the issue:",
    exception
    buttonType -> { // Proceed and validate the result }
  );
}
// Error Dialog with details
dialogBtn.setOnAction(event ->
  workbench.showErrorDialog(
    "Button click failed!",
    "During the click of this button, something went"
      + "horribly wrong.",
    "Details about this exception are not present.",
    buttonType -> { // Proceed and validate the result }
  )
);
// Warning Dialog
dialogBtn.setOnAction(event ->
  workbench.showWarningDialog(
    "Reset settings?",
    "This will reset your device to its default"
      + "factory settings.",
    buttonType -> { // Proceed and validate the result }
  )
);
// Information Dialog
dialogBtn.setOnAction(event ->
  workbench.showInformationDialog(
    "Just to let you know",
    "(This is an information dialog)",
    buttonType -> { // Proceed and validate the result }
  )
);

Custom Dialog

Sometimes just using the default dialog types are not enough. For such special cases, the workbench.showDialog() method can be used. With WorkbenchDialog.builder() a custom dialog can be created. The builder provides some useful methods which can be used:

WorkbenchDialog.builder(Parameters) Description
String title Required and defines the title of the dialog
String message Optionally either message or content can be defined. The message is located below the title
Node content A Node with custom content
Type type Defines one of the default dialog types like Type.ERROR, Type.INFORMATION, etc. The corresponding buttons and style class will automatically be set
ButtonType... buttonTypes All the specified button types will be set (eg. OK, CANCEL and APPLY for a preferences dialog)

Note:

  • Defining content will override further definitions of message, details or exception
WorkbenchDialog.builder().Parameters Description
blocking(boolean) Defines whether clicking on the GlassPane closes the dialog or not (i.e. forcing a decision when blocking)
onResult(Consumer<ButtonType>) After clicking on a dialog button, the clicked ButtonType is returned. Enables to define an action to be performed when a dialog button was pressed
details(String) The dialog will display the specified error message (Error Dialog With Details). Will not be displayed when defining a content
exception(Exception) The dialog will display the stacktrace of a specified Exception (Error Dialog With Exception). Will not be displayed when defining a content
maximized(boolean) Defines whether the dialog's size should take up the whole window or only as much as needed by the content
showButtonsBar(boolean) Defines whether the dialog's buttons should be shown or not
onShown(EventHandler<Event>) The EventHandler which is called when the dialog is showing
onHidden(EventHandler<Event>) The EventHandler which is called when the dialog is hidden
dialogControl(DialogControl) Makes it possible to define a custom DialogControl
build() Builds the WorkbenchDialog
WorkbenchDialog Description
getButton(ButtonType buttonType) Returns an Optional<Button> of the dialog. Useful when accessing the buttons of the dialog is needed

Using the builder it is possible to write some interesting custom dialogs:

// Precondition
Workbench workbench = Workbench.builder(...).build; // Creating the workbench
Button dialogBtn = new Button("Show Dialog"); // Assuming the button is used in a module
Syntax Outcome
// Dialog which requires input to proceed
// Create a CheckBox which will be set as content
CheckBox checkBox = 
  new CheckBox("I accept the Terms and Conditions");
dialogBtn.setOnAction(event -> {
  // Building the dialog with the CheckBox as content
  WorkbenchDialog dialog = WorkbenchDialog.builder(
  "Check the box to continue", checkBox, ButtonType.OK)
    .blocking(true)
    .build();
  // Bind the OK button to the CheckBox
  dialog.setOnShown(event1 -> {
    dialog.getButton(ButtonType.OK).ifPresent(
      button -> button.disableProperty().bind(
        checkBox.selectedProperty().not()));
  });
  getWorkbench().showDialog(dialog);
});

Other examples can be found in the DialogTestModule of the Custom Demo

Prevent module from closing

In some cases it is necessary to prevent a module from closing. For example, the following dialog asks about saving before closing:

Image of a dialog which asks about saving before closing the module

As mentioned in Module Lifecycle, the destroy() method will be called when closing the module. The module will be closed as soon as the destroy() method returns true. If you want to prevent the module from closing, return false and then close the module by calling close(), as soon as you are ready.

The code snippet below results in the dialog displayed in the image on top:

@Override
public boolean destroy() {
  
  // Perform an asynchronous task (in our case showing a dialog)
  getWorkbench().showDialog(WorkbenchDialog.builder(
      "Save before closing?",
      "Do you want to save your progress? Otherwise it will be lost.",
      ButtonType.YES, ButtonType.NO, ButtonType.CANCEL)
      .blocking(true)
      .onResult(buttonType -> {
        // If CANCEL was not pressed
        if (!ButtonType.CANCEL.equals(buttonType)) {
          if (ButtonType.YES.equals(buttonType)) {
            // YES was pressed -> Proceed with saving
            ...
          }
          close(); // Close the module since CANCEL was not pressed 
        }
      })
      .build());
  
  return false; // return false, because we're closing manually
}

Drawer

Calling workbench.showDrawer(), enables you to show a custom drawer (like the NavigationDrawer). There are two possibilities for showing a drawer:

workbench.showDrawer(
    Region drawer, // Drawer to be shown
    Side side      // From which side the drawer should come from
);

Calling this, the width of the drawer is calculated automatically and takes the width which fits best for the drawer content defined. The other possibility comes into action when a specific width is desired:

workbench.showDrawer(
    Region drawer, // Drawer to be shown
    Side side      // From which side the drawer should come from
    int percentage // Defines how much of the screen should be covered
);

The percentage can be defined in an Integer range between 0 and 100. It represents the percentage of the window the drawer covers when showing.

Examples of drawers can be found in the DrawerTestModule of the Custom Demo

Custom Overlay

The foundation of Dialogs and Drawers are overlays. It is possible to define a custom overlay by calling workbench.showOverlay(). The defined overlay will be stacked on top of a GlassPane.

workbench.showOverlay(
    Region overlay,  // Overlay to be shown
    boolean blocking // true, if the overlay should not be closed when clicking on the GlassPane
);

The overlay can essentially be any Region (for example a custom Control). Per default, the defined content will be displayed in the top-left corner of the window. To center the content of an overlay, perform the following call on the overlay:

StackPane.setAlignment(overlay, Pos.CENTER); // is needed to center the overlay on the screen

Restyling

Basic Styling

First of all: WorkbenchFX does not interfere with the styles of the individual modules. This way each module can be styled independently and you do not have to worry about the workbench influencing the styling.

But it is possible to alter the styles of the workbench itself. WorkbenchFX comes with an out of the box styling. It is strongly inspired by Material Design.

The workbench's styling can be altered by referencing a stylesheet, like in the Custom Demo:

workbench.getStylesheets().add(CustomDemo.class.getResource("customTheme.css").toExternalForm());

In the file customTheme.css, some default colors are referenced:

* {
  -primary-color: #6200EE;
  -primary-variant-color: #3700b3;
  -secondary-color: #6300ff;
  -secondary-variant-color: #1e005f;
  -background-color: #FFFFFF;
  -surface-color: #FFFFFF;
  -error-color: #B00020;
  -on-primary-color: #FFFFFF;
  -on-secondary-color: #FFFFFF;
  -on-background-color: #000000;
  -on-surface-color: #000000;
  -on-error-color: #FFFFFF;
}

.logo {
  /* Reference to the applications logo */
  -fx-graphic: url("logo.png");
}

The colors are named according to the Material Design guidelines. Changing those colors leads to a complete restyling of the workbench. For example, a file darkTheme.css is also referenced in the demo and leads to the following result:

screenshot of the workbench's darkTheme version

Changing Colors

If you want to change the colors of the application, create a new css file customTheme.css and add it to the workbench:

workbench.getStylesheets().add(CustomDemo.class.getResource("customTheme.css").toExternalForm());

In context, the code looks like this:

public class CustomDemo extends Application {
  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    
    Workbench customWorkbench = Workbench.builder(
        new CustomModule()
    ).build();
    
    // Adding the stylesheet to the workbench to restyle it
    customWorkbench.getStylesheets().add(CustomDemo.class.getResource("customTheme.css").toExternalForm());
    
    Scene myScene = new Scene(customWorkbench);
    primaryStage.setScene(myScene);
    primaryStage.setWidth(700);
    primaryStage.setHeight(450);
    primaryStage.show();
  }
}

Changing the colors in the css file to something like this:

* {
  -primary-color: #9db668;
  -primary-variant-color: #7f975f;
  -secondary-color: #9db668;
  -secondary-variant-color: #7f975f;
  -background-color: #FFFFFF;
  -surface-color: #FFFFFF;
  -error-color: #B00020;
  -on-primary-color: #FFFFFF;
  -on-secondary-color: #FFFFFF;
  -on-background-color: #747474;
  -on-surface-color: #747474;
  -on-error-color: #FFFFFF;
}

Leads to following design:

screenshot of the custom css

Setting a Logo

In the upper section of the NavigationDrawer, there is a section for a logo. The logo is defined in the custom stylesheet (how to create one and reference it is described in the previous chapter). An example implementation of the logo can be found in the customTheme.css of the Custom Demo:

.logo {
  /* Reference to the application's logo */
  -fx-graphic: url("logo.png");
}

Changing the logo can easily be done by adding an image with the correct size in the resources folder and referring to its name in the stylesheet:

.logo {
  /* Reference to the applications logo */
  -fx-graphic: url("myCustomLogo.png"); /* Replacing logo.png with a different image. */
}

Note:

  • WorkbenchFX does not resize the image. We suggest a maximum image height of 250px

Advanced Styling

Sometimes just changing the colors is not enough. Every component in the workbench has its own .class or #id. This way, the components can be restyled if needed.

For example, every generated Tab and Tile has its own unique #id. The naming conventions for the #id are defined as:

  • Prefix: tab / tile (depending on the component)
  • Body: the name of the module
    • all special characters besides hyphens are removed
    • all spaces are replaced by hyphens (-)
    • uppercase letters are converted to lowercase

Setting the LOGGER level to debug will print each module's tab and tile id as soon as they are set:

  • Set Tab-ID of '(MODULE NAME)' to: '(TAB ID)'
  • Set Tile-ID of '(MODULE NAME)' to: '(TILE ID)'

For further information, refer to the Javadoc of WorkbenchUtils.convertToId()

#id example:

Module name:
    François' Module
    
Results in:
    tab-franois-module // Tab id
    tile-franois-module // Tile id
    
LOGGER output:
    Set Tab-ID of 'François' Module' to: 'tab-franois-module'
    Set Tile-ID of 'François' Module' to: 'tile-franois-module'

Starting with the result after chapter Getting Started:

Assuming the Tab and Tile need to be restyled, add the following code snippet to the customTheme.css file:

/* Styling the Tile */
#tile-my-first-workbench-module .tile-box {
  -fx-background-color: -primary-color !important; /* The background of the Tile */
}

#tile-my-first-workbench-module .tile-box .text, /* The icon and the text */
#tile-my-first-workbench-module .tile-box .glyph-icon {
  -fx-fill: -on-primary-color !important;
}

/* Styling the Tab */
#tab-my-first-workbench-module:selected {
  -fx-background-color: #747474 !important; /* The background of the Tab */
  -fx-background-radius: 5px 5px 0 0 !important;
}

#tab-my-first-workbench-module:selected .text, /* The icon and the text */
#tab-my-first-workbench-module:selected .glyph-icon {
  -fx-fill: #ffffff !important;
}

#tab-my-first-workbench-module:selected .shape {
  -fx-background-color: #ffffff !important; /* The close icon */
}

Leads to following styling:

screenshot of the custom css

Note:

  • The css color variables can still be used in the customTheme.css file
  • Since the styling of the workbench is more specific, the !important tag is required when styling the workbench
  • A tool like ScenicView helps to determine the style classes

Team

License

FOSSA Status

Comments
  • How to use WorkbenchFX as a Java 11 module

    How to use WorkbenchFX as a Java 11 module

    I am trying to set up a new project with WorkbenchFX and to use modules right from the start. I use Intellij with Gradle.

    1. Is it correct that the modularized version of WorkbenchFX is currently not in a public repository?
    2. To build it, is the best choice at the moment branch fixjava11 (by diff-ing with master-11, I noticed that you've removed the javafx.swing dependency from module-info.java) ?
    3. In this branch, I ran the "install" task in the Maven window of Intellij. That created, among others:

    .../.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.0.0/workbenchfx-core-11.0.0.jar

    But that seems to be a fat jar which includes dependencies javafx classes and logger classes. Is that the jar I should add to my runtime dependencies? 4. But I am confused: Should'nt the JavaFx -parts be in separate modules, installed separately and platform - specific from https://gluonhq.com/products/javafx/ ?

    opened by maehly 6
  • Strategy to init WorkbenchModule

    Strategy to init WorkbenchModule

    At first, WorkbenchFX is really great. Thank you for that. The case: In my WorkbenchModule I add a ToolbarItem to the ModuleToolbar. Based on v1.0.0 I have two possibilities: Add this code to the constructor or override 'init(Workbench workbench)'. The point is, I need to use the workbench object. Only the 'init' method provides it. But using this method calls my code (to fill the toolbar) multiple times while using the application (the reason is clear for me). And this will add my toolbaritems again and again. Based on this behaviour I have to check if the method was called the first time, only then I execute the code. Ok, this is simple. But it would be more intuitive, to have a support for this. Proposal: class 'WorkbenchModule' provides a further empty method (to override), which is called only once after init. Means, even if init is called again, based on the known state, the new method is not called again. What do you think?

    opened by ryppo 5
  • Initial visibilty of NavigationDrawer

    Initial visibilty of NavigationDrawer

    I noticed that workbench.getNavigationDrawer().isVisible() returns true from start when it's not visible. The following code only works after I toggle the NavigationDrawer by mouse

    if (mWorkbench.getNavigationDrawer().isVisible()) {
        mWorkbench.hideNavigationDrawer();
    } else {
        mWorkbench.showNavigationDrawer();
    }
    

    ...unless I first do

    mWorkbench.getNavigationDrawer().setVisible(false);
    

    Should this be done in the framework?

    opened by trixon 4
  • Implement a simple single module layout

    Implement a simple single module layout

    PR Checklist

    • [x] There is an issue for the bug/feature this PR is for. To avoid wasting your time, it's best to open an issue first and wait for approval before working on it.
    • [x] The code follows the Google Java Style Guide.
    • [x] JavaDoc is added / changed for public methods.
    • [x] An example of the new feature is added to the demos.
    • [x] Documentation of the feature is included in the README.
    • [x] Tests for the changes are included.

    What is the current behavior?

    The tab bar is displayed in any case, even when only a single module is used in the workbench, see #23 .

    What is the new behavior?

    If only a single module is defined for a workbench, the tab bar and the add module button are not visible and the module is automatically opened at startup.

    Closes #23

    enhancement 
    opened by s-schoen 4
  • [Security] Bump log4j-core from 2.12.1 to 2.13.3

    [Security] Bump log4j-core from 2.12.1 to 2.13.3

    Bumps log4j-core from 2.12.1 to 2.13.3.

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)
    dependencies security 
    opened by dependabot-preview[bot] 3
  • Please provide non shaded artifact

    Please provide non shaded artifact

    The current workbenchFX maven artifact is a shaded jar with all dependencies inside. This breaks my current projects' maven structure configuration (especially logging system).

    I would like to exclude some incompatible dependencies or WorkbenchFX but with a shaded jar, it's impossible.

    I think this is a bad practice, you shouldn't include third-party libs in your artifact as it's maybe violated license terms on some of them.

    Please provide an artifact without shaded dependencies.

    Thanks.

    opened by garzy 3
  • Open module without load it

    Open module without load it

    Let me say workbench its great, thanks for it!!.. Well, i have a list and need a "submodule" to edit the objects of the list In first, i think i can create a module and just open it (without load it before), but i did it and get the error "Module has not been loaded yet" It supose they dont clic on a module, only by the list and then clic on edit button. Is there any way i can do that? or am i doing anything wrong? Thanks

    question 
    opened by hortegag91 3
  • Bump view from 11.5.0 to 11.6.4

    Bump view from 11.5.0 to 11.6.4

    Bumps view from 11.5.0 to 11.6.4.

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Note: This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

    You can always request more updates by clicking Bump now in your Dependabot dashboard.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    Finally, you can contact us by mentioning @dependabot.

    dependencies 
    opened by dependabot-preview[bot] 3
  • Bump javafx-web from 11.0.1 to 12.0.2

    Bump javafx-web from 11.0.1 to 12.0.2

    Bumps javafx-web from 11.0.1 to 12.0.2.

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Note: This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

    You can always request more updates by clicking Bump now in your Dependabot dashboard.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    Finally, you can contact us by mentioning @dependabot.

    dependencies 
    opened by dependabot-preview[bot] 3
  • Bump preferencesfx-core from 11.3.0 to 11.5.0

    Bump preferencesfx-core from 11.3.0 to 11.5.0

    Bumps preferencesfx-core from 11.3.0 to 11.5.0.

    Release notes

    Sourced from preferencesfx-core's releases.

    Release 11.5.0

    See CHANGELOG.md

    Release 11.4.3

    See CHANGELOG.md

    Release 11.4.1

    See CHANGELOG.md

    Release 11.4.0

    See CHANGELOG.md

    Release 11.3.2

    See CHANGELOG.md

    Release 11.3.1: CI/CD Release

    See CHANGELOG.md

    Changelog

    Sourced from preferencesfx-core's changelog.

    Change Log

    8.5.0 (2019-08-25)

    Full Changelog

    Merged pull requests:

    11.4.3 (2019-08-19)

    Full Changelog

    8.4.3 (2019-08-19)

    Full Changelog

    8.4.2 (2019-08-19)

    Full Changelog

    8.4.1 (2019-08-19)

    Full Changelog

    11.4.1 (2019-08-19)

    Full Changelog

    11.4.0 (2019-08-19)

    Full Changelog

    Closed issues:

    • Set default view/Show first subcategory #83

    8.4.0 (2019-08-19)

    Full Changelog

    Merged pull requests:

    • Automatically select first subcategory if a category is empty #86 (ArvidNy)
    • remove dependency to efxclipse #84 (sclassen)

    11.3.2 (2019-07-30)

    Full Changelog

    11.3.1 (2019-07-30)

    Full Changelog

    8.3.2 (2019-07-30)

    ... (truncated)
    Commits
    • 1ddeea0 Merge branch 'master' into master-11
    • f46dd57 Merge pull request #89 from sclassen/simplifyAsciiClass
    • a142d97 Merge pull request #90 from sclassen/fixJavaDoc
    • 4f37214 Merge branch 'master' into fixJavaDoc
    • 4d3d289 Merge pull request #93 from sclassen/splitStorageHandlerImpl
    • 71d1dcc Revert "add checkstyle for codeclimate"
    • b450b9c add checkstyle for codeclimate
    • 7d74375 update links
    • fa67629 optimize imports
    • 72da124 rename local variables from json -> serialized
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Note: This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

    You can always request more updates by clicking Bump now in your Dependabot dashboard.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    Finally, you can contact us by mentioning @dependabot.

    dependencies 
    opened by dependabot-preview[bot] 3
  • Bump controlsfx from 8.40.14 to 9.0.0

    Bump controlsfx from 8.40.14 to 9.0.0

    Bumps controlsfx from 8.40.14 to 9.0.0.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Note: This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

    You can always request more updates by clicking Bump now in your Dependabot dashboard.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    Finally, you can contact us by mentioning @dependabot.

    dependencies 
    opened by dependabot-preview[bot] 3
  • How to pause execution until a dialog is closed?

    How to pause execution until a dialog is closed?

    I'm trying to add an exit confirmation but it just falls through, the dialog is never shown.

            mStage.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, windowEvent -> {
                if (true) {//TODO Add condition
                    var dialog = WorkbenchDialog.builder("title", "message", WorkbenchDialog.Type.CONFIRMATION).onResult(buttonType -> {
                        if (buttonType.getButtonData() != ButtonBar.ButtonData.YES) {
                            windowEvent.consume();
                        }
                    }).blocking(true).build();
                    mWorkbench.showDialog(dialog);
                }
            });
    

    For this simple test the result is 132, what I want it to be 123.

                System.out.println("1");
                mWorkbench.showConfirmationDialog(
                        "Continue without saving?",
                        "Are you sure you want to continue without saving"
                        + "your document?",
                        buttonType -> { // Proceed and validate the result
                            System.out.println("2");
                        });
                System.out.println("3");
    
    

    Just speculating here but are there any (overlay transition) listeners or something I could connect a CountDownLatch to?

    opened by trixon 0
  • Can I set the drawer always show?

    Can I set the drawer always show?

    Hi, first of all, thank you very much for open-source this project, I like it very much, it is very easy to use and supports a high degree of customization.

    It may be my first day to use this project. Now I want the left menu bar to be displayed all the time, and do not block the right window when it is displayed. After I read the documentation and tried it by myself, I still couldn't find the idea. Excuse me, can you give me anything help?Thank you very much.

    opened by 974988176 0
  • Styles Errors

    Styles Errors

    I have been getting these console errors or logs in red about some style warning from this library. for example, as shown below, what could be the cause of this:

    Jul 21, 2022 10:17:26 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Could not resolve '-on-surface-color' while resolving lookups for '-fx-fill' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box *.text-lbl *.text' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:26 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Caught 'java.lang.ClassCastException: class java.lang.String cannot be cast to class javafx.scene.paint.Paint (java.lang.String is in module java.base of loader 'bootstrap'; javafx.scene.paint.Paint is in module [email protected] of loader 'platform')' while converting value for '-fx-background-color' from rule '*#content-view *#add-module-view>*.pagination-control>*.control-box>*.bullet-button:selected' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:27 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Caught java.lang.IllegalArgumentException: Parsed value is not an Effect' while calculating value for '-fx-effect' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box:hover' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:27 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Caught 'java.lang.ClassCastException: class java.lang.String cannot be cast to class javafx.scene.paint.Paint (java.lang.String is in module java.base of loader 'bootstrap'; javafx.scene.paint.Paint is in module [email protected] of loader 'platform')' while converting value for '-fx-background-color' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:27 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Could not resolve '-on-surface-color' while resolving lookups for '-fx-icon-color' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box *.ikonli-font-icon' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:27 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Could not resolve '-on-surface-color' while resolving lookups for '-fx-fill' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box *.text-lbl *.text' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:28 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Caught java.lang.IllegalArgumentException: Parsed value is not an Effect' while calculating value for '-fx-effect' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box:pressed' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:28 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Caught 'java.lang.ClassCastException: class java.lang.String cannot be cast to class javafx.scene.paint.Paint (java.lang.String is in module java.base of loader 'bootstrap'; javafx.scene.paint.Paint is in module [email protected] of loader 'platform')' while converting value for '-fx-background-color' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    Jul 21, 2022 10:17:28 PM javafx.scene.CssStyleHelper calculateValue
    WARNING: Could not resolve '-on-surface-color' while resolving lookups for '-fx-icon-color' from rule '*#content-view *#add-module-view *.page-control *.tile-pane *.tile-box *.ikonli-font-icon' in stylesheet jar:file:///home/variable-k/.m2/repository/com/dlsc/workbenchfx/workbenchfx-core/11.3.1/workbenchfx-core-11.3.1.jar!/com/dlsc/workbenchfx/css/main.css
    
    opened by kinsleykajiva 0
  • Missing -background-variant-color

    Missing -background-variant-color

    I tried to set -background-variant-color in my css in order to change the background color of pressed module toolbar items but it had now effect.

    For a light theme one can see the hard coded default mask in _content-view.scss

            &:pressed {
              -fx-background-color: rgba(0, 0, 0, .075);
            }
    

    but it's invisible in a dark theme. I added the following to my css and it works as expected

    .toolbar-button:pressed{
        -fx-background-color: red;
    }
    

    I'm still a beginner of css but doesn't it make sense to expose -background-variant-color, similar to the -primary-variant-color?

    opened by trixon 0
  • Styling localized modules

    Styling localized modules

    I've just begun styling my workbench and it looks to me like the style mapping is done by the module display name, if that name is localized, it requires one style for each language.

    Is that correct? If so, could that be improved somehow?

    opened by trixon 1
Releases(v11.3.1)
Owner
DLSC Software & Consulting GmbH
DLSC Software & Consulting GmbH
DataFX - is a JavaFX frameworks that provides additional features to create MVC based applications in JavaFX by providing routing and a context for CDI.

What you’ve stumbled upon here is a project that intends to make retrieving, massaging, populating, viewing, and editing data in JavaFX UI controls ea

Guigarage 110 Dec 29, 2022
Lightweight JavaFX Framework for Kotlin

TornadoFX JavaFX Framework for Kotlin Important: TornadoFX is not yet compatible with Java 9/10 Oracle is intending to decouple JavaFX from the JDK. W

Edvin Syse 3.6k Dec 29, 2022
To quickly integrate your applications into the EdgeGallery platform, we provide the toolchain project to help developers quickly modify code and migrate applications to the platform.

Toolchain 工具链 工具链是MEC Developer开发者平台中的一个重要特性,当x86平台的App想要上车ARM平台时,底层的代码不可避免的需要进行修改或重写。 App提供者可以通过MEC Developer开发者平台中集成的工具链进行源代码分析,定位需要修改的源代码并根据指导意见进行修

EdgeGallery 19 Jan 7, 2022
A lightweight pinch-to-zoom pane for JavaFX

GestureFX A lightweight gesture enabled pane for JavaFX Features Accepts any Node or implementations of net.kurobako.gesturefx.GesturePane.Transformab

Tom Lin 57 Dec 18, 2022
Auto updating launcher for JavaFX Applications

FXLauncher Auto updating launcher for JavaFX Applications. Combined with JavaFX native packaging, you get a native installer with automatic app update

Edvin Syse 694 Dec 27, 2022
A 3D chart library for Java applications (JavaFX, Swing or server-side).

Orson Charts (C)opyright 2013-2020, by Object Refinery Limited. All rights reserved. Version 2.0, 15 March 2020. Overview Orson Charts is a 3D chart l

David Gilbert 96 Sep 27, 2022
A Javafx Library for building MVC Applications.

A JavaFx Library For Making MVC Type Desktop Applications Installation requires Java jdk > 7 for windows requres openjdk-7 or 8 and openjfx for linux

Obi Uchenna David 38 Apr 30, 2022
A 2D chart library for Java applications (JavaFX, Swing or server-side).

JFreeChart Version 2.0.0, not yet released. Overview JFreeChart is a comprehensive free chart library for the Java(tm) platform that can be used on th

David Gilbert 946 Jan 5, 2023
Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE 8 and provides the functionalities to use and handle easily Tiles in your JavaFX application.

Lib-Tile Intention Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE and provides the functionalities to use and handle easily Tile

Peter Rogge 13 Apr 13, 2022
Docking framework for JavaFX platform

Docking framework for JavaFX platform AnchorFX is a gratis and open source library for JavaFX to create graphical interfaces with docking features Anc

Alessio Vinerbi 197 Oct 15, 2022
A Java framework for creating sophisticated calendar views (JavaFX 8, 9, 10, and 11)

CalendarFX A Java framework for creating sophisticated calendar views based on JavaFX. A detailed developer manual can be found online: CalendarFX 8 D

DLSC Software & Consulting GmbH 660 Jan 6, 2023
A JavaFX UI framework to create fully customized undecorated windows

CustomStage A JavaFX undecorated stage which can fully be customized Donations If this project is helpful to you and love my work and feel like showin

Oshan Mendis 186 Jan 6, 2023
A framework for easily creating forms for a JavaFX UI.

FormsFX Forms for business application made easy. Creating forms in Java has never been this easy! Maven To use this framework as part of your Maven b

DLSC Software & Consulting GmbH 534 Dec 30, 2022
Desktop/Mobile JavaFX application framework

Basilisk is desktop/mobile application development platform for the JVM. Inspired by Griffon, Basilisk leverages JavaFX and JavafXPorts to bring the s

Basilisk 55 Feb 10, 2022
an Application Framework for implementing the MVVM Pattern with JavaFX

mvvmFX is an application framework which provides you necessary components to implement the MVVM pattern with JavaFX. MVVM is the enhanced version of

Alexander Casall 438 Dec 28, 2022
😉PrettyZoo is a GUI for Zookeeper created by JavaFX and Apache Curator Framework.

?? Pretty nice Zookeeper GUI, Support Win / Mac / Linux Platform

vran 2.4k Jan 5, 2023
JavaFX micro-framework that follows MVVM Pattern with Google Guice dependency Injection

ReactiveDeskFX (JavaFX and Google Guice MVVM Pattern micro-framework) JavaFX micro-framework to develop very fast JavaFX components with minimal code

TangoraBox 3 Jan 9, 2022
an open souece, lightWeight and beautiful GUI for VPN Usage

free, open source, lightweight and beutiful GUI for vpn usage , this Project is part of my #100DaysOfCode challenge in twitter : @My_Terminal Dependen

Mohammad Esmaeili 21 Nov 9, 2022
Lightweight installer written in java, made for minecraft mods, The installer uses JPanel and uses a URL to install to the specific area (Discord URL's work the best i've seen)

InstallerForJava Lightweight installer written in java, made for minecraft mods, The installer uses JPanel and uses a URL to install to the specific a

null 18 Dec 9, 2022