【问题标题】:Combobox selections disappear when table editing canceled取消表格编辑时,组合框选择消失
【发布时间】:2016-05-29 17:56:54
【问题描述】:

好吧,我开始对这个失去理智了。我有一个表格视图,其中有 3 个组合框表格单元格。第一个是用户可以选择工作的框,所选工作会更改下一个组合框的选项(工作类别)。工作类别选择会更改劳动力框中的选项。所以向下的流程是:

工作 > 工作类别 > 劳动力。

我有一个非常特殊的问题。编辑表格时,您可以单击任何框以获取基于其他字段的可用选择的相应列表。这工作正常。它爆炸的是选择不是。为了让事情变得更有趣,它只会影响工作和工作类别组合框,劳动力框可以完美地工作。

症状:

--当通过esc取消编辑或失去焦点时,作业类别选择消失

--当通过 esc 取消编辑或失去焦点时,在工作类别字段中选择的选项被放置到工作字段中

以下是重现症状的步骤:

1) 点击工作类别框并启用编辑模式

2) 从下拉列表中进行新的选择

new selection made img

3) 点击工作框并启用编辑

4) 关闭工作框,点击同一行的工作类别或劳动框取消编辑

5) 启用工作类别编辑,然后通过单击人工/人工框或使用 esc 取消工作类别编辑

lose the job category / job selections img

这是在图形出现时初始化图形的代码:

public void initialize(URL location, ResourceBundle resources) {

    /* this is here because the screen handler will load up the Main screen in the
    in the hashmap; no connection data will be assigned to the user at that time.
    Without this block, when the hashmap attempts to load the Main data this
    will cause the screenhandler to error and the main application
    to not load correctly.  The block below initiatializes the connection to
    prevent this from happening.*/

    if ( vUsers.getConn() == null){
        try {
            //establishes a user's connection to the database
            vUsers.ConnecrDB();

        } catch (SQLException | IOException ex) {
            //debugging catch
            System.out.println(ex);
        }
    }

    //set the job box list for the user
    cmbxJobT.setItems(cmbxPopulator.getJobComboBox());

    cmbxJobT.valueProperty().addListener(new ChangeListener<String>(){
        @Override
        //reads the user's selectino and returns the appropriate labor codes for the Employee
        public void changed(ObservableValue o, String oldValue, String newValue){
            if (newValue != null){
                cmbxJobCatT.getItems().clear();
                cmbxJobCatT.getItems().addAll(cmbxPopulator.getJobCatComboBox(newValue));
            }else {
                cmbxJobCatT.getItems().clear();
                cmbxJobCatT.getItems().add(null);
            }
        }
    });

    cmbxJobCatT.valueProperty().addListener(new ChangeListener<String>(){
        @Override
        //reads the user's selectino and returns the appropriate labor codes for the Employee
        public void changed(ObservableValue o, String oldValue, String newValue){
            if (newValue != null){
                cmbxLaborT.getItems().clear();
                cmbxLaborT.getItems().addAll(cmbxPopulator.getLaborComboBox(newValue));
            }else {
                cmbxLaborT.getItems().clear();
                cmbxLaborT.getItems().add(null);
            }
        }
    });

    tblviewTime.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSel) ->{
        if (newSel != null){

            Model_Time current = tblviewTime.getSelectionModel().getSelectedItem();

            cmbxJobCatT.getItems().clear();
            cmbxJobCatT.getItems().addAll(cmbxPopulator.getJobCatComboBox(current.getJob()));

            cmbxLaborT.getItems().clear();                
            cmbxLaborT.getItems().addAll(cmbxPopulator.getLaborComboBox(current.getJobCat()));              
        }

        if (newSel == null){

             Model_Time current = tblviewTime.getSelectionModel().getSelectedItem();

            cmbxJobCatT.getItems().clear();
            cmbxJobCatT.getItems().addAll(cmbxPopulator.getJobCatComboBox(current.getJob()));

            cmbxLaborT.getItems().clear();                
            cmbxLaborT.getItems().addAll(cmbxPopulator.getLaborComboBox(current.getJobCat()));

        }
    });
    addDragListeners(bertaTabPane);
}

这是设置 tableview 的代码:

public void btnTimeSearch(ActionEvent event){


   //makes an instance of the toolkit needed to query user time.
   Database_RetrievesTime userData = new Database_RetrievesTime();

   //grabs data from the userinput fields to set the toolkit
   userData.setDateSelect(lblPickDateT.getValue());  
   userData.setJobBoxSelect(jobTbl.getIdByDesc(cmbxJobT.getValue()));
   userData.setLaborBoxSelect(laborTbl.getIdByDesc(cmbxLaborT.getValue()));
   userData.setJobCatSelect(jobCatTbl.getIdByDesc(cmbxJobCatT.getValue()));

    /*creates cell factories in each column and maps the cell values to the
    observable array list's IDs. The section also sets the columns up for user
    editing to be available and the methods to execute upon an editted cell
    being committed to entry.

    **NOTE:  The values are retrieved by the model class's getter methods. 
    Changing a name in the model class requires the user to update the getters.  
    Naming convention does apply.  So for example: a variable
    named cscHelp is added, it would need to have a getter called getCscHelp otherwise
    the corresponding column will return blanks.*/

    //setup ID column
    IDcol.setCellValueFactory(new PropertyValueFactory<>("ID"));

    //setup Datecol
    Datecol.setCellValueFactory(new PropertyValueFactory<>("userDate"));
    Datecol.setCellFactory(DatePickerTableCell.forTableColumn());
    //created a custom datepicker callback that can be reused throughout the code's interfaces
    Datecol.setOnEditCommit((CellEditEvent<Model_Time,LocalDate> t) -> {

            //generate a temporary variable to convert the LocalDate returned into a SimpleObjectProperty
            ObjectProperty<LocalDate> temp = new SimpleObjectProperty(t.getNewValue());
            //store the new value to the object's model
            t.getRowValue().setUserDate(temp);

            //store row's object to the change list
            Helper_TimShArrGen.addToEditedMatrix(t.getRowValue());
            //signaling to the program that a change had been made
            isChanged = true;
    });

    //job column setup
    Jobcol.setCellValueFactory(new PropertyValueFactory<>("Job"));
    Jobcol.setCellFactory(ComboBoxTableCell.forTableColumn(cmbxPopulator.getJobComboBox()));
    /*creates a combobox filled with the populated items found at initialization of the screen
    user inputs are automatically commited
    */

    Jobcol.setOnEditCommit((CellEditEvent<Model_Time,String> t) -> {

            SimpleStringProperty ssp = new SimpleStringProperty(t.getNewValue());
            //store selection to the object's model (unprocessed so values will show something like '6002: Kobota'
            t.getRowValue().setJob(ssp);
            //store row's object to the change list
            Helper_TimShArrGen.addToEditedMatrix(t.getRowValue());
            cmbxJobCatT.getItems().clear();
            cmbxJobCatT.getItems().addAll(cmbxPopulator.getJobCatComboBox(t.getRowValue().getJob()));
            //signaling a change has been made
            isChanged = true;
    });


    jobCatCol.setCellValueFactory(new PropertyValueFactory<>("JobCat"));
    jobCatCol.setCellFactory(ComboBoxTableCell.forTableColumn(cmbxPopulator.getJobCatComboBox(cmbxJobT.getValue())));
    jobCatCol.setOnEditCommit((CellEditEvent<Model_Time,String> t)->{

             SimpleStringProperty ssp = new SimpleStringProperty(t.getNewValue());
            //store selection to the object's model (unprocessed so values will show something like '6002: Kobota'
            t.getRowValue().setJob(ssp);
            //store row's object to the change list
            Helper_TimShArrGen.addToEditedMatrix(t.getRowValue());
            cmbxLaborT.getItems().clear();
            cmbxLaborT.getItems().addAll(cmbxPopulator.getLaborComboBox(t.getRowValue().getJob()));
            //signaling a change has been made
            isChanged = true;

    });

    //labor column setup works just like the job column
    Laborcol.setCellValueFactory(new PropertyValueFactory<>("Labor"));
    Laborcol.setCellFactory(ComboBoxTableCell.forTableColumn(cmbxPopulator.getLaborComboBox(cmbxJobCatT.getValue())));   
    Laborcol.setOnEditCommit((CellEditEvent<Model_Time,String> t) -> {

        SimpleStringProperty ssp = new SimpleStringProperty(t.getNewValue());
        t.getRowValue().setLabor(ssp);    
        Helper_TimShArrGen.addToEditedMatrix(t.getRowValue());
        t.getTableView().getItems().get(t.getTablePosition().getRow()).setLabor(ssp);
        isChanged = true;
    });

    //time column setup.  
    Timecol.setCellValueFactory(new PropertyValueFactory<>("Time"));
    Timecol.setCellFactory(TextFieldTableCell.<Model_Time, Float>forTableColumn(new FloatStringConverter()));
    Timecol.setOnEditCommit((CellEditEvent<Model_Time,Float> t) -> {

        //temp variable initialiation
        float token = t.getNewValue();
        //generate a temporary variable to convert the float return to a SimpleFloatProperty
        SimpleFloatProperty temp = new SimpleFloatProperty(token);
        //now update the row's object
        t.getRowValue().setTime(temp);
        //store row's object to the change list
        Helper_TimShArrGen.addToEditedMatrix(t.getRowValue());
        isChanged = true;
    });

    //set tableView editable
    tblviewTime.setEditable(true);

    //sets tableView to allow multiline selection
    TableViewSelectionModel<Model_Time> tvt = tblviewTime.getSelectionModel();
    tvt.setSelectionMode(SelectionMode.MULTIPLE); 

    /* checks if edits have been made.  If there are edits, it commits to the 
    database before wiping the arraylists and updating the table*/
    if (isChanged == true){
        /*makes sure there are no duplicate entries in the arraylist.  Throws out
        previous edits and takes the most recent*/
        Helper_TimShArrGen.validateMatrixEntries();
        //commits changes and resets the "isChanged" value.
        isChanged = Helper_TimShArrGen.confirmChanges(vUsers, jobTbl, jobCatTbl, laborTbl, isChanged);
    }

    /*tells the kit to run the querytime Method which uses the user input data
    and user data to search the timesheet tables and returns the user's time.*/
    if (isChanged == false){
        try {
            rs = userData.queryTime(vUsers.getConn(), vUsers.getLogin_ID());
        } catch (SQLException ex) {
            System.out.println(ex);
        }
    } else {
        return;
    }

    //sets up the observablelist for the tableview
    renderTable.setTableView(tblviewTime);
    ObservableList n = renderTable.generateTable(jobTbl, jobCatTbl, laborTbl, rs, vUsers.getConn());

    //renders the data on the screen`
    tblviewTime.setItems(n);


    Helper_TimeBreakDown breakdown = new Helper_TimeBreakDown();
    breakdown.setTblArr(n);
    breakdown.BreakDwnTim();
    lblMonTim.setText(String.valueOf(breakdown.getMon()));
    lblTuesTim.setText(String.valueOf(breakdown.getTues()));
    lblWedsTim.setText(String.valueOf(breakdown.getWeds()));
    lblThursTim.setText(String.valueOf(breakdown.getThurs()));
    lblFriTim.setText(String.valueOf(breakdown.getFri()));
    lblSatTim.setText(String.valueOf(breakdown.getSat()));
    lblSunTim.setText(String.valueOf(breakdown.getSun()));
    lblWkTim.setText(String.valueOf(breakdown.getWeek()));
}

这是处理进入列表的数据的类中的段。

public ObservableList<String> getJobComboBox(){

    //clear the jobList to clean out junk data between calls
    jobList.clear();

    //looks at the job table to determine if the job is active. If active, it reads the entry
    for (count=0; count<= jobTbl.getTblArray().size()-1; count++){
       if(jobTbl.getTblArray().get(count).isActive()){ 

           /*here we scroll through the JobIDList and match the IDs to the jobtbl
           data.  When a match is hit, we grab up the number on the job and the description
           this is added to another array that will become the combobox's list
           */
           for(inCount = 0; inCount <= jobIDList.size()-1; inCount++){
               if(jobIDList.get(inCount).getCol2ID() == jobTbl.getTblArray().get(count).getID()){
                   jobList.add(jobTbl.getNumById(jobIDList.get(inCount).getCol2ID()) 
                           + ": " + jobTbl.getDescById(jobIDList.get(inCount).getCol2ID()));
               }
           }
       }
    }

    /* there's probably a better dataset to use that won't allow duplicates
    due to my lack of knowledge at this time, I elected to create a hashset, pass the arrayList
    to the hashset to wipe out duplicates, and then pass it back to the arrayList to be used in the combobox
    */
   Set<String> tmp = new HashSet();

   tmp.addAll(jobList);
   jobList.clear();
   jobList.addAll(tmp);
   jobList.add(null);

    return jobList;
}

/**
 * 
 * @param job Argument for the selected Job String
 * @return returns the ObservableList of strings for the Job Category ComboBox 
 */
public ObservableList<String> getJobCatComboBox(String job){

    //clearing out old artifact data from the previous selection
    jobCatList.clear();

    //splitting the user's string selection apart (number as string, description as string)
    int jID=0;
    if (job != null){
        if (job.contains(": ")){
            String[] tmp = job.split(": ");
            job = tmp[1];
        }
    }

    // here we comb the job Table for a matching description and vacuum up the associated ID number
    for(count=0; count<=jobTbl.getTblArray().size()-1; count++){
        if(jobTbl.getTblArray().get(count).getDesc().equals(job)){
            jID = jobTbl.getTblArray().get(count).getID();
        }
    }

    /*using that jobID number to examine the fKey in the category table.
    once we match the JobID to the fKey ID in the jobCat table, we scoop up the
    the job Category code and description to create a list for the combobox
    */
    for (count=0; count<= jobCTbl.getTblArray().size()-1; count++){  
        for(inCount = 0; inCount <= jobCatIDList.size()-1; inCount++){

            if(jobCatIDList.get(inCount).getID() == jobCTbl.getTblArray().get(count).getID()){
                if(jobCTbl.getTblArray().get(count).getfKeyId() == jID){
                    jobCatList.add(jobCTbl.getNumById(jobCatIDList.get(inCount).getID()) 
                        + ": " + jobCTbl.getDescById(jobCatIDList.get(inCount).getID()));
                }
            }
        }
    }

    //same house keeping to remove duplicates as described above
    Set<String> tmp = new HashSet();
    tmp.addAll(jobCatList);
    jobCatList.clear();
    jobCatList.addAll(tmp);
    jobCatList.add(null);

    return jobCatList;
}

/**
 * 
 * @param jobCat Argument for the selected Job Category String
 * @return ObservableList of strings for the Labor ComboBox
 */
public ObservableList<String> getLaborComboBox(String jobCat){

    //temp arrays I needed to decode the affiliated connections
    ArrayList<Integer> jCID = new ArrayList();
    ArrayList<Integer> laborID = new ArrayList();

    //house keeping to remove artifact data from previous selections
    if(jCID != null){
    jCID.clear();
    }

    if(laborID != null){
    laborID.clear();
    }

    if(laborList !=null){
        laborList.clear();
    }

    //split user's string selection for the job category (numerical code as sting, description as string)
    if(jobCat != null){
        if (jobCat.contains(": ")){
            String[] tmp = jobCat.split(": ");
            jobCat = tmp[1];
        }
    }
    //use the description to find the affiliated job category ID
    for(count=0; count<=jobCTbl.getTblArray().size()-1; count++){
        if(jobCTbl.getTblArray().get(count).getDesc().equals(jobCat)){
            jCID.add(jobCTbl.getTblArray().get(count).getID());
        }
    }

    //use the job category ID to find the associated labor IDs from the associate entity table 
    for(count=0; count<=jCLTbl.getTblArray().size()-1; count++){
        for(inCount=0; inCount<=jCID.size()-1; inCount++){
            if(jCLTbl.getTblArray().get(count).getCol1ID() == jCID.get(inCount)){
                laborID.add(jCLTbl.getTblArray().get(count).getCol2ID());
            }     
        }
    }

    //use the labor ID to look up the needed data from the labor table.
    for (count=0; count<= laborTbl.getTblArray().size()-1; count++){
        for(inCount = 0; inCount <= laborID.size()-1; inCount++){
            if(laborID.get(inCount) == laborTbl.getTblArray().get(count).getID()){
                    laborList.add(laborTbl.getNumById(laborID.get(inCount)) 
                        + ": " + laborTbl.getDescById(laborID.get(inCount)));
                }
            }
        }

    //more housekeeping to remove duplicate entries.
    Set<String> tmp = new HashSet();
    tmp.addAll(laborList);
    laborList.clear();
    laborList.addAll(tmp);
    laborList.add(null);

    return laborList;
}   

我知道这里可能有更好的方法来做事。我对 JAVA 和编码还是很陌生。我在一家小公司工作,所以我是他们唯一的员工。不幸的是,这限制了我可以自学的内容,因此可能有一些更有效的方法可以在这里完成相同的任务。无论如何,如果有人能帮助我弄清楚发生了什么,将不胜感激。

【问题讨论】:

  • 当它“炸毁”时您是否看到任何错误消息?
  • 没有什么让它变得更加模棱两可。该程序认为它没有问题。

标签: javafx combobox tableview javafx-8 tablecell


【解决方案1】:

这个问题的答案其实可以在jobcatCol的SetOnEdit部分找到。

经过仔细检查和大量调试,我发现这一行

 t.getRowValue().setJob(ssp);

实际上应该是

 t.getRowValue().setJobCat(ssp);

我还选择放弃 ComboBoxTableCell API 并为每个单元格编写自己的组合框实现。这是一个非常基本的版本:

public class JobComboBoxCell extends TableCell<Model_Time, String>
{

    private ComboBox<String> comboBox;
    private Helper_UserSpecificTimDat cmbxPopulator = new Helper_UserSpecificTimDat();

    public JobComboBoxCell(Helper_UserSpecificTimDat cmbxPopulator)
    {
        comboBox = new ComboBox<>();
        this.cmbxPopulator = cmbxPopulator;
    }


    @Override
    public void startEdit()
    {
        if ( !isEmpty() )
        {
            super.startEdit();


            comboBox.setItems( cmbxPopulator.getJobComboBox() );
            comboBox.getSelectionModel().select( this.getItem() );

            comboBox.focusedProperty().addListener( new ChangeListener<Boolean>()
            {
                @Override
                public void changed( ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue )
                {
                    if ( !newValue )
                    {
                        commitEdit( comboBox.getSelectionModel().getSelectedItem() );
                    }
                }
            } );

            setText( null );
            setGraphic( comboBox );
        }
    }


    @Override
    public void cancelEdit()
    {
        super.cancelEdit();

        setText( ( String ) this.getItem() );
        setGraphic( null );
    }


    @Override
    public void updateItem( String item, boolean empty )
    {
        super.updateItem( item, empty );

        if ( empty )
        {
            setText( null );
            setGraphic( null );
        }
        else
        {
            if ( isEditing() )
            {
                setText( null );
                setGraphic( comboBox );
            }
            else
            {
                setText( this.getItem() );
                setGraphic( null );
            }
        }
    }

}

此代码由 Uluk Biy 在线程中的回复提供:Populate combo box list dynamically for each row in javaFx table view

我稍微修改了他的代码以专门满足我的需求。这解决了从工作类别字段中消失的值以及从工作类别字段到工作字段的数据传输的问题。

这是我不得不排除故障的最难的代码之一。它结合了 ComboBoxTableCell 的运行方式、组合框的动态数据以及我调用的 setter 中的错误。这是一场完美的混乱风暴,该计划因此没有发现任何例外。

感谢您的帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2014-10-09
    • 2011-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多