输入空格后FilteredList中断

时间:2014-05-23 19:32:19

标签: java listview javafx javafx-2 javafx-8

我有一个ListView,上面有一个TextField。如果用户在文本字段中输入搜索查询,则列表视图将更新并过滤自身以显示相关结果。

ListView显示FilteredList中的项目,该项目填充了Employee对象。每个员工都有名字和姓氏。

package application.ctrl;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import application.Main;
import application.objects.Employee;
import application.objects.EmployeeDatabase;

public class EmployeePickerWidget extends VBox implements Initializable {

   @FXML
   private TextField textField;
   @FXML
   private Button addNewEmployee;
   @FXML
   private ListView<Employee> employeeList;
   private FilteredList<Employee> filteredList;
   private ContextMenu cm;
   private CustomMenuItem item;
   private ClickedEmployeeInterface parent;



   public EmployeePickerWidget(ClickedEmployeeInterface parent) {
      FXMLLoader loader = new FXMLLoader(this.getClass().getResource(
            Main.EMPLOYEE_PICKER));
      loader.setRoot(this);
      loader.setController(this);
      try {
         loader.load();
      } catch (IOException e) {
         e.printStackTrace();
      }
      this.parent = parent;
   }



   @Override
   public void initialize(URL location, ResourceBundle resources) {
      setupEmployeeListView();
      setupTextField();

   }



   private void setupEmployeeListView() {
      filteredList = new FilteredList<Employee>(EmployeeDatabase.getInstance()
            .getObservableList());
      employeeList = new ListView<Employee>();
      employeeList.setItems(filteredList);
      employeeList.setOnMouseClicked(arg0 -> {
         if (employeeList.getSelectionModel().getSelectedItem() != null) {
            cm.hide();
            parent.handleClickedEmployee();
         }
      });
   }



   private void setupTextField() {
      textField.textProperty().addListener(
            (observable, oldValue, newValue) -> {
               filteredList.setPredicate(employee -> {
                  return filterHelper(employee, newValue);
               });
            });
      textField.setText(" ");
      textField.setText("");
      textField.setOnMouseClicked(event -> cm
            .show(textField, Side.BOTTOM, 0, 0));
      cm = new ContextMenu();
      item = new CustomMenuItem();

      VBox container = new VBox();
      container.setAlignment(Pos.CENTER_RIGHT);
      container.getChildren().add(employeeList);
      Button defineEmployeeBtn = new Button("Define New Employee");
      defineEmployeeBtn.setOnAction(event -> {
         FXMLLoader loader = new FXMLLoader(getClass().getResource(
               Main.DEFINE_NEW_EMPLOYEE));
         Parent root = null;
         try {
            root = loader.load();
         } catch (IOException e) {
            e.printStackTrace();
         }
         Scene newScene = new Scene(root);
         Stage newStage = new Stage();
         newStage.setScene(newScene);
         newStage.show();
      });
      container.getChildren().add(defineEmployeeBtn);
      item.setContent(container);
      cm.getItems().add(item);
   }



   private boolean filterHelper(Employee employee, String query) {
      String first = employee.getFirst().toLowerCase(), last = employee
            .getLast().toLowerCase();
      String[] querySplit = query.replace(",", "\\s").split("\\s+");
      int length = querySplit.length;
      for (int i = 0; i < length; i++)
         querySplit[i] = querySplit[i].toLowerCase();
      if (length == 1) {
         if (first.contains(querySplit[0]) || last.contains(querySplit[0]))
            return true;
         else
            return false;
      } else if (length == 2) {
         if (first.contains(querySplit[0]) || last.contains(querySplit[0]))
            if (first.contains(querySplit[1]) || last.contains(querySplit[1]))
               return true;
         return false;
      } else if (length == 3) {
         return false;
      }
      return false;
   }



   public Employee getEmployee() {
      return employeeList.getSelectionModel().getSelectedItem();
   }



   @FXML
   public void addNewEmployee() {

   }

}










interface ClickedEmployeeInterface {

   void handleClickedEmployee();
}

如果有3名员工被命名为&#34;唐纳德特朗普&#34;,&#34;唐纳德史密斯&#34;和&#34;唐纳德杰克逊&#34;在数据库中,需要进行以下操作:

  • 打字到#34; Donald&#34;将显示所有3个结果。
  • 在唐纳德之后键入一个空格(导致&#34;唐纳德&#34;)仍将显示3个结果。
  • 在上一次查询后输入一个T(结果为&#34;唐纳德T&#34;)只应显示1个结果。

问题是,在我进入空间后,ListView中断了,我的所有Employees都从ListView中消失了。当我在文本字段外单击并再次单击时,它会触发:

textField.setOnMouseClicked(event -> cm
            .show(textField, Side.BOTTOM, 0, 0));

我的ListView突然再次起作用,显示出一个Employee。

如何正确制作ListView过滤器而无需单击并重新登录?

1 个答案:

答案 0 :(得分:0)

我没有FXML文件,因此我无法复制您的问题。您的代码存在多个问题,这不是最佳解决方案,仍然,我已编辑您的答案,为您提供提示并帮助您了解可能出现逻辑错误的区域

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Side;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class DemoList extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        GridPane gridPane = new GridPane();
        Label label = new Label("Name");
        final TextField textField = new TextField();
        textField.setFocusTraversable(false);
        textField.setPromptText("Please Type Here");
        final ContextMenu cm = new ContextMenu();

        final ObservableList<String> employeeList = FXCollections
                .observableArrayList();
        employeeList.addAll("Donald Duck", "Donald Mouse", "Donald Goofy");

        textField.textProperty().addListener(new ChangeListener<String>() {

            @Override
            public void changed(ObservableValue<? extends String> arg0,
                    String arg1, String arg2) {
                // To clear the Context Menu so that same items are not added
                // multiple times
                cm.getItems().clear();
                for (String employee : employeeList) {
                    if (filterHelper(employee, arg2)) {
                        cm.getItems().add(new MenuItem(employee));
                    }
                }
            }
        });

        textField.setOnMouseClicked(new EventHandler<Event>() {

            @Override
            public void handle(Event arg0) {
                // To clear the Context Menu so that same items are not added
                // multiple times
                cm.getItems().clear();
                //Adding the data for initial click
                for (String employee : employeeList) {
                    if (filterHelper(employee, textField.getText())) {
                        cm.getItems().add(new MenuItem(employee));
                    }
                }
                cm.show(textField, Side.BOTTOM, 0, 0);
            }
        });

        gridPane.add(label, 0, 0);
        gridPane.add(textField, 0, 1);
        Scene scene = new Scene(gridPane, 300, 300);
        stage.setScene(scene);
        stage.show();
    }

    private boolean filterHelper(String employee, String query) {
        //Splitting Employee name to fetch first and last name
        String first = employee.split(" ")[0].toLowerCase(), last = employee
                .split(" ")[1].toLowerCase();
        String[] querySplit = query.replace(",", "\\s").split("\\s+");
        int length = querySplit.length;
        for (int i = 0; i < length; i++)
            querySplit[i] = querySplit[i].toLowerCase();
        /**
         * Avoid adding unnecessary return statement
         * I have removed all the 'return false' statements
         * The last return will take care of all the 'return false'
         */
        //only single word
        if (length == 1) {
            if (first.startsWith(querySplit[0])
                    || last.startsWith(querySplit[0]))
                return true;
        } 
        //two words, considering first word is first name
        //and second word is last name
        else if (length == 2) {
            if (first.startsWith(querySplit[0])
                    && last.startsWith(querySplit[1]))
                return true;
        }
        return false;
    }

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

}