mercredi 25 octobre 2017

Working checkboxes in JavaFX table

(This is similar to a homework question.)

I recently made an example UI in Scenebuilder for something I later had to program with Java Swing. That more or less worked. Now it is my task, not for the actual development of the program, but for learning something in my job training, to make a similar UI with Scenebuilder, but this time an actually working one. The specifications are:

  • It's a window with a table in it.
  • At least two of the columns have radio boxes in them that look like checkboxes or checkboxes that act like radio boxes (because the company has weird standards).
  • It uses FXML files made with Scenebuilder for the layout.

Making the check boxes act as radio boxes should be easy, if I could just enable the editing. I found a lot of examples that do almost what I want, but are still all not really applicable to my situation. Here are some of them:

  • I started with this video and almost exactly copied the code to first have a working example. Then I adjusted it to my needs until I only had the check boxes to do (first working prototype had Booleans instead).
  • Then I took part of the full code of this answer to add the check boxes. That worked, but they don't react to clicks.
  • This, this and this seems to only apply to text fields, not checkboxes.
  • I then used the two lambda expressions from the second code block in this answer (actually I used the variant in the first answer and manually resolved some errors until suddenly Eclipse automatically converted it to lambda expressions). I also added the public ObservableValue<Boolean> getCompleted() method, Eclipse suggested some magic and then I had what you can see in the corresponding code below (without the console print).
  • I also added a listener to the boolean property, like this site apparently does (I think), but that doesn't seem like it helped much.

Here is a picture of how the dialog looks now, I still can't use the check boxes: enter image description here

My question: How can I make it so that the check boxes react to clicks? React can mean outputting something on the console, I don't need a given code that makes it automatically disable the other checkbox, I want to figure that part out myself.

My code:

src.controller.MainController.java

package controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import view.Table;
public class MainController implements Initializable{
 @FXML TableView<Table> tableID;
 @FXML TableColumn<Table,String> iFirstName;
 @FXML TableColumn<Table,String> iLastName;
 @FXML TableColumn<Table,Boolean> iMalebox;
 @FXML TableColumn<Table,Boolean> iFemalebox;
 @Override public void initialize(URL location,ResourceBundle resources){
  iFirstName.setCellValueFactory(new PropertyValueFactory<Table,String>("rFirstName"));
  iLastName.setCellValueFactory(new PropertyValueFactory<Table,String>("rLastName"));
  iMalebox.setCellValueFactory(p->p.getValue().getCompleted());
  iMalebox.setCellFactory(p->new CheckBoxTableCell<>());
  iMalebox.setEditable(true);
  // iMalebox.setCellValueFactory(p->p.getValue().getCompleted());
  // iMalebox.setCellFactory(p->new CheckBoxTableCell<>());
  iFemalebox.setCellValueFactory(p->p.getValue().getCompleted());
  iFemalebox.setCellFactory(p->new CheckBoxTableCell<>());
  // iMalebox.setCellValueFactory(new PropertyValueFactory<Table,Boolean>("rMalebox"));
  // iFemalebox.setCellValueFactory(new PropertyValueFactory<Table,Boolean>("rFemalebox"));
  tableID.setItems(FXCollections.observableArrayList(new Table("Horst","Meier",true,false),new Table("Anna","Becker",false,true),new Table("Karl","Schmidt",true,false)));
  tableID.setEditable(true);
 }
}

src.controller.MainView.java

package controller;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class MainView extends Application{
 @Override public void start(Stage primaryStage){
  try{
   // FXMLLoader.load(MainView.class.getResource("MainController.fxml"));
   AnchorPane page=(AnchorPane)FXMLLoader.load(MainView.class.getResource("MainController.fxml"));
   Scene scene=new Scene(page);
   primaryStage.setScene(scene);
   primaryStage.setTitle("Window Title");
   primaryStage.show();
  }catch(Exception e){
   Logger.getLogger(MainView.class.getName()).log(Level.SEVERE,null,e);
  }
 }
 public static void main(String[] args){
  Application.launch(MainView.class,(java.lang.String[])null);
 }
}

src.controller.MainController.fxml

<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="600.0" prefWidth="800.0" xmlns="http://ift.tt/2iyhPJC" xmlns:fx="http://ift.tt/1cgvoBb" fx:controller="controller.MainController">
 <children>
<TableView fx:id="tableID" prefHeight="494.0" prefWidth="798.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="iFirstName" prefWidth="75.0" text="First name" />
<TableColumn fx:id="iLastName" prefWidth="75.0" text="Last name" />
            <TableColumn fx:id="iMalebox" prefWidth="75.0" text="Male" />
            <TableColumn fx:id="iFemalebox" prefWidth="75.0" text="Female" />
</columns>
</TableView>
 </children>
</AnchorPane>

src.view.Table.java

package view;
import javafx.beans.InvalidationListener;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
public class Table{
 private SimpleStringProperty rFirstName;
 private SimpleStringProperty rLastName;
 private SimpleBooleanProperty rMalebox;
 private SimpleBooleanProperty rFemalebox;
 public Table(String sFirstName,String sLastName,Boolean sMalebox,Boolean sFemalebox){
  rFirstName=new SimpleStringProperty(sFirstName);
  rLastName=new SimpleStringProperty(sLastName);
  rMalebox=new SimpleBooleanProperty(sMalebox);
  rMalebox.addListener((ChangeListener)(observable,oldValue,newValue)->{
   System.out.println("test");
   System.out.println("abc");
  });
  rFemalebox=new SimpleBooleanProperty(sFemalebox);
 }
 public String getRFirstName(){
  return rFirstName.get();
 }
 public void setRFirstName(String v){
  rFirstName.set(v);
 }
 public String getRLastName(){
  return rLastName.get();
 }
 public void setRLastName(String v){
  rLastName.set(v);
 }
 public Boolean getRMalebox(){
  return rMalebox.get();
 }
 public void setRMalebox(Boolean v){
  rMalebox.set(v);
 }
 public Boolean getRFemalebox(){
  return rFemalebox.get();
 }
 public void setRFemalebox(Boolean v){
  rFemalebox.set(v);
 }
 public ObservableValue<Boolean> getCompleted(){
  return new ObservableValue<Boolean>(){
   @Override public void removeListener(InvalidationListener arg0){}
   @Override public void addListener(InvalidationListener arg0){}
   @Override public void removeListener(ChangeListener<? super Boolean> listener){}
   @Override public Boolean getValue(){
    return null;
   }
   @Override public void addListener(ChangeListener<? super Boolean> listener){
    System.out.println("Test");
   }
  };
 }
}




Aucun commentaire:

Enregistrer un commentaire