javafx-TableView as combobox popup (Tried and able to achieve partially. need help further)

一曲冷凌霜 提交于 2019-12-10 11:30:05

问题


What i need:

  1. Need an editable combobox which filters the data on the popup upon typing and first matching item should be highlighted and should set as the text in the combo upon pressing enter.
  2. The popup should be a tableview with 2 or 3 columns. (screen shot attached.)(in the image it is a textfield but i prefer combo so that if the user is not sure about the values, he can click the combo button and see the entire list and select one.)

I will be binding some data as a source to the tableview which should act as the popup for the combobox. I know i should go for a custom control but dont know where to start?

Reference URL: enter link description here

Thanks in Advance.

What i have tried so far:

Guys,

With the idea you guys gave, I have tried this so far and able to achieve. (For now, i am not showing the tableview dynamically below the text field (eventually dats wat i want)) 1. A tableview with static data is already loaded and added to the scene. 2. Having a text field below the tableview. (this is named as txt) 3. Having another text field below the first text field(this is named as txt1) (when i press tab from the previous text field cursor should come here)

i have a predicate set for the table and i am updating my predicate as the user types in the txt. (working) Able to filter the table and the first matching row will highlighted. (working) When the user press either "Tab" or "Enter" the highlighted row in the tableview should be set as the value in the txt.(working)

Needed: 1. When i press "Tab" or "Enter", the highlighted row will be set as the value in the text field (txt) and also the cursor should move to next focusable node. in my case it is the 2nd text field (txt1). I dont want to say txt1.requestFocus() bcoz in realtime, i have many text fields in the scene and this control will be a user control. so cant hardcode anything.

  1. When the user types some text in the text field(not full text. eg: "do" where my table contains "Dom", "Don"), if there are multiple matches, currently both the records will be displayed in the table but the first one will be highlighted. User should be able to select the 2nd row if he wants by pressing the down arrow from the text field itself.

Main.java

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = FXMLLoader.load(this.getClass().getResource("MainView.fxml"));
            Scene scene = new Scene(root,500,300);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

MainController.java

package application;

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

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Popup;

public class MainController implements Initializable
{
    private @FXML TableView<Person> table;
    private @FXML TableColumn<Person, String> firstNameCol;
    private @FXML TableColumn<Person, String> lastNameCol;
    private @FXML TableColumn<Person, String> emailCol;
    private @FXML TableColumn<Person, Integer> ageCol;
    private @FXML TextField txt;
    private @FXML TextField txt1;
    private @FXML Button btn;

    @Override
    public void initialize(URL location, ResourceBundle resources)
    {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                txt.requestFocus();
            }
        });

        ObservableList<Person> obsList =FXCollections.observableArrayList();
        obsList.add(new Person("Sam", "P1LasttName", "P1Email@gmail.com", 20));
        obsList.add(new Person("Dom", "P2LasttName", "P2Email@gmail.com", 30));
        obsList.add(new Person("Ken", "P3LasttName", "P3Email@gmail.com", 40));
        obsList.add(new Person("Don", "P4LasttName", "P4Email@gmail.com", 50));
        obsList.add(new Person("Tom", "P5LasttName", "P5Email@gmail.com", 60));


        FilteredList<Person> filteredList = new FilteredList<>(obsList, p->true);
        table.setItems(filteredList);

        txt.textProperty().addListener((obs, oldValue, newValue) ->{

            filteredList.setPredicate(person-> {
                if(newValue == null || newValue.isEmpty())
                    return true;
                if(person.getFirstName().trim().toLowerCase().contains(newValue.toLowerCase()))
                    return true;
                return false;
            });

            Platform.runLater(new Runnable() {
                @Override
                public void run()
                {
                    // we don't want repeated selections
                    table.getSelectionModel().clearSelection();
                    //get the focus
                    table.requestFocus();

                    //select first item in TableView model
                    table.getSelectionModel().selectFirst();

                    //set the focus on the first element
                    table.getFocusModel().focus(0);

                    //render the selected item in the TableView
                    //tableClickHandler(null);
                }
            });

            Platform.runLater(new Runnable() {
                @Override
                public void run()
                {
                    txt.requestFocus();
                    txt.end();
                }
            });

        });

        table.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event)
            {
                if(event.getCode() == KeyCode.ENTER)
                {
                    txt.setText(table.getSelectionModel().getSelectedItem().getFirstName());
                }
            }
        });

        txt.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event)
            {
                if(event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)
                //if(event.getCode() == KeyCode.ENTER)
                {
                    txt.setText(table.getSelectionModel().getSelectedItem().getFirstName());
                    /*Platform.runLater(new Runnable() {
                        public void run() {
                            txt1.requestFocus();
                        }
                    });*/
                }
            }
        });

        /*txt.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event)
            {
                if(event.getCode() == KeyCode.TAB)
                {
                    //txt.setText(table.getSelectionModel().getSelectedItem().getFirstName());
                    if(txt.getSkin() instanceof BehaviorSkinBase)
                    {
                        //((BehaviorSkinBase)txt.getSkin()).getBehavior().traverseNext();
                        BehaviorBase x = ((BehaviorSkinBase)txt.getSkin()).getBehavior();
                        ((TextFieldBehavior)x).callAction("TraverseNext");
                    }
                    event.consume();
                }
            }
        });*/

        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event)
            {
                /*
                Popup popup = new Popup();
                popup.getContent().add(new TableView());
                //popup.show(txt, txt.localToScreen(0, 0).getX() + txt.getWidth()/2, txt.localToScreen(0, 0).getY() + txt.getHeight());
                popup.show(txt, txt.localToScreen(0, 0).getX(), txt.localToScreen(0, 0).getY() + txt.getHeight() + 2);
                */
                Parent vbox = null;
                try {
                    vbox = FXMLLoader.load(this.getClass().getResource("TableView.fxml"));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                Popup popup = new Popup();
                popup.getContent().add(vbox);
                //popup.show(txt, txt.localToScreen(0, 0).getX() + txt.getWidth()/2, txt.localToScreen(0, 0).getY() + txt.getHeight());
                //popup.show(txt, txt.localToScreen(0, 0).getX(), txt.localToScreen(0, 0).getY() + txt.getHeight() + 2);
                popup.show(txt, txt.localToScreen(0, 0).getX(), txt.localToScreen(0, 0).getY() + txt.getHeight() + 2);
            }
        });
    }
}

Person.java

package application;

public class Person
{
    private String firstName;
    private String lastName;
    private String email;
    private Integer age;

    public Person(){}

    public Person(String firstName, String lastName, String email, Integer age)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.age = age;
    }

    public String getFirstName()
    {
        return firstName;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    public Integer getAge()
    {
        return age;
    }

    public void setAge(Integer age)
    {
        this.age = age;
    }
}

application.css

.table-row-cell:selected
{
    -fx-background-color: lightgreen;
    /* the below style will remove the border lines of the selected row */
    -fx-table-cell-border-color: transparent;
}

MainView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.VBox?>

<!-- <?import application.Person?> -->

<VBox spacing="10.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
   <children>
      <TableView fx:id="table" prefHeight="250.0" prefWidth="437.0">
        <columns>
          <TableColumn fx:id="firstNameCol" prefWidth="120.0" text="First Name">
          <cellValueFactory><PropertyValueFactory property="firstName" /></cellValueFactory>
          </TableColumn>
          <TableColumn fx:id="lastNameCol" prefWidth="120.0" text="Last Name">
          <cellValueFactory><PropertyValueFactory property="lastName" /></cellValueFactory>
          </TableColumn>
            <TableColumn fx:id="emailCol" prefWidth="120.0" text="Email">
            <cellValueFactory><PropertyValueFactory property="email" /></cellValueFactory>
            </TableColumn>
            <TableColumn fx:id="ageCol" prefWidth="75.0" text="Age">
            <cellValueFactory><PropertyValueFactory property="age" /></cellValueFactory>
            </TableColumn>
        </columns>

      </TableView>
      <Button text="Button" fx:id="btn"/>
      <TextField fx:id="txt" promptText="Type to Filter" />
      <TextField fx:id="txt1" promptText="Focus should be here when tab is pressed from pervious txt" />
   </children>
   <padding>
      <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
   </padding>
</VBox>

TableView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.VBox?>
<?import application.Person?>
<?import javafx.collections.*?>

<!--
<VBox xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65">
<children>
-->

      <!--  <TableView xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:id="table" prefHeight="160.0" prefWidth="440.0"> -->
      <TableView xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:id="table" prefHeight="140.0">
        <columns>
          <TableColumn fx:id="firstNameCol" prefWidth="120.0" text="First Name">
          <cellValueFactory><PropertyValueFactory property="firstName" /></cellValueFactory>
          </TableColumn>
          <TableColumn fx:id="lastNameCol" prefWidth="120.0" text="Last Name">
          <cellValueFactory><PropertyValueFactory property="lastName" /></cellValueFactory>
          </TableColumn>
            <TableColumn fx:id="emailCol" prefWidth="120.0" text="Email">
            <cellValueFactory><PropertyValueFactory property="email" /></cellValueFactory>
            </TableColumn>
            <TableColumn fx:id="ageCol" prefWidth="75.0" text="Age">
            <cellValueFactory><PropertyValueFactory property="age" /></cellValueFactory>
            </TableColumn>
        </columns>

        <columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /></columnResizePolicy>

        <items>
        <FXCollections fx:factory="observableArrayList">
        <Person firstName="P1FirstName" lastName="P1LasttName" email="P1Email@gmail.com" age="20"/>
        <Person firstName="P2FirstName" lastName="P2LasttName" email="P2Email@gmail.com" age="30"/>
        <Person firstName="P3FirstName" lastName="P3LasttName" email="P3Email@gmail.com" age="40"/>
        <Person firstName="P4FirstName" lastName="P4LasttName" email="P4Email@gmail.com" age="50"/>
        <Person firstName="P5FirstName" lastName="P5LasttName" email="P5Email@gmail.com" age="60"/>
        </FXCollections>
        </items>

      </TableView>
<!--
</children>
</VBox>
-->

Any help is appreciated. Thanks!

来源:https://stackoverflow.com/questions/39372780/javafx-tableview-as-combobox-popup-tried-and-able-to-achieve-partially-need-he

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!