2016-04-13 3 views
1

を無視してからJavaFXのテーブルを止めることはできません。 myTextRowクラスのテキストフィールドを検証したいと思います。 "setText2"メソッドでは、入力が6シンボルより大きくない場合は入力をチェックしますが、何の効果もありません。は、私はいくつかのテーブルのものを行うためにJavaFXのを使用しています私のセッター機能の検証

import java.util.ArrayList; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.scene.control.ContentDisplay; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TextArea; 
import javafx.util.Callback; 

import javafx.application.Application; 
import static javafx.application.Application.launch; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 

public class Supermain extends Application { 

    @Override 
    public void start(Stage primaryStage) { 

     ArrayList myindizes=new ArrayList(); 



     final TableView<myTextRow> table = new TableView<>(); 
     table.setEditable(true); 
     table.setStyle("-fx-text-wrap: true;"); 

     //Table columns 
     TableColumn<myTextRow, String> clmID = new TableColumn<>("ID"); 
     clmID.setMinWidth(160); 
     clmID.setCellValueFactory(new PropertyValueFactory<>("ID")); 

     TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text"); 
     clmtext.setMinWidth(160); 
     clmtext.setCellValueFactory(new PropertyValueFactory<>("text")); 
     clmtext.setCellFactory(new TextFieldCellFactory()); 

     TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2"); 
     clmtext2.setMinWidth(160); 
     clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2")); 
     clmtext2.setCellFactory(new TextFieldCellFactory()); 

     //Add data 
     final ObservableList<myTextRow> data = FXCollections.observableArrayList(
       new myTextRow(5, "Lorem","bla"), 
       new myTextRow(2, "Ipsum","bla") 
     ); 

     table.getColumns().addAll(clmID, clmtext,clmtext2); 
     table.setItems(data); 

     HBox hBox = new HBox(); 
     hBox.setSpacing(5.0); 
     hBox.setPadding(new Insets(5, 5, 5, 5)); 

     Button btn = new Button(); 
     btn.setText("Get Data"); 
     btn.setOnAction(new EventHandler<ActionEvent>() { 

      @Override 
      public void handle(ActionEvent event) { 
       for (myTextRow data1 : data) { 
        System.out.println("data:" + data1.getText2()); 
       } 
      } 
     }); 

     hBox.getChildren().add(btn); 

     BorderPane pane = new BorderPane(); 
     pane.setTop(hBox); 
     pane.setCenter(table); 
     primaryStage.setScene(new Scene(pane, 640, 480)); 
     primaryStage.show(); 


    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 


    public static class TextFieldCellFactory 
      implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> { 

     @Override 
     public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) { 
      TextFieldCell textFieldCell = new TextFieldCell(); 
      return textFieldCell; 
     } 

     public static class TextFieldCell extends TableCell<myTextRow, String> { 

      private TextArea textField; 
      private StringProperty boundToCurrently = null; 

      public TextFieldCell() { 

       textField = new TextArea(); 
       textField.setWrapText(true); 
       textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); 

       this.setGraphic(textField); 
      } 

      @Override 
      protected void updateItem(String item, boolean empty) { 
       super.updateItem(item, empty); 
       if (!empty) { 
        // Show the Text Field 
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 


        // myindizes.add(getIndex()); 

        // Retrieve the actual String Property that should be bound to the TextField 
        // If the TextField is currently bound to a different StringProperty 
        // Unbind the old property and rebind to the new one 
        ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex()); 
        SimpleStringProperty sp = (SimpleStringProperty) ov; 

        if (this.boundToCurrently == null) { 
         this.boundToCurrently = sp; 
         this.textField.textProperty().bindBidirectional(sp); 
        } else if (this.boundToCurrently != sp) { 
         this.textField.textProperty().unbindBidirectional(this.boundToCurrently); 
         this.boundToCurrently = sp; 
         this.textField.textProperty().bindBidirectional(this.boundToCurrently); 
        } 

        double height = real_lines_height(textField.getText(), this.getWidth(), 30, 22); 
        textField.setPrefHeight(height); 
        textField.setMaxHeight(height); 

        textField.setMaxHeight(Double.MAX_VALUE); 
        // if height bigger than the biggest height in the row 
        //-> change all heights of the row(textfields()typeof textarea) to this height 
        // else leave the height as it is 


        //System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue()); 
        //this.textField.setText(item); // No longer need this!!! 
       } else { 
        this.setContentDisplay(ContentDisplay.TEXT_ONLY); 
       } 
      } 

     } 

    } 

    public class myTextRow { 

     private final SimpleIntegerProperty ID; 

     private final SimpleStringProperty text; 
     private final SimpleStringProperty text2; 

     public myTextRow(int ID, String text,String text2) { 

      this.ID = new SimpleIntegerProperty(ID); 
      this.text = new SimpleStringProperty(text); 
      this.text2 = new SimpleStringProperty(text2); 


     } 

     public void setID(int id) { 
      this.ID.set(id); 
     } 

     public void setText(String text) { 
      this.text.set(text); 
     } 

     public void setText2(String text) { 
      if(text2check(text)){ 
      this.text2.set(text);} 
      else 
      {System.out.println("wrong value!!!");} 
     } 

     public int getID() { 
      return ID.get(); 
     } 

     public String getText() { 
      return text.get(); 
     } 

     public StringProperty textProperty() { 
     return text; 

     } 

     public String getText2() { 
      return text2.get(); 
     } 

     public StringProperty text2Property() { 
     return text2; 

     } 

    public IntegerProperty IDProperty() { 
     return ID; 
    } 

    public boolean text2check(String t) 
    { 
     if(t.length()>6)return false; 
     return true; 
    } 
    } 

    private static double real_lines_height(String s, double width, double heightCorrector, double widthCorrector) { 
     HBox h = new HBox(); 
     Label l = new Label("Text"); 
     h.getChildren().add(l); 
     Scene sc = new Scene(h); 
     l.applyCss(); 
     double line_height = l.prefHeight(-1); 

     int new_lines = s.replaceAll("[^\r\n|\r|\n]", "").length(); 
     // System.out.println("new lines= "+new_lines); 
     String[] lines = s.split("\r\n|\r|\n"); 
     // System.out.println("line count func= "+ lines.length); 
     int count = 0; 
     //double rest=0; 
     for (int i = 0; i < lines.length; i++) { 
      double text_width = get_text_width(lines[i]); 
      double plus_lines = Math.ceil(text_width/(width - widthCorrector)); 
      if (plus_lines > 1) { 
       count += plus_lines; 
       //rest+= (text_width/(width-widthCorrector)) - plus_lines; 
      } else { 
       count += 1; 
      } 

     } 
     //count+=(int) Math.ceil(rest); 
     count += new_lines - lines.length; 

     return count * line_height + heightCorrector; 
    } 

    private static double get_text_width(String s) { 
     HBox h = new HBox(); 
     Label l = new Label(s); 
     l.setWrapText(false); 
     h.getChildren().add(l); 
     Scene sc = new Scene(h); 
     l.applyCss(); 
     // System.out.println("dubbyloop.FXMLDocumentController.get_text_width(): "+l.prefWidth(-1)); 
     return l.prefWidth(-1); 

    } 

} 
+0

私は ')あなたは'のsetText(呼び出しん – user3776738

+0

...それはTextFieldCellFactoryを経由して「データ」ObservableListによって自動的に呼び出されたと思いましたか? – jns

+0

ありません:それは財産に直接セッターを呼び出し、ないあなたはモデルクラスで定義するsetメソッドを経由して(すなわち 'text2Property()のsetValue()'。)。あなたのコードの問題は、JavaFXプロパティパターンのルールに違反していることです。 'xProperty()。setValue(value)'は常に 'setX(value)'と同じでなければなりません。 –

答えて

1

JavaFXのプロパティパターンのルールは、プロパティxため、呼び出しxProperty().setValue(value)は常にsetX(value)を呼び出すのと同じでなければならないことです。あなたの妥当性検査はこれを真実にしない。セル実装が使用するバインディングは、プロパティのsetValueメソッドを呼び出します。そのため、検証チェックをバイパスします。

(注記:すべてのコードで、私は、彼らが適切なnaming conventionsに密着するように名前を変更するつもりです)

このパターンでプロパティを実装するデフォルトの方法は次のとおりです。

public class MyTextRow { 

    private final StringProperty text = new SimpleStringProperty(); 

    public StringProperty textProperty() { 
     return text ; 
    } 

    public final void setText(String text) { 
     textProperty().set(text); 
    } 

    public final String getText() { 
     return textProperty().get(); 
    } 
} 

はセットを有することによって/適切なプロパティ・メソッドへのメソッドのデリゲートを取得し、あなたはtextProperty()メソッドがサブクラスでオーバーライドされた場合でも、これらのルールが適用されていることが保証されています。 setメソッドとfinalメソッドをfinalにすると、それらのメソッドをオーバーライドするサブクラスによってルールが壊れないようになります。

public class MyTextRow { 

    private final StringProperty text2 = new StringPropertyBase() { 
     @Override 
     public String getName() { 
      return "text2"; 
     } 
     @Override 
     public Object getBean() { 
      return MyTextRow.this ; 
     } 
     @Override 
     public void setValue(String value) { 
      if (text2Check(value)) { 
       super.setValue(value); 
      } 
     } 
     @Override 
     public void set(String value) { 
      if (text2Check(value)) { 
       super.set(value); 
      } 
     } 
    } 

    public StringProperty text2Property() { 
     return text2 ; 
    } 

    public final void setText2(String text2) { 
     text2Property().set(text2); 
    } 

    public final String getText2() { 
     return text2Property().get(); 
    } 

    // ... 
} 

をしかし、私は(これはTextAreatextプロパティを使用して、あなたが持っていることを結合双方向を破るだろうと思い、次のように

一つのアプローチは、プロパティにsetsetValueメソッドをオーバーライドするかもしれません基本的には、変更が拒否されたときにテキストエリアに返信する方法がないため、テキストエリアは以前の値に戻すことを知らない)。 1つの修正は、バインディングの代わりにプロパティでリスナーを使用してセルを実装することです。テキスト領域にTextFormatterを使用すると、単にプロパティを更新し、変更が発生しない場合はテキストの変更を拒否することができます。ここで

は、このアプローチを使用して完全SSCCEです:

import java.util.function.Function; 
import java.util.function.UnaryOperator; 

import javafx.application.Application; 
import javafx.beans.property.Property; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.property.StringPropertyBase; 
import javafx.scene.Scene; 
import javafx.scene.control.ContentDisplay; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextArea; 
import javafx.scene.control.TextFormatter; 
import javafx.scene.control.TextFormatter.Change; 
import javafx.stage.Stage; 

public class VetoStringChange extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TableView<Item> table = new TableView<>(); 
     table.setEditable(true); 
     table.getColumns().add(column("Item", Item::nameProperty)); 
     table.getColumns().add(column("Description", Item::descriptionProperty)); 

     for (int i = 1; i <= 20 ; i++) { 
      table.getItems().add(new Item("Item "+i, "")); 
     } 

     primaryStage.setScene(new Scene(table, 600, 600)); 
     primaryStage.show(); 
    } 

    public static <S> TableColumn<S,String> column(String title, Function<S,Property<String>> property) { 
     TableColumn<S,String> col = new TableColumn<>(title); 
     col.setCellValueFactory(cellData -> property.apply(cellData.getValue())); 

     col.setCellFactory(tc -> new TextAreaCell<S>(property)); 
     col.setPrefWidth(200); 

     return col ; 
    } 

    public static class TextAreaCell<S> extends TableCell<S, String> { 

     private TextArea textArea ; 

     public TextAreaCell(Function<S, Property<String>> propertyAccessor) { 

      textArea = new TextArea(); 
      textArea.setWrapText(true); 
      textArea.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); 
      textArea.setMaxHeight(Double.MAX_VALUE); 

      UnaryOperator<Change> filter = c -> { 
       String proposedText = c.getControlNewText() ; 
       Property<String> prop = propertyAccessor.apply(getTableView().getItems().get(getIndex())); 
       prop.setValue(proposedText); 
       if (prop.getValue().equals(proposedText)) { 
        return c ; 
       } else { 
        return null ; 
       } 
      }; 
      textArea.setTextFormatter(new TextFormatter<String>(filter)); 
      this.setGraphic(textArea); 
     } 

     @Override 
     protected void updateItem(String item, boolean empty) { 
      super.updateItem(item, empty); 
      if (!empty) { 

       if (! textArea.getText().equals(item)) { 
        textArea.setText(item); 
       } 

       // Show the Text Field 
       this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 
      } else { 
       this.setContentDisplay(ContentDisplay.TEXT_ONLY); 
      } 
     } 

    } 



    public static class Item { 
     private final StringProperty name = new StringPropertyBase() { 

      @Override 
      public Object getBean() { 
       return Item.this; 
      } 

      @Override 
      public String getName() { 
       return "name" ; 
      } 

      @Override 
      public void set(String value) { 
       if (checkValue(value)) { 
        super.set(value); 
       } 
      } 

      @Override 
      public void setValue(String value) { 
       if (checkValue(value)) { 
        super.setValue(value); 
       } 
      } 

     }; 
     private final StringProperty description = new SimpleStringProperty(); 

     public Item(String name, String description) { 
      setName(name); 
      setDescription(description); 
     } 

     private boolean checkValue(String value) { 
      return value.length() <= 6 ; 
     } 

     public final StringProperty nameProperty() { 
      return this.name; 
     } 

     public final String getName() { 
      return this.nameProperty().get(); 
     } 

     public final void setName(final String name) { 
      this.nameProperty().set(name); 
     } 

     public final StringProperty descriptionProperty() { 
      return this.description; 
     } 

     public final String getDescription() { 
      return this.descriptionProperty().get(); 
     } 

     public final void setDescription(final String description) { 
      this.descriptionProperty().set(description); 
     } 

    } 

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

別のアプローチは、あなたの財産上の「コミットして戻す」型の戦略を可能にすることです。一般的には

public class MyTextRow { 

    private final StringProperty text2 = new SimpleStringProperty(); 

    public MyTextRow() { 
     text2.addListener((obs, oldText, newText) -> { 
      if (! checkText2(newText)) { 
       // sanity check: 
       if (checkText2(oldText)) { 
        text2.set(oldText); 
       } 
      } 
     }); 
    } 

    public StringProperty text2Property() { 
     return text ; 
    } 

    public final void setText2(String text2) { 
     text2Property().set(text2); 
    } 

    public final String getText2() { 
     return text2Property().get(); 
    } 
} 

私がして、検証を嫌います無効な値をリッスンし、このように戻すことができます。プロパティーの他のリスナーは、無効な値との変更を含むすべての変更を表示するためです。しかし、これはこの場合には最良の選択肢かもしれません。

最後に、最初のオプションのように無効な変更を拒否し、無効な文字列をもたらすテキスト入力を許可しないセルのコントロールでTextFormatterを設定することもできます。これは、ユーザビリティの観点からは必ずしも可能ではありません(空の文字列が無効な場合など、ほとんどの場合、すべてのテキストを一時的に削除することができます)。痛み。

+0

あなたの答えpuuh..thanks .. jqueryのhtml/jsと比較すると、これは絶対に処理できないので、私は再びjavaで新しいプロジェクトを行うことはありません。要素に簡単にアクセスすることはできません.HTMLファイルを埋め込み、Javaアプリケーションにajaxリクエストを送信してお互いに通信する方が簡単かもしれません。 – user3776738

+0

さて、あなたは好きなようには比較していません。 JavaFXはデスクトップUIツールキットであり、Webアプリケーションツールキットではありません。これは、非常に堅牢なビジネスロジックにフックするように設計されています。 JavaFXは決して完璧ではありませんが、バックエンド層がサーバーサイドで実装されているWebページテクノロジとは比較できません。フロントエンドの開発だけに興味があるのであれば、 'TextFormatter'でセル内で検証するのはなぜですか?または、Webテクノロジーを使用して記述した内容と同等の処理を行い、Webサービス要求を持つサーバーにビジネスを委任します。 –

+0

私は実際には、これがあなたが思っているほど難しいとは思わない。私が意図していた種類のセル実装の例を更新しました。実際には 'StringProperty'実装(VetoableStringProperty')を除外してより洗練されたものにすることはかなり簡単です。これは本当にそのようなフィット感を持っている価値がありますか? –

関連する問題