5 Replies Latest reply: Jun 2, 2012 9:39 AM by 941172 RSS

    JavaFX Tables and Jython

    941172
      Hi all,

      I'm trying to use JavaFX tables with Jython and I'm trying to port the examples code that comes with the 'Ensenble' demo application; For some reason the table comes empty when I render the GUI and I was wondering if someone can point me into the right direction.

      Below is the jython script:
      #!/usr/bin/env jython
      import sys
      from javafx.application import Application
      from javafx.scene import Group, Scene
      from javafx.beans.property import StringProperty, SimpleStringProperty
      from javafx.collections import FXCollections, ObservableList
      from javafx.scene.control import TableColumn, TableView
      from javafx.scene.control.cell import PropertyValueFactory
      from javafx.util import Callback
      
      class Person:
      
              def __init__(self, fName, lName, email):
                  self.firstName = SimpleStringProperty(fName);
                  self.lastName = SimpleStringProperty(lName);
                  self.email = SimpleStringProperty(email);
      
              def setFirstName(self, firstName):
                      return self.firstName.set(firstName)
      
              def getFirstName(self):
                      return self.firstName.get()
      
              def setLastName(self, lastName):
                      return self.lastName.set(lastName)
      
              def getLastName(self):
                      return self.lastName.get()
      
              def setEmail(self, email):
                      return self.email.set(email)
      
              def getEmail(self):
                      return self.email.get()
      
      class TableSample(Application):
      
              def __gui__(self, primaryStage, data):
                      root = Group()
                      scene = Scene(root)
      
                      # Columns to show
                      firstNameCol = TableColumn()
                      firstNameCol.setText("First Name")
                      firstNameCol.setCellValueFactory(PropertyValueFactory("firstName"))
                      firstNameCol.setMinWidth(200)
      
                      lastNameCol = TableColumn()
                      lastNameCol.setText("Last Name")
                      lastNameCol.setMinWidth(200)
                      lastNameCol.setCellValueFactory(PropertyValueFactory("lastName"))
      
                      emailCol = TableColumn()
                      emailCol.setText("Email")
                      emailCol.setMinWidth(200)
                      emailCol.setCellValueFactory(PropertyValueFactory("email"))
      
                      # Define the view
                      tableView = TableView()
                      tableView.getColumns().setAll(firstNameCol, lastNameCol, emailCol)
      
                      # Add the data collection
                      tableView.setItems(data)
      
                      # Set the GUI
                      root.getChildren().add(tableView)
                      primaryStage.setTitle("Sample table")
                      primaryStage.setScene(scene)
                      primaryStage.show()
      
              def start(self, primaryStage):
                      data = FXCollections.observableArrayList(
                              Person("Jacob",     "Smith",    "jacob.smith@example.com" ),
                              Person("Isabella",  "Johnson",  "isabella.johnson@example.com" ),
                              Person("Ethan",     "Williams", "ethan.williams@example.com" ),
                              Person("Emma",      "Jones",    "emma.jones@example.com" ),
                              Person("Michael",   "Brown",    "michael.brown@example.com" )
                      )
                      self.__gui__(primaryStage, data)
      
      if __name__ == "__main__":
              Application.launch(TableSample().class, sys.argv[1:])
      Thanks in advance,

      --Jose                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
        • 1. Re: JavaFX Tables and Jython
          daniel
          Hi,

          First a disclaimer: I have never used jython (or it was so long ago that I don't remember)...

          I think that the PropertyValueFactory(<name>) expect to find a method:
          public ObservableValue<?> <name>Property() {
                return <name>Property;
          }
          in the beans added to the table.

          I suspect that if you add:
                  def firstNameProperty(self):
                          return self.firstName
          
                  def lastNameProperty(self):
                          return self.lastName
          
                 def emailProperty(self):
                          return self.email
          to your class Person, it might do the trick...

          -- daniel
          • 2. Re: JavaFX Tables and Jython
            941172
            Hello Daniel,

            No luck, the following doesn't seem to work:
            class Person:
            
                    def __init__(self, fName, lName, email):
                        self.firstName = SimpleStringProperty(fName);
                        self.lastName = SimpleStringProperty(lName);
                        self.email = SimpleStringProperty(email);
            
                    def firstNameProperty(self):
                            return self.firstName
            
                    def lastNameProperty(self):
                            return self.lastName
            
                    def emailProperty(self, email):
                            return self.email
            Still get the empty table. I agree with you that the mechanism to retrieve the values from the object don't match JavaFX expectations somehow and empty values are returned. Funny thing though is that the table object is aware it has 5 objects inside (is not empty).
            • 3. Re: JavaFX Tables and Jython
              941172
              I went a little further after reading this explanation of properties: http://blog.netopyr.com/2011/05/19/creating-javafx-properties/
              class Person:
              
                      def __init__(self, firstName, lastName , email):
                          self.setFirstName(firstName)
                          self.setLastName(lastName)
                          self.setEmail(email)
                          print "%s,%s,%s" % (self.getFirstName(),self.getLastName(), self.getEmail())
              
                      def getFirstName(self):
                        return self.firstName.get()
              
                      def setFirstName(self, firstName):
                              self.firstName = SimpleStringProperty(self, "firstName", firstName)
              
                      def firstNameProperty(self):
                              return self.firstName
              
                      def getLastName(self):
                        return self.lastName.get()
              
                      def setLastName(self, lastName):
                              self.lastName = SimpleStringProperty(self, "lastName", lastName)
              
                      def lastNameProperty(self):
                              return self.lastName
              
                      def getEmail(self):
                        return self.email.get()
              
                      def setEmail(self, email):
                              self.email = SimpleStringProperty(self, "email", email)
              
                      def emailNameProperty(self):
                              return self.email
              But once again, no luck.
              • 4. Re: JavaFX Tables and Jython
                daniel
                Well,

                I guess it all depends on how an jython object of class Person is mapped to a Java object in the JVM.
                I believe the PropertyValueFactory uses reflection to introspect the class of the beans in the table.
                If you configure your column with a PropertyValueFactory("firstName") - that PropertyValueFactory will use reflection to look for a noarg method named firstNameProperty() and returning an ObservableValue, on the bean's class. But this might not be what the jython script engine creates under the hood.
                In that case you might have to provide your own custom implementation of cellValueFactory for your table columns - instead of using directly PropertyValueFactory.
                The java documentation for TableView shows how to do this...

                hope this helps,

                -- daniel
                • 5. Re: JavaFX Tables and Jython
                  941172
                  Hello Daniel,

                  You were right, Jython is resolving this differently through reflection. I mplemented my own cell factory as you suggested and now the table shows the right contents. I'm attaching the whole code so if anybody stumps into this they can work around this issue.

                  Thanks for your help, code below:
                  #!/usr/bin/env jython
                  import sys
                  from javafx.application import Application
                  from javafx.scene import Group, Scene
                  from javafx.beans.property import StringProperty, SimpleStringProperty
                  from javafx.collections import FXCollections, ObservableList
                  from javafx.scene.control import TableColumn, TableView
                  from javafx.scene.control.cell import PropertyValueFactory
                  from javafx.util import Callback
                  
                  class CellFactoryPersonCallback(Callback):
                  
                       def __init__(self, name):
                            self.name = name
                  
                       def call(self, cellValue):
                            if self.name == "firstName":
                                 return cellValue.getValue().firstNameProperty()
                            elif self.name == "lastName":
                                 return cellValue.getValue().lastNameProperty()
                            elif self.name == "email":
                                 return cellValue.getValue().emailNameProperty()
                            else:
                                 return SimpleStringProperty("")
                  
                  class Person:
                  
                          def __init__(self, firstName, lastName , email):
                              self.setFirstName(firstName)
                              self.setLastName(lastName)
                              self.setEmail(email)
                              print "Added: %s,%s,%s" % (self.getFirstName(), self.getLastName(), self.getEmail())
                  
                          def getFirstName(self):
                            return self.firstName.get()
                  
                          def setFirstName(self, firstName):
                                  self.firstName = SimpleStringProperty(self, "firstName", firstName)
                  
                          def firstNameProperty(self):
                                  return self.firstName
                  
                          def getLastName(self):
                            return self.lastName.get()
                  
                          def setLastName(self, lastName):
                                  self.lastName = SimpleStringProperty(self, "lastName", lastName)
                  
                          def lastNameProperty(self):
                                  return self.lastName
                  
                          def getEmail(self):
                            return self.email.get()
                  
                          def setEmail(self, email):
                                  self.email = SimpleStringProperty(self, "email", email)
                  
                          def emailNameProperty(self):
                                  return self.email
                  
                  class TableSample(Application):
                  
                          def __gui__(self, primaryStage, data):
                                  root = Group()
                                  scene = Scene(root)
                  
                                  # Columns to show
                                  firstNameCol = TableColumn()
                                  firstNameCol.setText("First Name")
                                  firstNameCol.setCellValueFactory(CellFactoryPersonCallback("firstName"))
                                  firstNameCol.setMinWidth(200)
                  
                                  lastNameCol = TableColumn()
                                  lastNameCol.setText("Last Name")
                                  lastNameCol.setMinWidth(200)
                                  lastNameCol.setCellValueFactory(CellFactoryPersonCallback("lastName"))
                  
                                  emailCol = TableColumn()
                                  emailCol.setText("Email")
                                  emailCol.setMinWidth(200)
                                  emailCol.setCellValueFactory(CellFactoryPersonCallback("email"))
                  
                                  # Define the view
                                  tableView = TableView()
                                  tableView.getColumns().setAll(firstNameCol, lastNameCol, emailCol)
                  
                                  # Add the data collection
                                  tableView.setItems(data)
                  
                                  # Set the GUI
                                  root.getChildren().add(tableView)
                                  primaryStage.setTitle("Sample table")
                                  primaryStage.setScene(scene)
                                  primaryStage.show()
                  
                          def start(self, primaryStage):
                                  data = FXCollections.observableArrayList(
                                          Person("Jacob",     "Smith",    "jacob.smith@example.com" ),
                                          Person("Isabella",  "Johnson",  "isabella.johnson@example.com" ),
                                          Person("Ethan",     "Williams", "ethan.williams@example.com" ),
                                          Person("Emma",      "Jones",    "emma.jones@example.com" ),
                                          Person("Michael",   "Brown",    "michael.brown@example.com" )
                                  )
                                  self.__gui__(primaryStage, data)
                  
                  if __name__ == "__main__":
                          Application.launch(TableSample().class, sys.argv[1:])