Inner Classes variable Access - dialog

In this case I'm a little confused as to why I can't use myFrame as the first parameter in the showMessageDialog function. Why doesn't this work?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BabyCalculator extends JFrame{
public BabyCalculator(){
//You set this up so that you can refer to the frame using the inner class below.
setDefaultCloseOperation(EXIT_ON_CLOSE);
setName("Baby Calculator");
setLayout(new GridLayout(3,0));
//add
JLabel addLabel = new JLabel("Amount to add:");
JTextField addField = new JTextField(10);
JButton addButton = new JButton("add");
addButton.addActionListener(new AddListener());
//multiply
JLabel multiplyLabel = new JLabel("Amount to multiply:");
JTextField multiplyField = new JTextField(10);
JButton multiplyButton = new JButton("multiply");
//total
JLabel totalLabel = new JLabel("Total");
JTextField totalField = new JTextField(10);
totalField.setEditable(false);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new StopListener());
//Create Panels
JPanel topRow = new JPanel(new BorderLayout());
JPanel middleRow = new JPanel (new BorderLayout());
JPanel bottomRow = new JPanel (new FlowLayout());
//Add the top Row
topRow.add(addLabel,BorderLayout.WEST);
topRow.add(addField, BorderLayout.CENTER);
topRow.add(addButton, BorderLayout.EAST);
add(topRow);
middleRow.add(multiplyLabel,BorderLayout.WEST);
middleRow.add(multiplyField, BorderLayout.CENTER);
middleRow.add(multiplyButton, BorderLayout.EAST);
add(middleRow);
bottomRow.add(totalLabel);
bottomRow.add(totalField);
bottomRow.add(stopButton);
add(bottomRow);
pack();
setVisible(true);
}
public static void main (String[] args){
JFrame myFrame = new BabyCalculator();
}
public class AddListener implements ActionListener{
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(myFrame, "You Clicked the add button");
}
}
//end class AddListener
public class StopListener implements ActionListener{//this is an inner class
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(myFrame, "You Clicked the stop button");
}//end class StopListener
}
}
I know that this is an inner class, and I'm not exactly sure about the access privileges, but it seems like there should be some way to access the "myFrame" variable in the main function.

Add a declaration statement at the top within the BabyCalculator class as:
JFrame myFrame;
Or you could make it a public variable with:
public JFrame myFrame = ...

Related

Why does adding JavaFX TableViews to a VBox make other nodes disappear?

EDIT: Forgot the code...
I have an app that let's the user select CSV files for viewing. I'm using JavaFX TableViews to display the data.
For one page, the user can type into a special text box. It's a custom class I made called AutoCompleteTextArea, which extends RichTextFX's StyleClassedTextArea. On other pages, this text box should be hidden. When I have just one TableView, things work fine.
vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable);
But I need other pages with different TableViews. If I add another TableView to the VBox, my AutoCompleteTextArea goes away!
vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable, tempTable);
The TableViews do not appear to be overlapping... Any idea why the AutoCompleteTextArea is disappearing? The other weird thing is that if I substitute a regular TextField for the AutoCompleteTextArea, things work fine!
Here's my code. You will need RichTextFX on your build path in order to run it. Use the View Menu to see the problem. The first menu item shows the AutoCompleteTextArea (in the working case). The second menu item shows a different TableView, but this is the broken case - the AutoCompleteTextArea is gone from the first page.
Line 132 is the line in question.
I hope someone is up for the challenge!
More background:
I originally wanted to have just one TableView, and update it's contents based on the user's selection in the View Menu. But I couldn't find a good way to do that, and now here I am again... (see this post: How do I clone a JavaFX TableView?)
package FLOOR;
// --- Imports
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.fxmisc.richtext.StyleClassedTextArea;
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
// --- Main Class
public class Example extends Application {
// --- All Pages
final Page[] pages = new Page[] {
new Page("Welcome!",
"Welcome Page"),
new Page("Page 1", "Shows Table_1"),
new Page("Page 2", "Shows Table_2"),
};
// --- All Tables
TableView<ObservableList<StringProperty>> reqTable = new TableView<>();
TableView<ObservableList<StringProperty>> tempTable = new TableView<>();
//TextField reqBox = new TextField();
AutoCompleteTextArea reqBox = new AutoCompleteTextArea();
// --- Current Page
final Label title = new Label();
final Label subtitle = new Label();
// --- Main
public static void main(String[] args) { launch(args); }
// --- Start
#Override
public void start(Stage stage) {
// --- Menus
// --- File Menu
// --- Import Submenu
Menu menuFile = new Menu("File");
Menu importMenu = new Menu("Import");
MenuItem reqOption = new MenuItem("Requirements");
MenuItem tempOption = new MenuItem("Templates");
importMenu.getItems().addAll(reqOption, tempOption);
//Import Requirements
reqOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
//TODO
}
});
//Import Templates
tempOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
//TODO
}
});
//Export
MenuItem export = new MenuItem("Export");
export.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
//TODO
}
});
//Exit
MenuItem exit = new MenuItem("Exit");
exit.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
System.exit(0);
}
});
menuFile.getItems().addAll(importMenu, export, new SeparatorMenuItem(), exit);
// --- View Menu
Menu menuView = new Menu("View");
//Page1
MenuItem viewRequirements = new MenuItem("Requirements");
viewRequirements.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
getPage1();
}
});
//Page2
MenuItem viewTemplates = new MenuItem("Templates");
viewTemplates.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
getPage2();
}
});
menuView.getItems().addAll(viewRequirements, viewTemplates);
// --- Menu Bar
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(menuFile, menuView);
// --- VBox
final VBox vbox = new VBox();
vbox.setAlignment(Pos.TOP_CENTER);
vbox.setSpacing(10);
reqTable.setMinHeight(300);
tempTable.setMinHeight(300);
reqTable.translateYProperty().set(30);
tempTable.translateYProperty().set(-275);
reqTable.setVisible(false);
tempTable.setVisible(false);
reqBox.setVisible(false);
// --- Welcome Page
title.setFont(new Font("Arial", 24));
title.translateYProperty().set(10);
title.setText(pages[0].title);
subtitle.setText(pages[0].subtitle);
subtitle.setMinHeight(30);
subtitle.setTextAlignment(TextAlignment.CENTER);
// --- Show FLOOR
vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable);
//vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable, tempTable);
Scene scene = new Scene(vbox, 900, 500);
stage.setScene(scene);
stage.setTitle("FLOOR");
stage.show();
}
// --- Methods
// Page Getters
private void getPage1() {
title.setFont(new Font("Arial", 24));
title.translateYProperty().set(10);
title.setText(pages[1].title);
subtitle.setText(pages[1].subtitle);
subtitle.setMinHeight(20);
reqBox.setVisible(true);
reqTable.setVisible(true);
tempTable.setVisible(false);
}
private void getPage2() {
title.setFont(new Font("Arial", 24));
title.translateYProperty().set(10);
title.setText(pages[2].title);
subtitle.setText(pages[2].subtitle);
subtitle.setMinHeight(20);
reqBox.setVisible(false);
reqTable.setVisible(false);
tempTable.setVisible(true);
}
// --- Classes
// Page
private class Page {
public String title;
public String subtitle;
public Page(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle;
}
}
// AutoCompleteTextArea
public class AutoCompleteTextArea extends StyleClassedTextArea {
public final SortedSet<String> entries;
public ContextMenu entriesPopup;
public AutoCompleteTextArea() {
super();
entries = new TreeSet<>();
entriesPopup = new ContextMenu();
}
public SortedSet<String> getEntries() { return entries; }
public void populatePopup(List<String> searchResult) {
List<CustomMenuItem> menuItems = new LinkedList<>();
int maxEntries = 20;
int count = Math.min(searchResult.size(), maxEntries);
for (int i = 0; i < count; i++) {
final String result = searchResult.get(i);
Label entryLabel = new Label(result);
CustomMenuItem item = new CustomMenuItem(entryLabel, true);
menuItems.add(item);
}
entriesPopup.getItems().clear();
entriesPopup.getItems().addAll(menuItems);
}
}
}

Layout from own component isn't correctly displayed in TabPane

I have a own component (extended TextField). When I display the component in an AnchorPane the layout from the component is correctly displayed. But when I display the component in a TabPane then the first time when the component is shown the layout isn't correct rendered.
Screenshot:
Own component in an AnchorPane
Screenshot:
Own component in a TabPane
Here a MCVE:
import static javafx.scene.layout.Region.USE_PREF_SIZE;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author Naoghuman
*/
public class ExtendedComponentsMCVE extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
ExtendedTextField extendedTextField = new ExtendedTextField();
// OnlyAnchorPane oap = new OnlyAnchorPane(extendedTextField);
// Scene scene = new Scene(oap, 800, 600);
TabAnchorPane tap = new TabAnchorPane(extendedTextField);
Scene scene = new Scene(tap, 800, 600);
primaryStage.setTitle("Demo Extended Components");
primaryStage.setScene(scene);
primaryStage.show();
}
// ExtendedTextField #######################################################
class ExtendedTextField extends HBox {
private BooleanProperty configureCheckBoxProperty;
private BooleanProperty configureLeftLabelProperty;
private BooleanProperty configureTopLabelProperty;
private CheckBox cbReadOnly;
private Label lLeft;
private Label lTop;
private TextField tfText;
private VBox vBox;
private String lastUserInput = ""; // NOI18N
ExtendedTextField() {
super();
this.init();
}
private void init() {
// vbox
super.setAlignment(Pos.BOTTOM_LEFT);
super.setStyle("-fx-background-color: lightgreen;");
// left label
configureLeftLabelProperty = new SimpleBooleanProperty(Boolean.TRUE);
lLeft = new Label("<left>"); // NOI18N
lLeft.setMaxHeight(USE_PREF_SIZE);
lLeft.setMinHeight(USE_PREF_SIZE);
lLeft.visibleProperty().bind(configureLeftLabelProperty);
lLeft.managedProperty().bind(configureLeftLabelProperty);
super.getChildren().add(lLeft);
// checkbox
configureCheckBoxProperty = new SimpleBooleanProperty(Boolean.TRUE);
cbReadOnly = new CheckBox();
cbReadOnly.setMaxHeight(USE_PREF_SIZE);
cbReadOnly.setMinHeight(USE_PREF_SIZE);
cbReadOnly.visibleProperty().bind(configureCheckBoxProperty);
cbReadOnly.managedProperty().bind(configureCheckBoxProperty);
super.getChildren().add(cbReadOnly);
// vbox
vBox = new VBox();
HBox.setHgrow(vBox, Priority.ALWAYS);
// top label
configureTopLabelProperty = new SimpleBooleanProperty(Boolean.TRUE);
lTop = new Label("<top>"); // NOI18N
lTop.visibleProperty().bind(configureTopLabelProperty);
lTop.managedProperty().bind(configureTopLabelProperty);
vBox.getChildren().add(lTop);
// textfield
tfText = new TextField(lastUserInput);
tfText.disableProperty().bind(cbReadOnly.selectedProperty().not());
lLeft.prefHeightProperty().bind(tfText.heightProperty());
cbReadOnly.prefHeightProperty().bind(tfText.heightProperty());
vBox.getChildren().add(tfText);
super.getChildren().add(vBox);
}
public void setCheckBoxSelected(Boolean selected) {
cbReadOnly.setSelected(selected);
if (selected) {
tfText.setText(lastUserInput);
}
else {
lastUserInput = tfText.getText();
tfText.setText(null);
}
}
public void setCheckBoxVisibleManaged(Boolean visible) {
configureCheckBoxProperty.setValue(visible);
}
public void setLeftLabelVisibleManaged(boolean selected) {
configureLeftLabelProperty.setValue(selected);
}
public void setTopLabelVisibleManaged(boolean selected) {
configureTopLabelProperty.setValue(selected);
}
}
// ExtendedTextField #######################################################
// OnlyAnchorPane ##########################################################
class OnlyAnchorPane extends AnchorPane {
OnlyAnchorPane(ExtendedTextField extendedTextField) {
super();
super.setStyle("-fx-background-color: BLANCHEDALMOND;");
// hbox
HBox hbox = new HBox();
hbox.setStyle("-fx-background-color: KHAKI;");
hbox.setSpacing(7.0d);
hbox.setPrefWidth(Double.MAX_VALUE);
// extendedTextField
VBox vbox = new VBox();
vbox.getChildren().add(extendedTextField);
HBox.setHgrow(vbox, Priority.ALWAYS);
hbox.getChildren().add(vbox);
// menu
MenuVBox menu = new MenuVBox(extendedTextField);
hbox.getChildren().add(menu);
AnchorPane.setBottomAnchor(hbox, 14d);
AnchorPane.setLeftAnchor(hbox, 14d);
AnchorPane.setTopAnchor(hbox, 14d);
AnchorPane.setRightAnchor(hbox, 14d);
super.getChildren().add(hbox);
}
}
// OnlyAnchorPane ##########################################################
// TabAnchorPane ###########################################################
class TabAnchorPane extends AnchorPane {
TabAnchorPane(ExtendedTextField extendedTextField) {
super();
super.setStyle("-fx-background-color: BLANCHEDALMOND;");
// tabpane
TabPane tp = new TabPane();
// tab
Tab t = new Tab("TextField");
t.setClosable(false);
tp.getTabs().add(t);
// hbox
HBox hbox = new HBox();
hbox.setStyle("-fx-background-color: KHAKI;");
hbox.setSpacing(7.0d);
hbox.setPrefWidth(Double.MAX_VALUE);
// extendedTextField
VBox vbox = new VBox();
vbox.getChildren().add(extendedTextField);
HBox.setHgrow(vbox, Priority.ALWAYS);
hbox.getChildren().add(vbox);
// menu
MenuVBox menu = new MenuVBox(extendedTextField);
hbox.getChildren().add(menu);
t.setContent(hbox);
AnchorPane.setBottomAnchor(tp, 14d);
AnchorPane.setLeftAnchor(tp, 14d);
AnchorPane.setTopAnchor(tp, 14d);
AnchorPane.setRightAnchor(tp, 14d);
super.getChildren().add(tp);
}
}
// TabAnchorPane ###########################################################
// MenuVBox ################################################################
class MenuVBox extends VBox {
MenuVBox(ExtendedTextField extendedTextField) {
super();
super.setStyle("-fx-background-color: HONEYDEW;");
super.setSpacing(7.0d);
super.setMaxWidth(200.0d);
super.setMinWidth(200.0d);
super.setPrefWidth(200.0d);
// show top label
CheckBox cb1 = new CheckBox("Show top label");
cb1.setSelected(true);
cb1.setOnAction((ActionEvent event) -> {
extendedTextField.setTopLabelVisibleManaged(cb1.isSelected());
});
super.getChildren().add(cb1);
// show left label
CheckBox cb2 = new CheckBox("Show left label");
cb2.setSelected(true);
cb2.setOnAction((ActionEvent event) -> {
extendedTextField.setLeftLabelVisibleManaged(cb2.isSelected());
});
super.getChildren().add(cb2);
// seperator
super.getChildren().add(new Separator());
// select checkbox
CheckBox cb3 = new CheckBox("Select checkbox");
cb3.setSelected(false);
cb3.setOnAction((ActionEvent event) -> {
extendedTextField.setCheckBoxSelected(cb3.isSelected());
});
super.getChildren().add(cb3);
// show checkbox
CheckBox cb4 = new CheckBox("Show checkbox");
cb4.setSelected(true);
cb4.setOnAction((ActionEvent event) -> {
extendedTextField.setCheckBoxVisibleManaged(cb4.isSelected());
});
super.getChildren().add(cb4);
}
}
// MenuVBox ################################################################
}
That is the problem of laying out maybe due to the fixed values you tried to give for related nodes:
lLeft.setMaxHeight(USE_PREF_SIZE);
lLeft.setMinHeight(USE_PREF_SIZE);
and
cbReadOnly.setMaxHeight(USE_PREF_SIZE);
cbReadOnly.setMinHeight(USE_PREF_SIZE);
This just a guess, but anyway you can manually request the renderer to layout the components just at the end of constructing of them via runLater():
class ExtendedTextField extends HBox {
...
...
private void init() {
...
Platform.runLater( ()->{
requestLayout();
});
}
...
}
BTW, I could not see any control that extends TextField ;)

word wrap for JTextArea not available not found in java

i am creating notepad and i have given the option of word wrap as in notepad
but when i write
textArea.setLineWrap(true);
than it gives me the error as shown
cannot Find Symbol
Symbol: method setLineWrap(boolean)
Location: Variable textArea of type TextArea
even when i press '.' and dropdown came for textArea but it doesnt shows setLineWrap boolean method
here is my code so far:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package test3;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
class Test3 extends JFrame{
private final JMenu Format;
private final JMenuItem Word;
private final TextArea textArea = new TextArea("", 0,0,TextArea.SCROLLBARS_VERTICAL_ONLY);
public Test3(){
setLayout(new FlowLayout()); //Default layout
JMenuBar menubar=new JMenuBar();
setJMenuBar(menubar);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(textArea);
Format=new JMenu("Format");
Word=new JMenuItem("Word wrap");
Format.add(Word);
menubar.add(Format);
event1 e1 =new event1 ();
Word.addActionListener(e1);
}
public class event1 implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
//textArea.setLineWrap(true);
//textArea.setWrapStyleWord(true);
}
}
public static void main(String []args){
Test3 t=new Test3();
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setTitle("Notepad");
t.setVisible(true);
t.setSize(1280,786);
}
}
I Have changed your code little bit.
Instead of TextArea I have used JTextArea
and a JScrollPane to wrap the JTextArea
class Test3 extends JFrame {
private final JMenu Format;
private final JMenuItem Word;
private final JTextArea textArea = new JTextArea("", 0, 0);
public Test3() {
setLayout(new FlowLayout()); //Default layout
JScrollPane scroll = new JScrollPane (textArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JMenuBar menubar = new JMenuBar();
setJMenuBar(menubar);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(scroll);
Format = new JMenu("Format");
Word = new JMenuItem("Word wrap");
Format.add(Word);
menubar.add(Format);
event1 e1 = new event1();
Word.addActionListener(e1);
}
public class event1 implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
}
}
public static void main(String[] args) {
Test3 t = new Test3();
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setTitle("Notepad");
t.setVisible(true);
t.setSize(1280, 786);
}
}
Instead of using TextArea use JTextArea.
class test2{
private final JMenu Format;
private final JMenuItem Word;
private final JTextArea textArea = new JTextArea("", 0,0,TextArea.SCROLLBARS_VERTICAL_ONLY);
test2(){
setLayout (new FlowLayout()); //Default layout
JMenuBar menubar=new JMenuBar();
setJMenuBar(menubar);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(textArea);
format=new JMenu("Format");
Word=new JMenuItem("Word wrap");
format.add(Word);
menubar.add(format);
event1 e1 =new event1 ();
Word.addActionListener(e18);
}
public class event18 implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
}
}
public static void main(String []args){
Test2 t=new Test2();
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setTitle("Notepad");
t.setVisible(true);
t.setSize(1280,786);
}
}

TitledPane - Event

I have two distinct components: a TableView and a TitledPane next to the table.
What I´m trying to do is to redimension the tableview but only when the titledpane expands or collapse.
When the titledpane collapse the tableview gets bigger and when it expands the tableview gets smaller.
I don´t know what action should I take.
Anybody knows the solution?
Regards
Check out the sample code below:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TitledPane;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MyDemo extends Application {
private TableView<Person> tableview = new TableView<Person>();
// Suppose your preferred height values for those 2 component are as follows:
private double TABLE_MIN_HEIGHT = 30.0;
private double TABLE_MAX_HEIGHT = 500.0;
private double TITLED_PANE_HEIGHT; // will be determined
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com"));
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
tableview.setItems(data);
tableview.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final TitledPane titledPane = new TitledPane("TitledPane", new Text("Content\n\n\n\n"));
titledPane.setAnimated(false); // we need to temporarily disable
// animation to get the titledpanes computed height correctly.
// Force to min height of table view
tableview.setMaxHeight(TABLE_MIN_HEIGHT);
tableview.setMinHeight(TABLE_MIN_HEIGHT);
// Here you have 2 options
int option = 2;
if (option == 1) {
// 1st simply force the table view height to its preferred max value
// when the titled pane's expanded property changed:
titledPane.expandedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
tableview.setMaxHeight(newValue ? TABLE_MIN_HEIGHT : TABLE_MAX_HEIGHT);
tableview.setMinHeight(newValue ? TABLE_MIN_HEIGHT : TABLE_MAX_HEIGHT);
}
});
} else if (option == 2) {
// 2nd. Similar to first but with "animation". Here observe height changes of titled pane:
titledPane.heightProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
tableview.setMaxHeight(TABLE_MAX_HEIGHT - (TABLE_MAX_HEIGHT * (newValue.doubleValue() / TITLED_PANE_HEIGHT)));
tableview.setMinHeight(TABLE_MAX_HEIGHT - (TABLE_MAX_HEIGHT * (newValue.doubleValue() / TITLED_PANE_HEIGHT)));
}
});
}
HBox hBox = new HBox(10);
hBox.getChildren().addAll(tableview, titledPane);
Scene scene = new Scene(hBox);
stage.setTitle("Table View Sample");
stage.setWidth(650);
stage.setHeight(700);
stage.setScene(scene);
TITLED_PANE_HEIGHT = titledPane.getHeight();
System.out.println("TITLED_PANE_HEIGHT = " + TITLED_PANE_HEIGHT);
stage.show();
// Determine the titledPane computed height value after stage has been shown.
TITLED_PANE_HEIGHT = titledPane.getHeight();
System.out.println("TITLED_PANE_HEIGHT = " + TITLED_PANE_HEIGHT);
// .. then enable animation
titledPane.setAnimated(true);
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
It is demo, improve it according to your needs. There maybe other approaches as well. HTH.

JavaFx 2.1, 2.2 TableView update issue

My application uses JPA read data into TableView then modify and display them. The table refreshed modified record under JavaFx 2.0.3. Under JavaFx 2.1, 2.2, the table wouldn't refresh the update anymore. I found other people have similar issue. My plan was to continue using 2.0.3 until someone fixes the issue under 2.1 and 2.2. Now I know it is not a bug and wouldn't be fixed. Well, I don't know how to deal with this. Following are codes are modified from sample demo to show the issue. If I add a new record or delete a old record from table, table refreshes fine. If I modify a record, the table wouldn't refreshes the change until a add, delete or sort action is taken. If I remove the modified record and add it again, table refreshes. But the modified record is put at button of table. Well, if I remove the modified record, add the same record then move the record to the original spot, the table wouldn't refresh anymore. Below is a completely code, please shine some light on this.
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
private TextField firtNameField = new TextField();
private TextField lastNameField = new TextField();
private TextField emailField = new TextField();
private Stage editView;
private Person fPerson;
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com"));
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(535);
stage.setHeight(535);
editView = new Stage();
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setMinWidth(150);
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setMinWidth(150);
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
//--- create a edit button and a editPane to edit person
Button addButton = new Button("Add");
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
fPerson = null;
firtNameField.setText("");
lastNameField.setText("");
emailField.setText("");
editView.show();
}
});
Button editButton = new Button("Edit");
editButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (table.getSelectionModel().getSelectedItem() != null) {
fPerson = table.getSelectionModel().getSelectedItem();
firtNameField.setText(fPerson.getFirstName());
lastNameField.setText(fPerson.getLastName());
emailField.setText(fPerson.getEmail());
editView.show();
}
}
});
Button deleteButton = new Button("Delete");
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (table.getSelectionModel().getSelectedItem() != null) {
data.remove(table.getSelectionModel().getSelectedItem());
}
}
});
HBox addEditDeleteButtonBox = new HBox();
addEditDeleteButtonBox.getChildren().addAll(addButton, editButton, deleteButton);
addEditDeleteButtonBox.setAlignment(Pos.CENTER_RIGHT);
addEditDeleteButtonBox.setSpacing(3);
GridPane editPane = new GridPane();
editPane.getStyleClass().add("editView");
editPane.setPadding(new Insets(3));
editPane.setHgap(5);
editPane.setVgap(5);
Label personLbl = new Label("Person:");
editPane.add(personLbl, 0, 1);
GridPane.setHalignment(personLbl, HPos.LEFT);
firtNameField.setPrefWidth(250);
lastNameField.setPrefWidth(250);
emailField.setPrefWidth(250);
Label firstNameLabel = new Label("First Name:");
Label lastNameLabel = new Label("Last Name:");
Label emailLabel = new Label("Email:");
editPane.add(firstNameLabel, 0, 3);
editPane.add(firtNameField, 1, 3);
editPane.add(lastNameLabel, 0, 4);
editPane.add(lastNameField, 1, 4);
editPane.add(emailLabel, 0, 5);
editPane.add(emailField, 1, 5);
GridPane.setHalignment(firstNameLabel, HPos.RIGHT);
GridPane.setHalignment(lastNameLabel, HPos.RIGHT);
GridPane.setHalignment(emailLabel, HPos.RIGHT);
Button saveButton = new Button("Save");
saveButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (fPerson == null) {
fPerson = new Person(
firtNameField.getText(),
lastNameField.getText(),
emailField.getText());
data.add(fPerson);
} else {
int k = -1;
if (data.size() > 0) {
for (int i = 0; i < data.size(); i++) {
if (data.get(i) == fPerson) {
k = i;
}
}
}
fPerson.setFirstName(firtNameField.getText());
fPerson.setLastName(lastNameField.getText());
fPerson.setEmail(emailField.getText());
data.set(k, fPerson);
table.setItems(data);
// The following will work, but edited person has to be added to the button
//
// data.remove(fPerson);
// data.add(fPerson);
// add and remove refresh the table, but now move edited person to original spot,
// it failed again with the following code
// while (data.indexOf(fPerson) != k) {
// int i = data.indexOf(fPerson);
// Collections.swap(data, i, i - 1);
// }
}
editView.close();
}
});
Button cancelButton = new Button("Cancel");
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
editView.close();
}
});
HBox saveCancelButtonBox = new HBox();
saveCancelButtonBox.getChildren().addAll(saveButton, cancelButton);
saveCancelButtonBox.setAlignment(Pos.CENTER_RIGHT);
saveCancelButtonBox.setSpacing(3);
VBox editBox = new VBox();
editBox.getChildren().addAll(editPane, saveCancelButtonBox);
Scene editScene = new Scene(editBox);
editView.setTitle("Person");
editView.initStyle(StageStyle.UTILITY);
editView.initModality(Modality.APPLICATION_MODAL);
editView.setScene(editScene);
editView.close();
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.getChildren().addAll(label, table, addEditDeleteButtonBox);
vbox.setPadding(new Insets(10, 0, 0, 10));
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
}
See the answer to Updating rows in Tableview. Add these getters and it will just work.
Additionally since the data is an ObservableList which is set as items to tableView, any changes to this data list will be reflected to the table.getItems() too. Namely no need to table.setItems(data) again.
I have found a simple workaround for triggering the refresh of the TableView in JavaFX 2.1 TableView refresh items. It solved the issue for me.
Add this to your code:
tableView.getColumns().get(0).setVisible(false);
tableView.getColumns().get(0).setVisible(true);
looking into the TableView.java code, there's private refresh() which just executes
getProperties().put(TableViewSkinBase.REFRESH, Boolean.TRUE);
At last, the code below worked for me(Java8). (be careful, the constant's name is not REFRESH but RECREATE)
tableView.getProperties().put(TableViewSkinBase.RECREATE, Boolean.TRUE);
(reading javafx's code, this will force cell re-creation)
Notification-based updates of JavaFX controls typically require that the properties of the data model object backing your GUI meet the minimum definition for a JavaFX Bean.
The following exemplifies the minimum code needed in order for a JavaFX property to satisfy these requirements:
public class Client extends DB {
private IntegerProperty id = new SimpleIntegerProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty firstName = new SimpleStringProperty();
public final int getID() {return this.id.get(); }
void setID(int id) { this.id.set(id); }
public final IntegerProperty idProperty() { return this.id; }
public final String getLastName() { return this.lastName.get(); }
public final void setLastName(String ln) { this.lastName.set(ln); }
public final StringProperty lastNameProperty() { return this.lastName; }
public final String getFirstName() { return this.firstName.get(); }
public final void setFirstName(String fn) { this.firstName.set(fn); }
public final StringProperty firstNameProperty() { return this.firstName; }
:
:
}
Glancing over your code, it does not appear that your properties satisfy the requirements for a JavFX Bean. As such, automatic notification-based updates will not occur.
I have the same problem, and not being able to add SimpleStringProperty to the POJO's used by JPA makes this a bit problematic. But it seems to me that this should be fixable issue because I have noticed the following behavior:
In my application, clicking on a row in the table populates some text fields on the screen, that the user can then edit.
At that point the user can save the data, or create a new item with the same or changed data. If the user creates a new item, which is then inserted into the observable list that the tableview represents, the change is immediately reflected in the contents of the tableview. However if the user just saves the change the new data is not reflected in the table. To put the new data in the list I'm simply doing
trialList.set(currentIndex, tempTrial);
And here's what I think points to this as a fixable issue: if I scroll the affected row out of view on the table and then scroll it back, the 'new' value(s) are now presented.
Hopefully, this can be fixed. Sorry this isn't an answer, so to speak, but might provide some insight for a fix.
this worked for me
#FXML
private void refreshTableView()
{
firstNameCol.setVisible(false);
lastNameCol.setVisible(false);
emailCol.setVisible(false);
firstNameCol.setVisible(true);
lastNameCol.setVisible(true);
emailCol.setVisible(true);
}
I had the same problem and after some search this is my workaround. I found that if the columns are removed and then re-added the table is updated.
public static <T,U> void refreshTableView(final TableView<T> tableView, final List<TableColumn<T,U>> columns, final List<T> rows) {
if (tableView == null) {
throw new NullPointerException();
}
if (columns == null) {
throw new NullPointerException();
}
if (rows == null) {
throw new NullPointerException();
}
tableView.getColumns().clear();
tableView.getColumns().addAll(columns);
ObservableList<T> list = FXCollections.observableArrayList(rows);
tableView.setItems(list);
}
Example of usage:
refreshTableView(myTableView, Arrays.asList(col1, col2, col3), rows);

Resources