2014-05-23 1 views
0

위의 TextField가있는 ListView가 있습니다. 사용자가 텍스트 필드에 검색어를 입력하면 목록보기가 업데이트되고 필터링되어 관련 결과를 표시합니다.공백을 입력하면 필터링 된 목록이 깨집니다.

ListView는 FilteredList에서 Employee 개체로 채워진 항목을 표시합니다. 각 직원은 성과 이름이 있습니다. 데이터베이스에 "도널드 잭슨" "부동산 재벌 도널드 트럼프", "도널드 스미스"라는 3 명 직원

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(); 
} 

이 있다면, 다음 요구 사항이 발생합니다 :

  • 단어까지 입력하면 "Donald"는 3 가지 결과를 모두 표시합니다.
  • Donald ("Donald"로 표시됨) 뒤에 공백을 입력해도 여전히 3 개의 결과가 표시됩니다.
  • 이전 쿼리 ("Donald T"결과) 다음에 T를 입력하면 결과가 1 개만 표시됩니다.

공간에 입력 한 후 ListView가 중단되고 모든 직원이 ListView에서 사라집니다.

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

을 그리고 내 ListView에 갑자기 하나 명 직원을 보여주는, 다시 작동 : 나는 텍스트 필드의 바깥 쪽을 클릭하고 다시 다시 클릭하면,이 트리거됩니다.

클릭하여 다시 넣지 않고도 ListView 필터를 올바르게 만들 수 있습니까?

답변

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); 
    } 

} 
관련 문제