简体   繁体   English

JTable动态JCheckBox需要单击1次取消选中,但需要单击2次才能检查

[英]JTable dynamic JCheckBox needs 1 click to uncheck, but 2 clicks to check

I am fairly new to java, so please excuse me for any foolish mistakes i make ... 我对java很新,所以请原谅我犯的任何愚蠢的错误......

I have a JTable of 2 columns in which the 2nd column can have 4 types : 我有一个2列的JTable,其中第2列可以有4种类型:

  • a column in which values cannot be changed 无法更改值的列
  • a column which can contain any text string 一个可以包含任何文本字符串的列
  • a column which contains JComboBoxes 包含JComboBoxes的列
  • a column which contains JCheckBoxes 包含JCheckBoxes的列

The column types are dynamically since they depend on the data being received. 列类型是动态的,因为它们取决于接收的数据。

All types work fine, except the JCheckBox. 除JCheckBox外,所有类型都可以正常工作。 When I replace the JCheckBox with a JComboBox with 2 choices, then it works fine. 当我用带有2个选项的JComboBox替换JCheckBox时,它工作正常。 So i guess there is a problem in the code for the JCheckBox. 所以我猜JCheckBox的代码存在问题。

The problem is : 问题是 :

  • when the JCheckBox is checked, then I need only 1 click to uncheck it 当选中JCheckBox时,我只需要点击一下就可以取消选中它
  • however when the JCheckBox is unchecked, then I need to click it twice (not doubleclick) to check it 但是当取消选中JCheckBox时,我需要点击它两次(不是双击)来检查它

EDIT 编辑

An example project (as small as i can make it) : 一个示例项目(尽可能小):

    import java.awt.Component;
    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.table.*;

    public class frmCheck extends JApplet
    {
        JTable mgrdData;
        DefaultTableModel mtableModel;

        public void init()
        {
            mtableModel = new DefaultTableModel();
            mtableModel.setColumnCount(2);
            mtableModel.setRowCount(4);
            mgrdData = new JTable(mtableModel);
            mgrdData.getSelectionModel().addListSelectionListener(new RowListener());
            add(mgrdData);
            for (int i=1;i<mtableModel.getRowCount();i++)
            {
                addCheck(1);
            }
        }

        private class RowListener implements ListSelectionListener
        {
            public void valueChanged(ListSelectionEvent event)
            {
                if (event.getValueIsAdjusting()) return;
            }
        }

        private void addCheck(int intCol)
        {
            mgrdData.getColumnModel().getColumn(intCol).setCellRenderer(new TableCellRenderer()
            {
                public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean isFocused,int row,int col)
                {
                    JCheckBox rendererComponent = new JCheckBox();
                    String strVal="";
                    if (value!=null) strVal = value.toString();
                    if (strVal.equals("1"))
                    {
                        rendererComponent.setSelected(true);
                    } else
                    {
                        rendererComponent.setSelected(false);
                    }
                    return rendererComponent;
                }
            });
            DefaultCellEditor cellEditor = new DefaultCellEditor(new JCheckBox());
            cellEditor.setClickCountToStart(1);
            cellEditor.addCellEditorListener(new CellEditorListener()
            {
                public void editingCanceled(ChangeEvent e) {}
                public void editingStopped(ChangeEvent e)
                {
                    JCheckBox checkBox = (JCheckBox)((DefaultCellEditor)e.getSource()).getComponent();
                    System.out.println("isSelected = " + checkBox.isSelected());
                    if (checkBox.isSelected())
                    {
                        System.out.println("Sent 0");
                    } else
                    {
                        System.out.println("Sent 1");
                    }
                }
            });
            mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
        }
    }

The html page which i use to view the Applet is : 我用来查看Applet的html页面是:

<html>
  <body>
    <applet code="frmCheck.class" width="1016" height="822"></applet>
  </body>
</html>

To make it an executable (application) you can add the following main() function to it (above the init() function, and below the declaration of mtableModel) 要使它成为可执行文件(应用程序),您可以向其添加以下main()函数(在init()函数之上,并在mtableModel的声明之下)

        public static void main(String[] args) {
        frmCheck myApplet = new frmCheck(); // define applet of interest
        Frame myFrame = new Frame("Applet Holder"); // create frame with title

        // Call applet's init method (since Java App does not
        // call it as a browser automatically does)
        myApplet.init();    

        // add applet to the frame
        myFrame.add(myApplet, BorderLayout.CENTER);
        myFrame.pack(); // set window to appropriate size (for its elements)
        myFrame.setVisible(true); // usual step to make frame visible

      } 

When you click on an unchecked checkbox, then the console shows : 单击未选中的复选框时,控制台会显示:

isSelected = true
Sent 0

after that the checkbox is still unchecked when i click the checkbox again (thus for a second time), then the console shows : 之后,当我再次单击该复选框(因此第二次)时,复选框仍然未选中,然后控制台显示:

isSelected = false
Sent 1

the checkbox flashes as checked for a short time, and then becomes unchecked again when i then click the checkbox again (thus for a third time), then it behaves like being clicked for the first time 复选框闪烁检查短时间,然后当我再次单击复选框(因此第三次)时再次取消选中,然后它的行为就像是第一次点击

I want the checkbox to : - send 1 when unchecked and clicked - Send 0 when checked and clicked 我希望复选框: - 取消选中后单击发送1 - 选中并单击时发送0

The real project is a bit more complex : by checking the JCheckBox I send a message to a device, which answers with its current state, which is processed and shown as a checked JCheckBox. 真正的项目有点复杂:通过检查JCheckBox,我向设备发送一条消息,该设备以其当前状态进行回答,该状态被处理并显示为已检查的JCheckBox。 The processing works fine as when I change the state in the device via another channel, then the JCheckBox shows the current state perfectly 处理工作正常,因为我通过另一个通道更改设备中的状态,然后JCheckBox完美地显示当前状态

I would like the JCheckBox to respond to 1 click : 我希望JCheckBox响应1次点击:

  • when it's checked and I click it then it should send "REG SCH 4 = 0" 当它被检查并且我点击它然后它应该发送“REG SCH 4 = 0”
  • when it's unchecked and I click it then it should send "REG SCH 4 = 1" 当它取消选中并点击它然后它应该发送“REG SCH 4 = 1”

Ok here is the code i have so far : 好的,这是我到目前为止的代码:

The JTable is created as follows : JTable创建如下:

JTable mgrdData;
DefaultTableModel mtableModel;
mtableModel = new DefaultTableModel(null,new String[0]);
mgrdData = new JTable(mtableModel);
mgrdData.getSelectionModel().addListSelectionListener(new RowListener());
mgrdData.setFillsViewportHeight(true);
String[] strHeader = {"Naam","Waarde"};
mtableModel.setColumnIdentifiers(strHeader);

The columns are configured as follows : 列配置如下:

        addReadOnly(0);
//          addCombo(1,new String[]{"UIT","AAN"}); //this works fine
        addCheck(1);

Column 0 is readonly, and column 1 has 2 possible values where addCombo(1,new String[]{"UIT","AAN"}); 第0列是只读的,第1列有2个可能的值,其中addCombo(1,new String [] {“UIT”,“AAN”}); perfectly works 完美的作品

The functions addReadOnly and addCombo and addCheck are as follows : addReadOnly和addCombo以及addCheck函数如下:

private void addReadOnly(int intCol)
{
    JTextField txtField = new JTextField();
    txtField.setEditable(false);
    DefaultCellEditor cellEditor = new DefaultCellEditor(txtField);
    mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}

private void addCombo(int intCol,final String[] strItems)
{
    //add combobox
    mgrdData.getColumnModel().getColumn(intCol).setCellRenderer(new TableCellRenderer()
    {
        public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean isFocused,int row,int col)
        {
            JComboBox rendererComponent = new JComboBox(strItems);
            if (value!=null) rendererComponent.setSelectedItem(value.toString());
            return rendererComponent;
        }
    });
    DefaultCellEditor cellEditor = new DefaultCellEditor(new JComboBox(strItems));
    cellEditor.setClickCountToStart(1);
    cellEditor.addCellEditorListener(new CellEditorListener()
    {
        private boolean blnChanged=false;
        public void editingCanceled(ChangeEvent e) {}
        public void editingStopped(ChangeEvent e)
        {
            if (blnChanged==true)
            {
                JComboBox comboBox = (JComboBox)((DefaultCellEditor)e.getSource()).getComponent(); 
                sendVal(String.valueOf(comboBox.getSelectedIndex()));
                blnChanged = false;
            } else
            {
                blnChanged = true; 
            } 
        }
    });
    mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}

private void addCheck(int intCol)
{
    //add checkbox
    mgrdData.getColumnModel().getColumn(intCol).setCellRenderer(new TableCellRenderer()
    {
        public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean isFocused,int row,int col)
        {
            JCheckBox rendererComponent = new JCheckBox();
            String strVal="";
            if (value!=null) strVal = value.toString();
//              if (strVal.equals("AAN"))
            if (strVal.equals("1"))
            {
                rendererComponent.setSelected(true);
            } else
            {
                rendererComponent.setSelected(false);
            }
            return rendererComponent;
        }
    });
    DefaultCellEditor cellEditor = new DefaultCellEditor(new JCheckBox());
    cellEditor.setClickCountToStart(1);
    cellEditor.addCellEditorListener(new CellEditorListener()
    {
        public void editingCanceled(ChangeEvent e) {}
        public void editingStopped(ChangeEvent e)
        {
            JCheckBox checkBox = (JCheckBox)((DefaultCellEditor)e.getSource()).getComponent();
            System.out.println("isSelected = " + checkBox.isSelected());
            if (checkBox.isSelected())
            {
                sendVal("0");
                System.out.println("Sent 0");
            } else
            {
                sendVal("1");
                System.out.println("Sent 1");
            }
        }
    });
    mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}

Test results after 3 times clicking : 点击3次后测试结果:

JCheckBox is checked, result after 1 click : 检查JCheckBox,点击一下后得到结果:

isSelected = true
Sent : REG SCH 4 = 0
Sent 0

After this the JCheckBox is unchecked 在此之后,JCheckBox未被选中

JCheckBox is unchecked, result after 1 click : 未选中JCheckBox,单击一次后得到结果:

isSelected = true
Sent : REG SCH 4 = 0
Sent 0

After this the JCheckBox is still unchecked 在此之后,JCheckBox仍然未经检查

JCheckBox is unchecked but clicked once already, result after the second click : JCheckBox未经选中但已经点击一次,第二次点击后结果:

isSelected = false
Sent : REG SCH 4 = 1
Sent 1

After this the JCheckBox is checked 在此之后,检查JCheckBox

I search and found solution for when you always needed 2 clicks, or solutions with fixed checkboxes instead of dynamically, but not a case like mine .... 我搜索并找到解决方案,当你总是需要2次点击,或解决方案与固定复选框而不是动态,但不是像我的情况....

could anyone please shed a light ? 有人可以请光吗?

Answer 回答

Problem was that you were treating the checkbox value as a String when it's a boolean. 问题是,当它是布尔值时,您将复选框值视为字符串。

Working code is the following: 工作代码如下:

Boolean val = new Boolean(false);
if (value != null){
    val = (Boolean) value;
}
if (val.booleanValue()) {
    rendererComponent.setSelected(true);
}else{
     rendererComponent.setSelected(false);
}
return rendererComponent;

Old answer 老答案

I'm still looking at it, but I think the problem might be due to the fact that the JCheckBox is selected or not depending on: 我仍然在看它,但我认为问题可能是因为JCheckBox被选中或不依赖于:

if (strVal.equals("AAN"))
        {
            rendererComponent.setSelected(true);
        } else
        {
            rendererComponent.setSelected(false);
        }

Isn't "AAN" a value for the dropbox instead than for the checkbutton? "AAN"不是Dropbox的值而不是checkbutton的值吗?

An also, you're creating a new JCheckBox each time. 还有,你每次都在创建一个新的JCheckBox。

Maybe a SSCCE could be useful. 也许SSCCE可能有用。

The problem with your code is in getTableCellRendererComponent method. 代码的问题在于getTableCellRendererComponent方法。 Here you are always creating a new component with JCheckBox . 在这里,您始终使用JCheckBox创建新组件。 So every time it is taking a new JCheckBox and rendering the column. 所以每次它都采用新的JCheckBox并渲染列。

In addition to that there is no need to render a column to Boolean . 除此之外,不需要将列呈现为Boolean JTable it self will render that. JTable它会自我渲染。 You just need to specify the column type as Boolean.class. 您只需将列类型指定为Boolean.class. Overwrite the getColumnClass method in the model (DefaultTableModel, like I have shown) and say that column-1 is a Boolean. 覆盖模型中的getColumnClass方法(DefaultTableModel,就像我已经显示的那样),并说column-1是一个布尔值。

Applet Exampel

import javax.swing.DefaultCellEditor;
import javax.swing.JApplet;
import javax.swing.JCheckBox;
import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

    public class frmCheck extends JApplet
    {
        JTable mgrdData;
        DefaultTableModel mtableModel;

        public void init()
        {
            mtableModel = new DefaultTableModel() {
                @Override
                public Class<?> getColumnClass(int arg0) {
                    if(arg0 == 1) {
                        return Boolean.class; 
                    } else {
                        return super.getColumnClass(arg0);
                    }
                }
            };
            mtableModel.setColumnCount(2);
            mtableModel.setRowCount(4);
            mgrdData = new JTable(mtableModel);
//            mgrdData.getSelectionModel().addListSelectionListener(new RowListener());
            add(mgrdData);

            for (int i=1;i<mtableModel.getRowCount();i++)
            {
                addCheck(1);
            }
        }

        private class RowListener implements ListSelectionListener
        {
            public void valueChanged(ListSelectionEvent event)
            {
                if (event.getValueIsAdjusting()) return;
            }
        }

        private void addCheck(int intCol)
        {

            DefaultCellEditor cellEditor = new DefaultCellEditor(new JCheckBox());
             mgrdData.getColumnModel().getColumn(1).getCellEditor();
            cellEditor.setClickCountToStart(1);
            cellEditor.addCellEditorListener(new CellEditorListener()
            {
                public void editingCanceled(ChangeEvent e) {}
                public void editingStopped(ChangeEvent e)
                {
                    JCheckBox checkBox = (JCheckBox)((DefaultCellEditor)e.getSource()).getComponent();
                    System.out.println("isSelected = " + checkBox.isSelected());
                    if (checkBox.isSelected())
                    {
                        System.out.println("Sent 0");
                    } else
                    {
                        System.out.println("Sent 1");
                    }
                }
            });
            mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
        }
    }

PS: I have removed the unused code. PS:我删除了未使用的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM