I'm having having trouble getting a correct output from tableview. I'm using a button to set one item from tableview to a label. However, it prints "StringProperty [Value pineapples]" where I would like it to be just "pineapples".
The tableview gives them correctly.
public class ProductListController implements Initializable {
#FXML public TableView<Model> tableview ;
#FXML private TableColumn<Model, Number> ProductID;
#FXML private TableColumn<Model, String> ProductName;
#FXML private TableColumn<Model, Number> ProductPrice;
#FXML private Label lblProduct;
#FXML private Label lblPrice;
#FXML
private void btnActionShow(ActionEvent event) {
assert tableview !=null : " ";
ProductID.setCellValueFactory(cellData -> cellData.getValue().ProductIDProperty());
ProductName.setCellValueFactory(cellData -> cellData.getValue().ProductNameProperty());
ProductPrice.setCellValueFactory(cellData -> cellData.getValue().ProductPriceProperty());
buildData();
}
private ObservableList<Model> data;
public void buildData(){
data = FXCollections.observableArrayList();
try{
Connection conn = DriverManager.getConnection
("jdbc:derby://localhost:1527/Stock", "*****", "*****");
Statement stmt = conn.createStatement();
String SQL = "SELECT * FROM PRODUCTS";
ResultSet rs = stmt.executeQuery(SQL);
while (rs.next()) {
Model mod = new Model();
mod.ProductID.set(rs.getInt("ID"));
mod.ProductName.set(rs.getString("NAME"));
mod.ProductPrice.set(rs.getInt("SELL_PRICE"));
data.add(mod);
}
tableview.setItems(data);
}
catch ( SQLException err) {
System.out.println(err.getMessage() );
}
}
//Button to fetch data from Tableview. Sets the data not the way I want.
#FXML
private void btnConfirmAction(ActionEvent event) {
Model model = tableview.getSelectionModel().getSelectedItem();
String prd;
prd = model.getProductName().toString();
lblProduct.setText(prd);
}
#FXML
private void btnNextAction(ActionEvent event) {
try{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/appl/Discount.fxml"));
Parent parent = loader.load();
DiscountController discountcontr = loader.getController();
discountcontr.setProduct(tableview.getSelectionModel().getSelectedItem().getProductName().toString());
Stage stage = new Stage();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
}
catch(IOException e){
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
Model
public class Model {
public SimpleIntegerProperty ProductID = new SimpleIntegerProperty();
public SimpleStringProperty ProductName = new SimpleStringProperty ();
public SimpleIntegerProperty ProductPrice = new SimpleIntegerProperty();
private final SimpleBooleanProperty Checked = new SimpleBooleanProperty(false);
public SimpleBooleanProperty checkedProperty() {
return this.Checked;
}
public java.lang.Boolean getChecked() {
return this.checkedProperty().get();
}
public void setChecked(final java.lang.Boolean checked) {
this.checkedProperty().set(checked);
}
public SimpleIntegerProperty getProductID() {
return ProductID;
}
public SimpleStringProperty getProductName() {
return ProductName;
}
public SimpleIntegerProperty getProductPrice() {
return ProductPrice;
}
Since getProductName() returns a SimpleStringProperty, you need to retrieve the String from it using the get(). Just use :
String prd = model.getProductName().get();
Your model is implemented incorrectly. You should use the following pattern:
public class Model {
private SimpleStringProperty productName = new SimpleStringProperty();
public SimpleStringProperty productNameProperty() {
return productName ;
}
public final String getProductName() {
return productNameProperty().get();
}
public final void setProductName(String productName) {
productNameProperty().set(productName);
}
}
and similarly for the other properties.
If you use the e(fx)clipse plugin, you can generate the methods automatically from the property definition by right-clicking, choosing "Source" and then "Generate JavaFX Getters and Setters". I think NetBeans has similar functionality.
Related
I'm working on an application for our warehouse. I've got a Tableview reading data form an SQL database. There's an Add button that allows to enter new products into the Tableview.
The Tableview loads just fine when started, but when I add a new product, the product adds just fine only the Tableview loads everything again. This gives double entries in the Tableview. Looking at the Database table in DBeaver, everything is correct (no double entries there and the new product is added).
In my previous version (before using JavaFx) I would add a method to the Add functionality which allows the Tableview to refresh itself. This worked fine. Now i'm working with JavaFX and this same principle is giving me this problem.
Here's the Load Method:
private void LoadPickTableMethod() {
String sql3 = "SELECT * FROM PICKLOCATIES";
try {
Connection con = ConnectDatabase.conDB();
ResultSet rs = con.createStatement().executeQuery(sql3);
while (rs.next()) {
picklocaties.add(new TableModel(rs.getString("ID"),
rs.getString("LOCATIE"),
rs.getString("ARTIKELCODE"),
rs.getString("OMSCHRIJVING"),
rs.getString("EENHEID"),
rs.getString("HAL"),
rs.getString("CODE"),
rs.getString("AANTAL"),
rs.getString("INITIAAL"),
rs.getString("MAX")));
}
} catch (SQLException ex) {
Logger.getLogger(ZoekenFXMLController.class.getName()).log(Level.SEVERE, null, ex);
}
col_id2.setCellValueFactory(new PropertyValueFactory<>("Id"));
col_locatie2.setCellValueFactory(new PropertyValueFactory<>("Locatie"));
col_artikelcode2.setCellValueFactory(new PropertyValueFactory<>("Artikelcode"));
col_omschrijving2.setCellValueFactory(new PropertyValueFactory<>("Omschrijving"));
col_eenheid2.setCellValueFactory(new PropertyValueFactory<>("Eenheid"));
col_hal1.setCellValueFactory(new PropertyValueFactory<>("Hal"));
col_oescode.setCellValueFactory(new PropertyValueFactory<>("Code"));
col_initiaalP.setCellValueFactory(new PropertyValueFactory<>("Initiaal"));
col_aantalP.setCellValueFactory(new PropertyValueFactory<>("Aantal"));
col_max.setCellValueFactory(new PropertyValueFactory<>("Max"));
searchTable1.setItems(picklocaties);
col_id.setCellValueFactory(new PropertyValueFactory<>("Id"));
col_locatie.setCellValueFactory(new PropertyValueFactory<>("Locatie"));
col_artikelcode.setCellValueFactory(new PropertyValueFactory<>("Artikelcode"));
col_omschrijving.setCellValueFactory(new PropertyValueFactory<>("Omschrijving"));
col_eenheid.setCellValueFactory(new PropertyValueFactory<>("Eenheid"));
col_hal.setCellValueFactory(new PropertyValueFactory<>("Hal"));
col_oescode1.setCellValueFactory(new PropertyValueFactory<>("Code"));
col_initiaalP1.setCellValueFactory(new PropertyValueFactory<>("Initiaal"));
col_aantalP1.setCellValueFactory(new PropertyValueFactory<>("Aantal"));
col_max1.setCellValueFactory(new PropertyValueFactory<>("Max"));
searchTable.setItems(picklocaties);
}
This method is called at the beginning (initialize), but also after clicking the Add button.
The Add method:
#FXML
private void AddPick(ActionEvent event) {
try {
String sql = "INSERT INTO PICKLOCATIES"
+ "(artikelcode, locatie, omschrijving, eenheid,code,hal,aantal, initiaal, max)"
+ "VALUES (?,?,?,?,?,?,?,?,?)";
conn = ConnectDatabase.conDB();
pst = conn.prepareStatement(sql);
pst.setString(1, autocompleteTf.getText());
pst.setString(3, pickDescTxt.getText());
pst.setString(2, autocompleteLoc.getText());
pst.setString(4, pickEenheidTxt.getText());
pst.setString(5, oesTxt.getText());
pst.setString(6, autocompleteHal.getText());
pst.setString(7, pickAantalTxt.getText());
pst.setString(8, pickInitiaalTxt.getText());
pst.setString(9, maxAantalTxt.getText());
pst.executeUpdate();
Alert dialog = new Alert(Alert.AlertType.INFORMATION);
dialog.setContentText("Artikel Toegevoegd");
dialog.setHeaderText("Informatie");
dialog.showAndWait();
ClearAllFields();
LoadPickTableMethod();
} catch (Exception e) {
Logger.getLogger(LoginFXMLController.class.getName()).log(Level.SEVERE, null, e);
}
}
Screenshot of what happens:
Screenshot Tableview
The last row is the newly added product (which loads only once) but the above rows are duplicates. The first 4 rows are the original ones, and the 4 below that are duplicates.
The goal is to have the Tableview update itself with the newly added product and not to duplicate itself along with it.
Any help on this would be greatly appreciated.
Edit: as per request, minimal reproducable example:
public class HomeFXMLController implements Initializable {
Connection conn = null;
ResultSet rs = null;
PreparedStatement pst = null;
#FXML
private TableView<TableModel> searchTable1;
#FXML
private TableColumn<TableModel, String> col_id2;
#FXML
private TableColumn<TableModel, String> col_locatie2;
#FXML
private TableColumn<TableModel, String> col_artikelcode2;
#FXML
private TableColumn<TableModel, String> col_omschrijving2;
#FXML
private TableColumn<TableModel, String> col_eenheid2;
#FXML
private TableColumn<TableModel, String> col_hal1;
#FXML
private TableColumn<TableModel, String> col_oescode;
#FXML
private TableColumn<TableModel, String> col_aantalP;
#FXML
private TableColumn<TableModel, String> col_initiaalP;
#FXML
private TableColumn<TableModel, String> col_max;
#FXML
private JFXTextField pickEenheidTxt;
#FXML
private JFXTextArea pickDescTxt;
#FXML
private JFXTextField pickIdTxt;
#FXML
private JFXTextField oesTxt;
#FXML
private JFXButton pickAddBtn;
#FXML
private JFXTextField maxAantalTxt;
#FXML
private JFXTextField autocompleteTf;
#FXML
private JFXTextField autocompleteLoc;
#FXML
private JFXTextField autocompleteHal;
ObservableList<TableModel> picklocaties = FXCollections.observableArrayList();
FilteredList filtered = new FilteredList(picklocaties, e -> true);
#Override
public void initialize(URL url, ResourceBundle rb) {
LoadPickTableMethod();
#FXML //this bit is linked to pickAddBtn
private void AddPick(ActionEvent event) {
try {
String sql = "INSERT INTO PICKLOCATIES"
+ "(artikelcode, locatie, omschrijving, eenheid,code,hal,aantal, initiaal, max)"
+ "VALUES (?,?,?,?,?,?,?,?,?)";
conn = ConnectDatabase.conDB();
pst = conn.prepareStatement(sql);
pst.setString(1, autocompleteTf.getText());
pst.setString(3, pickDescTxt.getText());
pst.setString(2, autocompleteLoc.getText());
pst.setString(4, pickEenheidTxt.getText());
pst.setString(5, oesTxt.getText());
pst.setString(6, autocompleteHal.getText());
pst.setString(7, pickAantalTxt.getText());
pst.setString(8, pickInitiaalTxt.getText());
pst.setString(9, maxAantalTxt.getText());
pst.executeUpdate();
Alert dialog = new Alert(Alert.AlertType.INFORMATION);
dialog.setContentText("Artikel Toegevoegd");
dialog.setHeaderText("Informatie");
dialog.showAndWait();
ClearAllFields();
LoadPickTableMethod();
} catch (Exception e) {
Logger.getLogger(LoginFXMLController.class.getName()).log(Level.SEVERE, null, e);
}
}
private void LoadPickTableMethod() {
String sql3 = "SELECT * FROM PICKLOCATIES";
try {
Connection con = ConnectDatabase.conDB();
ResultSet rs = con.createStatement().executeQuery(sql3);
while (rs.next()) {
picklocaties.add(new TableModel(rs.getString("ID"),
rs.getString("LOCATIE"),
rs.getString("ARTIKELCODE"),
rs.getString("OMSCHRIJVING"),
rs.getString("EENHEID"),
rs.getString("HAL"),
rs.getString("CODE"),
rs.getString("AANTAL"),
rs.getString("INITIAAL"),
rs.getString("MAX")));
}
} catch (SQLException ex) {
Logger.getLogger(ZoekenFXMLController.class.getName()).log(Level.SEVERE, null, ex);
}
col_id2.setCellValueFactory(new PropertyValueFactory<>("Id"));
col_locatie2.setCellValueFactory(new PropertyValueFactory<>("Locatie"));
col_artikelcode2.setCellValueFactory(new PropertyValueFactory<>("Artikelcode"));
col_omschrijving2.setCellValueFactory(new PropertyValueFactory<>("Omschrijving"));
col_eenheid2.setCellValueFactory(new PropertyValueFactory<>("Eenheid"));
col_hal1.setCellValueFactory(new PropertyValueFactory<>("Hal"));
col_oescode.setCellValueFactory(new PropertyValueFactory<>("Code"));
col_initiaalP.setCellValueFactory(new PropertyValueFactory<>("Initiaal"));
col_aantalP.setCellValueFactory(new PropertyValueFactory<>("Aantal"));
col_max.setCellValueFactory(new PropertyValueFactory<>("Max"));
searchTable1.setItems(picklocaties);
col_id.setCellValueFactory(new PropertyValueFactory<>("Id"));
col_locatie.setCellValueFactory(new PropertyValueFactory<>("Locatie"));
col_artikelcode.setCellValueFactory(new PropertyValueFactory<>("Artikelcode"));
col_omschrijving.setCellValueFactory(new PropertyValueFactory<>("Omschrijving"));
col_eenheid.setCellValueFactory(new PropertyValueFactory<>("Eenheid"));
col_hal.setCellValueFactory(new PropertyValueFactory<>("Hal"));
col_oescode1.setCellValueFactory(new PropertyValueFactory<>("Code"));
col_initiaalP1.setCellValueFactory(new PropertyValueFactory<>("Initiaal"));
col_aantalP1.setCellValueFactory(new PropertyValueFactory<>("Aantal"));
col_max1.setCellValueFactory(new PropertyValueFactory<>("Max"));
searchTable.setItems(picklocaties);
}
private void ClearAllFields() {
autocompleteTf.setText("");
pickDescTxt.setText("");
pickEenheidTxt.setText("");
autocompleteHal.setText("");
autocompleteLoc.setText("");
oesTxt.setText("");
pickAantalTxt.setText("");
pickInitiaalTxt.setText("");
maxAantalTxt.setText("");
}
}
The Table Model:
package voorraadsysteem;
public class TableModel {
public final String ID, Locatie, Artikelcode, Omschrijving,
Eenheid,
Hal, Code, Aantal, Initiaal, Max;
public TableModel(
String ID,
String Locatie,
String Artikelcode,
String Omschrijving,
String Eenheid,
String Hal,
String Code,
String Aantal,
String Initiaal,
String Max)
{
this.ID = ID;
this.Locatie = Locatie;
this.Artikelcode = Artikelcode;
this.Omschrijving = Omschrijving;
this.Eenheid = Eenheid;
this.Hal = Hal;
this.Code = Code;
this.Aantal = Aantal;
this.Initiaal = Initiaal;
this.Max = Max;
}
public String getID() {
return ID;
}
public String getLocatie() {
return Locatie;
}
public String getArtikelcode() {
return Artikelcode;
}
public String getOmschrijving() {
return Omschrijving;
}
public String getEenheid() {
return Eenheid;
}
public String getHal() {
return Hal;
}
public String getOescode() {
return Code;
}
public String getAantal() {
return Aantal;
}
public String getInitiaal() {
return Initiaal;
}
public String getMax(){
return Max;
}
}
My guess is it's because you initialize ObservableList picklocaties once when creating the class. Have you tried moving the initialization (=FXCollections.observableArrayList();) inside the AddPick method? This way an empty list will be generated everytime the method is called therefore adding the items in your DB only once.
When generating a multi view project with Gluon plugin for Ecplise, Netbeans or Intellij. It will be generating a view-class and a presenter-class. The view class looks like this for example:
public class ModelsView {
public View getView() {
try {
View view = FXMLLoader.load(ModelsView.class.getResource("models.fxml"));
return view;
} catch (IOException e) {
System.out.println("IOException: " + e);
return new View();
}
}
}
Is there some way I can access all the private fields in this controller models.fxml by just creating a code line like this:
View view = new ModelsView().getView(); // Here I am inside another controller
Can I access for example the getter method from the presenter-class by using the view object ? The view object is static as I can see it because there is no new before FXMLLoader.load(URL location)
public class ModelsPresenter {
#FXML
private View models;
#FXML
private #Getter TableView<String> tableView;
public void initialize() {
}
}
Heretic I am not using JavaFX from Gluon my configuration is jdk1.8.0_191 with derby in Netbeans 8.2 The code I am posting is my Model class PWData and the TableViewController just grabs the data from the derby DB The real important code is the initialize section of the TableViewController
public class PWData {
private final StringProperty ID;
private final StringProperty website;
private final StringProperty un;
private final StringProperty pw;
private final StringProperty sq;
private final StringProperty sans;
private final StringProperty notes;
public PWData(String ID,String website,String un,String pw,String sq,String sans,String notes) {
this.ID = new SimpleStringProperty(ID);
this.website = new SimpleStringProperty(website);
this.un = new SimpleStringProperty(un);
this.pw = new SimpleStringProperty(pw);
this.sq = new SimpleStringProperty(sq);
this.sans = new SimpleStringProperty(sans);
this.notes = new SimpleStringProperty(notes);
}
public String getID() {// 0
return ID.get();
}
public void setID(String ID){// 0
this.ID.set(ID);
}
public StringProperty IDProperty(){// 0
return ID;
}
public String getWebSite() {// 1
return website.get();
}
public void setwebsite(String website){// 1
this.website.set(website);
}
public StringProperty websiteProperty(){// 1
return website;
}
public String getUNName() {// 2
return un.get();
}
public void setun(String un){// 2
this.un.set(un);
}
public StringProperty unProperty(){// 2
return un;
}
public String getPW() {// 3
return pw.get();
}
public void setpw(String pw){// 3
this.pw.set(pw);
}
public StringProperty pwProperty(){// 3
return pw;
}
public String getSQName() {// 4
return sq.get();
}
public void setsq(String sq){// 4
this.sq.set(sq);
}
public StringProperty sqProperty(){// 4
return sq;
}
public String getSANS() {// 5
return sans.get();
}
public void setsans(String sans){// 5
this.sans.set(sans);
}
public StringProperty sansProperty(){// 5
return sans;
}
public String getNotes() {// 6
return notes.get();
}
public void setnotes(String notes){// 6
this.notes.set(notes);
}
public StringProperty notesProperty(){// 6
return notes;
}
public class TableViewController implements Initializable {
#FXML Pane tableviewPane,signinPane,detailviewPane;
#FXML private TableView<PWData> table;// NOTE CONSTRUCTION see Observable Value
#FXML private TableColumn<PWData,String> IDCol;
#FXML private TableColumn<PWData,String> websiteCol;
#FXML private TableColumn<PWData,String> unCol;
#FXML private TableColumn<PWData,String> pwCol;
String SQL_PWDataTable = "create table PWData ("
+ "ID int not null generated always as identity "
+ " (start with 100,increment by 1),"
+ "website varchar(50) not null, un varchar(40) not null, "
+ "pw varchar(40) not null, sq varchar(80) not null, "
+ "sans varchar(80) not null, notes varchar(260) not null,"
+ "primary key (ID) )";
String dbName="PWKeep";
public Stage stage;
String conURL = "jdbc:derby:C:/A_DerbyPWKeeper/DBName/" + dbName;
public static String strID;
KeyCode kc;
#FXML
private void onPress(KeyEvent ev) throws IOException{
kc = ev.getCode();
if(kc == KeyCode.ESCAPE){
onBack(null);
}
}
private void MakeTable() throws SQLException, IOException{
if (!tableExists( SignInController.con, "PWData")){
//System.out.println ("Creating table PWData");
SignInController.stmnt = SignInController.con.createStatement();
SignInController.stmnt.execute(SQL_PWDataTable );
SignInController.stmnt.close();
}else{
//System.out.println("PWData already created");
}
ReadFromDB();
}
// Does the table EXISTS
private static boolean tableExists ( Connection con, String table ) {
int numRows = 0;
try {
DatabaseMetaData dbmd = con.getMetaData();
// Note the args to getTables are case-sensitive!
ResultSet rs = dbmd.getTables( null, "APP", table.toUpperCase(), null);
while( rs.next()) ++numRows;
}catch(SQLException e){
String theError = e.getSQLState();
System.out.println("Can't query DB metadata: " + theError );
System.exit(1);
}
return numRows > 0;
}
private void ReadFromDB() throws SQLException{
SignInController.stmnt = SignInController.con.createStatement();
ObservableList<PWData> TableData = FXCollections.observableArrayList();
try (ResultSet rs = SignInController.stmnt.executeQuery("SELECT * FROM PWData") // Get all DB data
//int rowCount = 0;
) {
while (rs.next()){// Add data to observableArrayList TableData
//rowCount++;
TableData.add(new PWData(rs.getString("ID"),rs.getString("website")
,rs.getString("un"),rs.getString("pw"),rs.getString("sq"),rs.getString("sans"),rs.getString("notes")));
} //System.out.println("Row Count "+rowCount);// Useful for Printing for further development
PropertyValueFactory<PWData, String> IDCellValueFactory = new PropertyValueFactory<>("ID");
IDCol.setCellValueFactory(IDCellValueFactory);
PropertyValueFactory<PWData, String> WebSiteCellValueFactory = new PropertyValueFactory<>("website");
websiteCol.setCellValueFactory(WebSiteCellValueFactory);
PropertyValueFactory<PWData, String> UNCellValueFactory = new PropertyValueFactory<>("un");
unCol.setCellValueFactory(UNCellValueFactory);
PropertyValueFactory<PWData, String> PWCellValueFactory = new PropertyValueFactory<>("pw");
pwCol.setCellValueFactory(PWCellValueFactory);
Collections.sort(TableData, (p1, p2)-> p1.getWebSite().compareToIgnoreCase(p2.getWebSite()));
// Line of Code above Sorts websiteCol alpha
if(TableData.size() < 14) {// Format TableView to display Vertical ScrollBar
table.setPrefWidth(838);
}else {
table.setPrefWidth(855);
} table.setItems(TableData);
SignInController.stmnt.close();
}
}
#FXML
private void onBack(ActionEvent e) throws IOException{
stage = (Stage)tableviewPane.getScene().getWindow();
signinPane = FXMLLoader.load(getClass().getResource("signin.fxml"));
Scene scene = new Scene(signinPane);
scene.getStylesheets().add(getClass().getResource("pwkeeper.css").toExternalForm());
stage.setScene(scene);
stage.show();
stage.sizeToScene();
stage.centerOnScreen();
}
#FXML
private void onAdd(ActionEvent e) throws IOException{
stage = (Stage)tableviewPane.getScene().getWindow();
detailviewPane = FXMLLoader.load(getClass().getResource("detailview.fxml"));
Scene scene = new Scene(detailviewPane);
scene.getStylesheets().add(getClass().getResource("pwkeeper.css").toExternalForm());
stage.setScene(scene);
stage.show();
stage.sizeToScene();
stage.centerOnScreen();
}
private void MakeConn() throws SQLException, IOException{
SignInController.con = DriverManager.getConnection(conURL);
}
#FXML // This DROPS the MasterPW TABLE when the Reset Password is selected
private void onDrop(ActionEvent e) throws SQLException, IOException{
SignInController.stmnt = SignInController.con.createStatement();
SignInController.stmnt.executeUpdate("DROP TABLE MasterPW");
SignInController.stmnt.close();
onBack(null);
}
private void showTableDataDetails(PWData info) throws IOException{
if (info != null) {
info = (PWData) table.getSelectionModel().getSelectedItem();
strID = info.getID();
onAdd(null);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
try {
MakeTable();
} catch (SQLException | IOException ex) {
Logger.getLogger(TableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
table.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends PWData>
observable,PWData oldValue, PWData newValue) -> {
try {
showTableDataDetails((PWData) newValue); // When a row of the table is Selected call
// Proper Construction // showTableDataDetails method
} catch (IOException ex) {
Logger.getLogger(TableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
I am a little unsure of what you are trying to do but I would suggest you focus on the use of ObservableValue and Listeners You can download the entire code
At GitHub HERE
I am trying to run a method in a controller class specified to a particular task, once a specified key is pressed using KeyListener. But i'm unable to detect the keypress and invoke the java.awt.event keyPressed method. My code is as follows :
public class POSController implements KeyListener {
#Override
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.getKeyCode() == com.sun.glass.events.KeyEvent.VK_F1) {
try {
paymentAction();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
What could have gone wrong? Thanks in advance.
Here is the minimal executable example of the problem.
public class POSController implements KeyListener {
#FXML
private TableView<Product> productTableView;
#FXML
private TableView<Item> listTableView;
#FXML
private MenuItem logoutItem, profile;
#FXML
private javafx.scene.image.ImageView backImage;
#FXML
private MenuButton menuButton;
#FXML
private TableColumn<Item, String> itemColumn;
#FXML
private ComboBox<String> clientId, paymentMethod;
#FXML
private TableColumn<Item, Double> priceColumn, totalColumn, discountPercentageColumn, amountColumn;
#FXML
private TableColumn<Item, Integer> quantityColumn;
#FXML
private TableColumn<Product, String> productColumn;
#FXML
private TextField searchField,discountPercentage,productField,priceField,quantityField,vatPercentage,subTotalField,discountField,totalVatField,vatField,netPayableField,totalDiscountField;
#FXML
private TextField ;
#FXML
private TextField ;
#FXML
private TextField ;
#FXML
private TextField ;
#FXML
private TextArea descriptionArea;
#FXML
private Button addButton, removeButton, paymentButton, resetTableButton, resetButton;
#FXML
private Label quantityLabel, errorLabel, userName, backLabel;
#FXML
private ObservableList<Item> ITEMLIST;
public static Scene paymentScene;
private double xOffset = 0;
private double yOffset = 0;
public static double finalNetPayablePrice = 0.0;
public static double finalSubTotalPrice = 0.0;
public static double finalVat = 0.0;
public static double finalDiscount = 0.0;
public static String clientName = null;
public static String selectedPaymentMethod = null;
public static List<String> itemNames = new ArrayList<>();
public static List<Double> itemDiscounts = new ArrayList<>();
public static List<String> prices = new ArrayList<>();
public static List<String> quantities = new ArrayList<>();
public static List<String> subTotals = new ArrayList<>();
public static ObservableList<Item> itemList;
public static List<String> columnItemData = new ArrayList<>();
public static List<String> columnQuantityData = new ArrayList<>();
#FXML
private void initialize() throws SQLException, ClassNotFoundException, IOException {
ObservableList<Product> productsData = ProductDAO.searchGoodProducts(app.values.getProperty("STATUS_TYPE1"));
populateProducts(productsData);
}
#FXML
private void populateProducts(ObservableList<Product> productData) throws ClassNotFoundException {
productTableView.setItems(productData);
}
#Override
public void keyTyped(java.awt.event.KeyEvent e) {
}
#Override
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_F1) {
try {
paymentAction();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
#Override
public void keyReleased(java.awt.event.KeyEvent e) {
}
#FXML
public void paymentAction() throws Exception {
if (validateInputsForPayment()) {
Payment payment = new Payment();
FXMLLoader loader = new FXMLLoader((getClass().getResource(app.values.getProperty("INVOICE_VIEW_LOCATION"))));
Parent root = loader.load();
Stage stage = new Stage();
root.setOnMousePressed((MouseEvent e) -> {
xOffset = e.getSceneX();
yOffset = e.getSceneY();
});
root.setOnMouseDragged((MouseEvent e) -> {
stage.setX(e.getScreenX() - xOffset);
stage.setY(e.getScreenY() - yOffset);
});
Scene scene = new Scene(root);
stage.initModality(Modality.APPLICATION_MODAL);
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
this.paymentScene = scene;
stage.showAndWait();
}
}
You shouldn't be using java.awt.event.KeyListener for a JavaFX application. JavaFX has its own set of event API.
Assuming that POSController is a controller class for a particular FXML:
public class POSController {
#FXML private BorderPane root; // Or any other Node from FXML file
#FXML private void initialize() {
javafx.event.EventHandler<javafx.scene.input.KeyEvent> handler = event -> {
if (event.getCode() == javafx.scene.input.KeyCode.F1) {
try {
paymentAction();
} catch (Exception e1) {
e1.printStackTrace();
}
}
};
// I'm using root to get scene, but any node would be fine
if (root.getScene() != null) {
root.getScene().addEventHandler(javafx.scene.input.KeyEvent.KEY_PRESSED, handler);
}
else {
root.sceneProperty().addListener((obs, oldScene, newScene) -> {
if (newScene != null) {
root.getScene().addEventHandler(javafx.scene.input.KeyEvent.KEY_PRESSED, handler);
}
});
}
}
}
This will add the key event to the Scene. If you do not need to apply this event scene-wide, then you can add the event handler at other appropriate nodes.
Update
If there are any input controls in the scene, then you may need to use setEventFilter() instead of setEventHandler(). This is because those controls are probably going to consume the key event during the event bubbling phase.
I can't seem to get it right. I have a listbox with category items. I also have a data model that defines the ID, Name, Lastname, Category.. and an ObservableList that holds the data. I'm trying to update the existing object in case the user click on the same item in the listbox and change name, lastname.
Here is my code:
public class FXMLDocController implements Initializable {
ObservableList<String> listitems = FXCollections.observableArrayList(
"Visual Basic", "ASP.net", "JavaFX");
ObservableList<Persons> personData = FXCollections.observableArrayList();
Persons pp = new Persons();
private Label label;
#FXML
private TextField txtName;
#FXML
private TextField txtLastName;
#FXML
private Button btnSave;
#FXML
private TextArea txtArea;
#FXML
private ListView<String> listview = new ListView<String>();
#FXML
private Button btnTest;
#FXML
private Label lblCategory;
#FXML
private Label lblIndex;
#Override
public void initialize(URL url, ResourceBundle rb) {
listview.setItems(listitems);
}
#FXML
private void handleSave(ActionEvent event) {
String category = lblCategory.getText();
boolean duplicate = false;
//Add data. Check first if personData is empty
if (personData.isEmpty()){
pp = new Persons(Integer.valueOf(lblIndex.getText()),category,txtName.getText(),txtLastName.getText());
personData.add(pp);
}else{
for(int i = 0 ; i<personData.size() ; i ++){
if(Integer.toString(personData.get(i).getID()).equals(lblIndex.getText())){
duplicate = true;
}else{
duplicate = false;
}
}
System.out.println(duplicate);
if (duplicate == false){
pp = new Persons(Integer.valueOf(lblIndex.getText()),category,txtName.getText(),txtLastName.getText());
personData.add(pp);
}else{
System.out.println("Duplicate");
// Do Update later.
}
}
//Show data to Test
System.out.println("-- START OF LIST --");
for (Persons person : personData){
System.out.println(person.getID() + " " + person.getCategory()+ " " + person.getName() + " " + person.getLastname() + " " );
}
System.err.println(" ");
}
#FXML
private void handleListClick(MouseEvent event) {
lblCategory.setText(listview.getSelectionModel().getSelectedItem());
lblIndex.setText(String.valueOf(listview.getSelectionModel().getSelectedIndex()));
}
}
If I click multiple times on one item on the listbox it works well.. but if for example I click on Visual Basic, then ASP.net the go back to Visual Basic it still accepts it. :(
Need advice and help. Please
Here is the code based on Phil's suggestion
#FXML
private void handleSave(ActionEvent event) {
String category = lblCategory.getText();
boolean duplicate = false;
int x = 0;
//Add data
Persons newPerson = new Persons(Integer.valueOf(lblIndex.getText()), category, txtName.getText(), txtLastName.getText());
if (!personData.contains(newPerson)) {
personData.add(newPerson);
}else{
System.out.println("Duplicate!");
}
//Show data
System.out.println("-- START OF LIST --");
for (Persons person : personData){
System.out.println(person.getID() + " " + person.getCategory()+ " " + person.getName() + " " + person.getLastname() + " " );
}
}
here's my Persons Class
public class Persons {
private SimpleIntegerProperty id;
private SimpleStringProperty name;
private SimpleStringProperty lastname;
private SimpleStringProperty category;
public Persons(){}
public Persons(int id, String category, String name, String lastname){
this.id = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(name);
this.lastname = new SimpleStringProperty(lastname);
this.category = new SimpleStringProperty(category);
}
public Persons(String name, String lastname){
this.name = new SimpleStringProperty(name);
this.lastname = new SimpleStringProperty(lastname);
}
#Override
public boolean equals(Object o){
if (o == this) return true;
if (!(o instanceof Persons)){
return false;
}
Persons persons = (Persons) o;
return persons.id.equals(id) &&
persons.name.equals(name) &&
persons.lastname.equals(lastname) &&
persons.category.equals(category);
}
//SETTERS
public void setID(int id) {
this.id = new SimpleIntegerProperty(id);
}
public void setName(String name) {
this.name = new SimpleStringProperty(name);
}
public void setLastname(String lastname) {
this.lastname = new SimpleStringProperty(lastname);
}
public void setCategory(String category) {
this.category = new SimpleStringProperty(category);
}
//GETTERS
public int getID() {
return id.getValue();
}
public String getName() {
return name.getValue();
}
public String getLastname() {
return lastname.getValue();
}
public String getCategory(){
return category.getValue();
}
// PROPERTIES
public SimpleIntegerProperty idProperty(){
return this.id;
}
public SimpleStringProperty nameProperty(){
return this.name;
}
public SimpleStringProperty lastnameProperty(){
return this.lastname;
}
public SimpleStringProperty categoryProperty(){
return this.category;
}
}
Ok, this looks good. Just one little thing in your equals implementation:
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Persons)) {
return false;
}
Persons persons = (Persons) o;
// persons.id.equals() leads to the default implementation in Object
// --> instead use this one.
// The Property classes have their own isEqualTo method
// with get(), you will get your simple boolean from the returned BooleanBinding
return persons.id.isEqualTo(id).get() &&
persons.name.isEqualTo(name).get() &&
persons.lastname.isEqualTo(lastname).get() &&
persons.category.isEqualTo(category).get();
}
The default equals implementation from Object just compares if it is the same instance. And we are creating a new instance and check with contains(...) if the list contains the Persons.
Here is the whole code I used to test it:
public class Main extends Application {
private ObservableList<String> listitems = FXCollections.observableArrayList("Visual Basic", "ASP.net", "JavaFX");
private ObservableList<Persons> personData = FXCollections.observableArrayList();
private TextField txtName = new TextField();
private TextField txtLastName = new TextField();
private Button btnSave = new Button("save");
private ListView<String> listview = new ListView<>();
private Label lblCategory = new Label();
private Label lblIndex = new Label();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
listview.setItems(listitems);
listview.setOnMouseClicked(this::handleListClick);
btnSave.setOnAction(this::handleSave);
VBox vb = new VBox(new HBox(5, new Label("Index:"), lblIndex),
new HBox(5, new Label("Category:"), lblCategory),
new HBox(5, new Label("Name:"), txtName),
new HBox(5, new Label("Last name:"), txtLastName)
);
BorderPane bp = new BorderPane();
bp.setLeft(listview);
bp.setCenter(vb);
bp.setRight(btnSave);
Scene scene = new Scene(bp, 600, 400);
stage.setScene(scene);
stage.show();
}
private void handleSave(ActionEvent event) {
Persons newPerson = new Persons(Integer.valueOf(lblIndex.getText()), lblCategory.getText(), txtName.getText(), txtLastName.getText());
if (!personData.contains(newPerson)) {
personData.add(newPerson);
} else {
System.out.println("Duplicate!");
}
System.out.println("-- START OF LIST --");
for (Persons person : personData) {
System.out.println(person);
}
}
private void handleListClick(MouseEvent event) {
System.out.println("click");
lblCategory.setText(listview.getSelectionModel().getSelectedItem());
lblIndex.setText(String.valueOf(listview.getSelectionModel().getSelectedIndex()));
}
public class Persons {
SimpleIntegerProperty id;
SimpleStringProperty name;
SimpleStringProperty lastname;
SimpleStringProperty category;
Persons(int id, String category, String name, String lastname) {
this.id = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(name);
this.lastname = new SimpleStringProperty(lastname);
this.category = new SimpleStringProperty(category);
}
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Persons)) {
return false;
}
Persons persons = (Persons) o;
// persons.id.equals() leads to the default implementation in Object
// --> instead use this one.
// The Property classes have their own isEqualTo method
// with get(), you will get your simple boolean from the returned BooleanBinding
return persons.id.isEqualTo(id).get() &&
persons.name.isEqualTo(name).get() &&
persons.lastname.isEqualTo(lastname).get() &&
persons.category.isEqualTo(category).get();
}
#Override
public String toString() {
return "Persons{" +
"id=" + id +
", name=" + name +
", lastname=" + lastname +
", category=" + category +
'}';
}
}
}
I try set edit cell on run program. Set table editable, cellfactory and other.
I can edit the cell, when clicked with the mouse. But the call edit() method of TableView does not create Textfield.
What have I missed?
public class Main extends Application {
TableView <TestClass> tableView;
TableColumn <TestClass, String> stringColumn;
TableColumn <TestClass, String> editColumn;
ObservableList<TestClass> items;
#Override
public void start(Stage primaryStage) throws Exception{
makeTestData();
tableView = new TableView();
tableView.setEditable(true);
stringColumn = new TableColumn<>("Col1");
editColumn = new TableColumn<>("Col2");
tableView.getColumns().addAll(stringColumn, editColumn);
stringColumn.setCellValueFactory(cell -> cell.getValue().stringProperty());
editColumn.setCellValueFactory(cell -> cell.getValue().editProperty());
editColumn.setCellFactory(TextFieldTableCell.<TestClass>forTableColumn());
tableView.setItems(items);
tableView.getSelectionModel().select(1);
tableView.getSelectionModel().focus(1);
tableView.edit(1, editColumn); // !!! not create textfield ???
BorderPane pane = new BorderPane();
pane.setCenter(tableView);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public void makeTestData(){
items = FXCollections.observableArrayList(
new TestClass("str1", "edit1"),
new TestClass("str2", "edit2"),
new TestClass("str3", "edit3")
);
}
public class TestClass{
StringProperty string = new SimpleStringProperty();
StringProperty edit = new SimpleStringProperty();
public TestClass() {}
public TestClass(String string, String edit) {
this.string = new SimpleStringProperty(string);
this.edit = new SimpleStringProperty(edit);
}
public String getString() { return string.get();}
public StringProperty stringProperty() { return string; }
public void setString(String string) { this.string.set(string);}
public String getEdit() { return edit.get();}
public StringProperty editProperty() { return edit;}
public void setEdit(String edit) { this.edit.set(edit);}
}
}
yes im also getting this problem. the way i solved it is by putting the edit method call inside another fx thread.
Platform.runLater(() -> {
tableView.edit(row, editColumn);
});