2013-11-14 15 views
7

ho cella ListView personalizzato ho HBox con due controlli:JavaFX 8 personalizzato ListView Cells è male

  1. Etichetta con il campo nome
  2. E 'd'obbligo generato dal contesto di oggetto

Per esempio Ho impostato l'array di elementi ListView di Campi classe, se campo tipo Booleano creo CheckBox, se String i creo TextField ed ecc.

Il problema è: ottengo Oggetto campo solo nel metodo updateItem() - e solo lì posso creare i miei controlli.

In JavaFX 7 funziona tutto bene, ma su Java 8 non vedo i miei controlli.

Esiste il modo corretto per risolvere il caso?

UPDATE 1

esempio Qui completo per problema replicare:

package javafx8listviewexample; 

import java.lang.reflect.Field; 
import java.net.URL; 
import java.util.Date; 
import java.util.ResourceBundle; 
import javafx.collections.FXCollections; 
import javafx.event.ActionEvent; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.DatePicker; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.TextField; 
import javafx.scene.control.cell.TextFieldListCell; 
import javafx.util.Callback; 

/** 
* 
* @author dmitrynelepov 
*/ 
public class FXMLDocumentController implements Initializable { 

    static class TestClassForListView { 

     public String fieldString; 
     public Date fieldDate; 
    } 

    static class MyListCell extends ListCell<Field> { 

     /** 
     * As in tutorial 
     * 
     * @param t 
     * @param bln 
     */ 
     @Override 
     protected void updateItem(Field t, boolean bln) { 
      super.updateItem(t, bln); 
      if (t != null) { 
       if (t.getType().equals(String.class)) { 
        System.out.println("Draw string"); 
        setGraphic(new TextField(t.getName())); 
       } else if (t.getType().equals(Date.class)) { 
        System.out.println("Draw Date"); 
        setGraphic(new DatePicker()); 

       } 
      } 
     } 

    } 

    @FXML 
    private ListView<Field> listView; 

    @FXML 
    private void handleButtonAction(ActionEvent event) { 
     this.listView.getItems().clear(); 
     this.listView.setItems(
       FXCollections.observableArrayList(
         TestClassForListView.class.getFields() 
       ) 
     ); 
    } 

    @Override 
    public void initialize(URL url, ResourceBundle rb) { 
     this.listView.setCellFactory(new Callback<ListView<Field>, ListCell<Field>>() { 

      @Override 
      public ListCell<Field> call(ListView<Field> p) { 
       return new MyListCell(); 
      } 
     }); 

    } 

} 

Qui schermata del programma JDK 7

enter image description here

come u può vedere i TextField possono perseguire e modificato.

Ma se corro questo esempio con JDK 8 I Got

enter image description here

come qui u può vedere TextField cant essere messo a fuoco e modificato.

+0

Il codice completo e minimo per la replica del problema è importante per l'analisi. Se desideri ulteriore assistenza con la tua particolare implementazione e vorresti che qualcuno indagasse e spiegasse perché non funziona, dovrai inserire il codice per replicare il problema in una domanda modificata come [SSCCE] (http://sscce.org). – jewelsea

+2

Mentre la domanda è molto utile, potresti aggiornare il titolo? Dovrebbe riflettere in modo più accurato ciò che si trova così male negli oggetti ListCell personalizzati in javafx8. – demongolem

risposta

10

Sembra che si desidera un ControlsFX PropertySheet:

propertysheet


Una simile applicazione, è nella risposta alla JavaFX 2 TableView : different cell factory depending on the data inside the cell. Anche se la risposta a questa domanda è basata su TableView, sia i controlli virtualizzati ListView che TableView, quindi il concetto di implementazione è in qualche modo simile all'uso di un ListView con un HBox come delineato nella domanda.

tableproperty


aggiornamento sulla base di codice di esempio da domanda.

Continuo a pensare che un PropertySheet ControlsFX sembri la soluzione più appropriata per ciò che si sta tentando di realizzare. L'utilizzo di un controllo virtualizzato come un controllo ListView per tale compito rende semplicemente le cose più complicate di quanto debbano essere.

Una soluzione completa per un editor di proprietà basato su ListView è una cosa piuttosto complessa e al di fuori di ciò che può essere ragionevolmente fornito in una risposta StackOverflow.

Il codice di esempio fornito nella domanda presenta alcuni problemi.ListView è un controllo virtualizzato, pertanto non è necessario creare nuovi nodi grafici da inserire all'interno di ListView per tutto il tempo in cui viene chiamato l'aggiornamento. Quello che succede è che un campo di testo ottiene lo stato attivo, quindi l'aggiornamento viene richiamato sul ListView e si crea un nuovo campo di testo e, per impostazione predefinita, il nuovo campo di testo non ha il focus.

Penso che lo stesso ListView abbia alcuni problemi di implementazione per il tuo caso particolare e sta chiamando l'aggiornamento troppe volte. A prescindere da ciò, è necessario scrivere il codice in modo che sia possibile gestire in modo appropriato l'aggiornamento che viene chiamato più volte su una singola cella e. se lo fai, non importa se ListView chiama il tuo metodo più volte del necessario.

Ecco alcuni esempi di codice che possono aiutarti a fare ulteriori progressi. Non credo che il codice di esempio sia una soluzione completa al tuo problema, non è certamente fornito come un editor di proprietà completo per oggetti Java, ma forse potrebbe darti qualche spunto per migliorare e implementare il tuo codice (presumendo che tu decida di continuare a tentare di risolvere questo problema in questo modo). Se si continua a utilizzare ListView, è possibile esaminare le routine di modifica per ListView (simile a quanto definito per editing table cells nelle esercitazioni JavaFX di Oracle).

import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.collections.FXCollections; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.stage.Stage; 

import java.lang.reflect.Field; 
import java.time.LocalDate; 

/** 
* @author dmitrynelepov 
* Modified by Jewelsea 
*/ 
public class EvilHasSurvived extends Application { 

    static class TestClassForListView { 
     public String fieldString; 
     public LocalDate fieldDate; 

     @Override 
     public String toString() { 
      return "TestClassForListView{" + 
        "fieldString='" + fieldString + '\'' + 
        ", fieldDate=" + fieldDate + 
        '}'; 
     } 
    } 

    static class MyListCell extends ListCell<Field> { 
     private TextField textField; 
     private DatePicker datePicker; 
     private Object editedObject; 
     private ChangeListener<Boolean> editCommitHandler; 

     public MyListCell(Object editedObject) { 
      this.editedObject = editedObject; 
      setContentDisplay(ContentDisplay.RIGHT); 
     } 

     @Override 
     protected void updateItem(Field t, boolean bln) { 
      super.updateItem(t, bln); 

      if (datePicker != null) { 
       datePicker.focusedProperty().removeListener(editCommitHandler); 
      } 
      if (textField != null) { 
       textField.focusedProperty().removeListener(editCommitHandler); 
      } 

      if (t == null) { 
       setText(null); 
       setGraphic(null); 
       return; 
      } 

      if (t.getType().equals(String.class)) { 
       if (textField == null) { 
        textField = new TextField(); 
       } 

       editCommitHandler = (observable, oldValue, newValue) -> { 
        try { 
         t.set(editedObject, textField.getText()); 
         System.out.println(editedObject + " for " + textField + " value " + textField.getText()); 
        } catch (IllegalAccessException e) { 
         e.printStackTrace(); 
        } 
       }; 
       textField.focusedProperty().addListener(editCommitHandler); 

       setText(t.getName()); 
       setGraphic(textField); 
      } else if (t.getType().equals(LocalDate.class)) { 
       if (datePicker == null) { 
        datePicker = new DatePicker(); 
       } 

       editCommitHandler = (observable, oldValue, newValue) -> { 
        try { 
         t.set(editedObject, datePicker.getValue()); 
         System.out.println(editedObject + " for " + datePicker + " value " + datePicker.getValue()); 
        } catch (IllegalAccessException e) { 
         e.printStackTrace(); 
        } 
       }; 
       datePicker.focusedProperty().addListener(editCommitHandler); 

       setText(t.getName()); 
       setGraphic(datePicker); 
      } 
     } 
    } 

    @Override 
    public void start(Stage stage) throws Exception { 
     ListView<Field> listView = new ListView<>(); 
     listView.setItems(
      FXCollections.observableArrayList(
       TestClassForListView.class.getFields() 
      ) 
     ); 
     TestClassForListView testObject = new TestClassForListView(); 
     listView.setCellFactory(p -> new MyListCell(testObject)); 

     stage.setScene(new Scene(listView)); 
     stage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

Non è corretto ciò di cui ho bisogno e il modello updateItem funziona con TableView updateItem. Vedete: quando create TableView Cell è l'evento completo, ma se fate lo stesso su ListView come controllo sub Node - le sue chiamate si aggiornano ripetutamente. –

+0

Inserisci il tuo codice nella tua domanda. – jewelsea

+0

Domanda di aggiornamento: come puoi vedere - in updateItem - utilizzo lo stesso metodo setGraphics di te. –