How to create a “add tab“button in JAVAFX? - javafx

I want to create a button ,which will create a new tab to tabPane when clicking,and on the right of all tab alltime. I'll appreciate if there has any example how to do it.

Your code should look similar to the code below.
This example uses a button above the TabPane.
public class TabPaneSample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
TabPane tabPane = new TabPane();
VBox layout = new VBox(10); // VBox with spacing of 10. Button sits above TabPane
layout.getChildren().addAll(newTabButton(tabPane), tabPane); // Adding button and TabPane to VBox
stage.setScene(new Scene(layout));
stage.show();
}
// Button that adds a new tab and selects it
private Button newTabButton(TabPane tabPane) {
Button addTab = new Button("Create Tab");
addTab.setOnAction(event -> {
tabPane.getTabs().add(new Tab("New Tab")); // Adding new tab at the end, so behind all the other tabs
tabPane.getSelectionModel().selectLast(); // Selecting the last tab, which is the newly created one
});
return addTab;
}
}
If you want it to be like in a browser, this code should do it.
This uses the an empty tab at the end, which acts like a button. You can add an icon like + instead of the text in the tab label.
public class TabPaneSample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
TabPane tabPane = new TabPane();
tabPane.getTabs().add(newTabButton(tabPane));
stage.setScene(new Scene(tabPane));
stage.show();
}
// Tab that acts as a button and adds a new tab and selects it
private Tab newTabButton(TabPane tabPane) {
Tab addTab = new Tab("Create Tab"); // You can replace the text with an icon
addTab.setClosable(false);
tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldTab, newTab) -> {
if(newTab == addTab) {
tabPane.getTabs().add(tabPane.getTabs().size() - 1, new Tab("New Tab")); // Adding new tab before the "button" tab
tabPane.getSelectionModel().select(tabPane.getTabs().size() - 2); // Selecting the tab before the button, which is the newly created one
}
});
return addTab;
}
}

Related

JavaFX Stage.close() not calling my onCloseRequest() handler

Please refer to the JavaFX SSCCE below. The print statement appears when closing the primary stage from the window's default titlebar "X" button. The print statement does NOT appear when clicking the "Close" button. Why isn't my onCloseHandler being called when I call close() on the stage? Is my expectation somehow unreasonable or is this (yet another) bug in JavaFX? Thanks!
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button closeButton = new Button("Close");
closeButton.setOnAction(e -> {
primaryStage.close();
});
primaryStage.setOnCloseRequest(e -> {
System.out.println("onCloseRequest handler called!");
});
StackPane rootPane = new StackPane();
rootPane.getChildren().add(closeButton);
primaryStage.setScene(new Scene(rootPane, 300, 250));
primaryStage.show();
}
}
As described by the Javadoc, this is only fired on external requests:
Called when there is an external request to close this Window.
Maybe setOnHidden would work for you, it is called in both cases.
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button closeButton = new Button("Close");
closeButton.setOnAction(e -> {
primaryStage.close();
});
primaryStage.setOnHidden(e -> {
System.out.println("stage hidden");
});
StackPane rootPane = new StackPane();
rootPane.getChildren().add(closeButton);
primaryStage.setScene(new Scene(rootPane, 300, 250));
primaryStage.show();
}
}

How to add a context menu to an empty tableview's header row?

I have a TableView. If it has columns, I can add context menus to the columns, and the menu will appear when I right click on the column header.
How do I add a context menu to the blank bar that appears for an empty table? Screenshot:
This can be done by accessing the internal structure of the TableView directly, I'm unaware of any official API to do this.
The official TableView CSS names a class of column-header-background which we can then access via the Node#lookup() method.
An example
public class ContextMenuOnTableHeader extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
TableView<String> table = new TableView<>();
Scene scene = new Scene(table);
primaryStage.setScene(scene);
primaryStage.setWidth(200);
primaryStage.setHeight(200);
primaryStage.show();
Node header = table.lookup(".column-header-background");
header.setOnContextMenuRequested(event -> {
ContextMenu menu = new ContextMenu();
menu.getItems().add(new MenuItem("Mr Horse"));
menu.show(header, event.getScreenX(), event.getScreenY());
});
}
}

javafx putting textarea value into a hashmap

I would like to make a small java fx app that has just textarea and one button on a stage and that when you type some strings in textarea and press submit it shows on the stage small table with results how many each Word had occurrences.
so my questions is: does map is the best solution for finding the occurrences even though I do not know what will be the key for finding occurrences and how to connect string from text area, to map.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Word counting");
TextArea txt=new TextArea();
txt.setMaxSize(450, 200);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.hide();
ShowResults.drugiProzor();
}
});
BorderPane root = new BorderPane();
root.setTop(txt);
HBox hbox=new HBox();
hbox.setPadding(new Insets(20,20,100,180));
hbox.getChildren().add(btn);
root.setBottom(hbox);
Scene scene = new Scene(root, 450, 300);
primaryStage.setTitle("Word counting!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and the second class is again gui class with table view
public class ShowResults {
static Stage secondaryStage;
public static void drugiProzor() {
secondaryStage=new Stage();
TableView table=new TableView();
TableColumn column1=new TableColumn("Word");
column1.setMinWidth(200);
TableColumn column2=new TableColumn("Number of occurencies");
column2.setMinWidth(200);
table.getColumns().addAll(column1,column2);
StackPane pane=new StackPane();
pane.getChildren().add(table);
Scene scene = new Scene(pane, 450, 300);
secondaryStage.setScene(scene);
secondaryStage.setTitle("Counting words");
secondaryStage.show();
}
}
and third class shoyld be the class where the magic happends something like this:
public class Logic {
public void logic()
}
}
You can just do something like
public Map<String, Long> countWordOccurences(String text) {
return Pattern.compile("\\s+") // regular expression matching 1 or more whitespace
.splitAsStream(text) // split at regular expression and stream words between
// group by the words themselves and count each group:
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}
Check the Javadocs to see what each step is doing: Pattern, Collectors.groupingBy(), Function, etc.
If you want to count in a case-insensitive way, you can replace Function.identity() with String::toLowerCase
.collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()));
and if you want to ignore punctuation, you can add
map(s -> s.replaceAll("[^a-zA-Z]",""))
to the pipeline.

How do I Dynamically Modifying the Display of Contols inside a GridPane (or other container) in Java FX?

Im looking at this problem from in a new way:
I have a simple FXML app that has a mainapp, a controller and a view. The view displays a gridpane consisting of three rows where each row contains a single label element. So the gridpane looks like this to the user:
row 1
row 2
row 3
There is also a button called Delete Selected Row that is clicked after the user selects a row. When the button is clicked, the element is temporarily removed, or hidden, from the gridpane. So if row 2 is selected and the button is clicked the user will see
row 1
row 3
The above view is created with Scene Builder that creates an XML file called AppOverview.fxml.
There is a MainApp that paints the scene that has the following code:
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
//Constructor
public MainApp() {}
#Override
public void start(Stage primaryStage)
{
this.primaryStage = primaryStage;
primaryStage.initStyle(StageStyle.UNDECORATED);
initRootLayout();
showAppOverview();
}
// Initializes the root layout.
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
System.out.println("Error in MainApp:initRootLayout()");
System.exit(0);
}
}
// Shows the app overview inside the root layout.
public void showAppOverview() {
try {
// Load overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/AppOverview.fxml"));
AnchorPane appOverview = (AnchorPane) loader.load();
// Set overview into the center of root layout.
rootLayout.setCenter(appOverview);
// Give the controller access to the main app.
AppController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
System.exit(0);
}
}
// Returns the main stage.
public Stage getPrimaryStage(){
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
The controller in my app.view package contains listeners on the handleDeleteBtn button (and a couple other buttons) and handleSelectedGridPaneRow() to manage row selection in the gridpane:
public class AppController {
//Reference to MainApp
private MainApp mainApp;
#FXML
private void handleRestoreBtn(){
System.out.println("You are restoring the hidden row");
}
#FXML
private void handleDeleteBtn(){
System.out.println("You are hiding the selected row");
}
#FXML
private void handleExitBtn(){
System.exit(0);
}
#FXML
private void handleSelectedGridPaneRow(){
System.out.println("You have selected a row to hide");
}
public AppController(){}
// Initialize the <code>AppController</code> instance.
#FXML
private void initialize(){}
public void setMainApp(MainApp mainApp)
{
this.mainApp = mainApp;
}
}
My specific questions are:
1) Is this kind of spec achievable, ie, being able to dynamically manage a gridpane as described?
2) If yes, where and how would I access the gridpane? Presumably somewhere in the method 'handleDeleteBtn()' in AppController. What do I need to do to reference the gridpane in the Controller and then execute statements such as gridPane.getChildren().remove(0,2);?
I think the fact I got know answers to my post indicated that my approach was all wrong. Anyway the solution I have found works very well. Instead of trying to remove and restore rows in the gridpane, I just left the gridpane alone with the original 1 column and 3 row and instead changed the content of each cell according to the button being pressed. So I changed the names of the button handlers to something more reflective to what I was attempting, and added an extra to display another combination of rows:
#FXML
private void showRow1and2Btn(){
...
}
#FXML
private void showRow2and3Btn(){
...
}
#FXML
private void showAll(){
...
}
Then I declared three labels to show the contents of the rows I want:
#FXML
private Label label_0;
#FXML
private Label label_1;
#FXML
private Label label_2;
These labels are bound to three labels that I built in Scene Builder and which occupy the three rows in the gridpane.
I added this method to get the three gridpane rows populated according to my spec:
private void setgridPaneRows(Label label, String str)
{
label.setText(str);
}
Then its just a case of getting something into the button handlers so the desired effect is achieved, for example:
private void showRow1and2Btn()
{
setgridPaneRows(label_0,"Label 0");
setgridPaneRows(label_1,"Label 1");
setgridPaneRows(label_2,null);
}
#FXML
private void showRow2and3Btn(){
setgridPaneRows(label_0,"Label 1");
setgridPaneRows(label_1,"Label 2");
setgridPaneRows(label_2,null);
}
#FXML
private void ShowAllBtn(){
setgridPaneRows(label_0,"Label 0");
setgridPaneRows(label_1,"Label 1");
setgridPaneRows(label_2,"Label 2");
}
In another application I have successfully extended this approach to adding a second column to the gridpane and populating these elements with different controls, so for example, I can make gridpane 1,0 contain a combo box for one input requirement and then contain a textfield for another kind of input requirement.

how to perform any task on clicking main menubutton

I have a menu heading, on clicking on which sub menu items are displayed. The set on action function is working for the sub menu items but not for the main menu. I wanted to perform some task on just clicking on the main menu along with the drop down list of sub menu items. Please Help.
Here's an example about how to catch events for the menu, the submenu and the menu items:
public class MenuActionDemo extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Menus");
Group root = new Group();
Scene scene = new Scene(root, 300, 250, Color.WHITE);
MenuBar menuBar = new MenuBar();
// main menu item
Menu menu = new Menu("Item");
menu.showingProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if( newValue) {
System.out.println( "Main menu item showing");
} else {
System.out.println( "Main menu item closing");
}
}
});
// sub menu
Menu subMenu = new Menu("Submenu");
subMenu.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if( event.getTarget() == subMenu) {
System.out.println("Submenu clicked");
}
}
});
// sub menu item
MenuItem menuItem = new MenuItem("Submenu Item 1");
menuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Submenu Item 1 clicked");
}
});
subMenu.getItems().add(menuItem);
// add items to main menu
menu.getItems().add(subMenu);
menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
menuBar.getMenus().add(menu);
root.getChildren().add(menuBar);
primaryStage.setScene(scene);
primaryStage.show();
}
}

Resources