【问题标题】:Jtable jcombobox and cell editingJtable jcombobox和单元格编辑
【发布时间】:2014-05-23 07:51:42
【问题描述】:

我想要一个有 4 列的 jtable。 一列必须是组合框。 其他列是字符串。

当我在一个单元格上单击一次时,我希望该单元格可以通过闪烁的插入符号/光标进行编辑。此外,如果我单击组合框,我希望组合框设置弹出窗口可见。

我已经阅读并测试了教程“如何使用表格”,如果我只单击单元格中的组合框,它就会打开。我的第一个问题是我不明白为什么教程中的代码在我们实现抽象表模型而不工作 DefaultTableModel 时工作。

我的代码是:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

public class JtabletestOK {

    public static void main(String[] args) {

        JtabletestOK test = new JtabletestOK();
        test.go();
    }

    public void go() {

        //create the frame
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



        //create a table and add it to a scroll pane in a new tab
        JTable jTable1 = new JTable()
        {
            //  Place cell in edit mode when it 'gains focus'

            public void changeSelection(
                    int row, int column, boolean toggle, boolean extend)
            {
                super.changeSelection(row, column, toggle, extend);

                if (editCellAt(row, column))
                {
                    Component editor = getEditorComponent();
                    editor.requestFocusInWindow();
                    // System.out.println("ffin focus gagne");
                    if (editor instanceof JTextField) {

                        JTextField jf = (JTextField) editor;
                        jf.select(0, jf.toString().length());
                    }}
            }
        };


        jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
        jTable1.setFillsViewportHeight(true);

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(jTable1);

        Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4"  };
        DefaultTableModel model = new DefaultTableModel(columnNames, 0);

        Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
        model.addRow(rowData);
        jTable1.setModel(model);


        String[] comboBoxArray = {"proem1","veitem2","atem3"};
        JComboBox jcb = new JComboBox(comboBoxArray);
        jcb.setEditable(true);


        TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
        colCombo.setCellEditor(new DefaultCellEditor(jcb));

        jcb.setEditable(true);



        frame.getContentPane().add(scrollPane);
        frame.pack();
        frame.setVisible(true);

    }

抽象模型的来源在这里: http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableRenderDemoProject/src/components/TableRenderDemo.java

只要发现问题:注释语句时 jcb.setEditable(true); ,如果我单击comboxcell,它会打开单元格。 但我不知道为什么效果更好。另外,我希望组合框可编辑。

我怎样才能对其他细胞有相同的行为。

你好,我已经更新了代码,以便拥有 - 如果我通过覆盖方法单击一次单元格,则单元格变为可编辑 - 如果我通过覆盖方法在单元格上单击一次,则组合框变为可编辑

我把我的新代码放在这里,它可能会帮助其他人:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;

public class JtabletestOK {

    public static void main(String[] args) {

        JtabletestOK test = new JtabletestOK();
        test.go();
    }

    public void go() {

        //create the frame
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



        //create a table and add it to a scroll pane in a new tab
        JTable jTable1 = new JTable()

        {
            //  Place cell in edit mode when it 'gains focus'

            public void changeSelection(
                    int row, int column, boolean toggle, boolean extend)
            {
                super.changeSelection(row, column, toggle, extend);

                if (column > 0)
                {

                    if (editCellAt(row, column))
                    {
                        Component editor = getEditorComponent();
                        editor.requestFocusInWindow();
                        // System.out.println("ffin focus gagne");
                        if (editor instanceof JTextField) {

                            JTextField jf = (JTextField) editor;
                            jf.select(0, jf.toString().length());
                        }}
                }
            }
        };



        jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
        jTable1.setFillsViewportHeight(true);
        replaceTabByEnter(jTable1);

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(jTable1);

        Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4"  };
        DefaultTableModel model = new DefaultTableModel(columnNames, 0);

        Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
        model.addRow(rowData);
        jTable1.setModel(model);


        String[] comboBoxArray = {"proem1","veitem2","atem3"};
        JComboBox jca = new JComboBox(comboBoxArray);
        jca.setSelectedItem("");
        JTextComponent editor = (JTextComponent) jca.getEditor().getEditorComponent();

        jca.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                JComponent ja = (JComponent) e.getSource();
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                JComponent ja = (JComponent) e.getSource();
                JTable jtb = (JTable) ja.getParent();
                jtb.changeSelection(0,1,false,false);
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
            }
        });



        editor.addMouseListener(new MouseListener() {

            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Not mouseClicked yet.");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("Not mousePressed yet.");
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                JComponent ja = (JComponent) e.getSource();
                JComponent jcbloc = (JComponent) ja.getParent();
                JComboBox jcb = (JComboBox) jcbloc;
                jcb.setPopupVisible(true);
                System.out.println("Not mouseReleased yet.");

            }

            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("Not mouseEntered yet.");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("Not mouseExited yet.");
            }
        });

        autocompletecombo jcb =new autocompletecombo(jca);
        TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
        jca.setEditable(true);
        comboboxEditor cbe = new comboboxEditor(jca);
        colCombo.setCellEditor(cbe);

        frame.getContentPane().add(scrollPane);
        frame.pack();
        frame.setVisible(true);

    }


    public void replaceTabByEnter(JTable  jtane) {

        KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
        KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
        InputMap im = jtane.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        im.put(enter, im.get(tab));
    }


    class comboboxEditor extends AbstractCellEditor implements TableCellEditor{

        JComboBox comboBox;
        JTextField jtf;

        S11InitialSelection sjcb;
        @Override
        public Object getCellEditorValue() {
            return comboBox.getSelectedItem();
        }

        public comboboxEditor(JComboBox jcb) {

            comboBox = jcb;
            jtf.selectAll();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {

            comboBox.setSelectedItem(value);
            return comboBox;
        }

        public boolean stopCellEditing() {


            fireEditingStopped();
            //     jt.EditNextCell();
            return true;

        }


    }










}
  • 当我单击组合框时,我想通过选择它来突出显示文本。 我不记得如何从 jcombobox 中获取文本字段以使用 selectAll() 方法或类似的方法。

我已经找到了解决方案:

            public void mouseReleased(MouseEvent e) {
                JComponent ja = (JComponent) e.getSource();
                JComponent jcbloc = (JComponent) ja.getParent();
                JComboBox jcb = (JComboBox) jcbloc;
                jcb.setPopupVisible(true);
                JTextComponent editor = (JTextComponent) jcb.getEditor().getEditorComponent();
                editor.setSelectionStart(0);
                editor.setSelectionEnd(editor.getText().length());
                System.out.println("Not mouseReleased yet.");

            }

感谢您的帮助。

【问题讨论】:

  • 我可以看看你的 AbstractTableModel 示例吗?

标签: java swing combobox jtable


【解决方案1】:

我终于找到了解决所有问题的方法。我发布所有代码。 我希望它会帮助别人。如果您找到解决问题的更好方法,我愿意。

它仍然是两个奇怪的东西,但它可以按我的意愿工作,所以如果有人作为一个想法:

  • 如果我移动代码

            if(e.getKeyChar() == KeyEvent.VK_ENTER){
                JComponent ja = (JComponent) e.getSource();
                JComboBox jcbloc = (JComboBox) ja.getParent();
                JTable jtb = (JTable) jcbloc.getParent();
                jtb.changeSelection(0,1,false,false);
            }
    

在keyReleased而不是keyPressed中,它不起作用。

  • 当我在基本单元格文本上按 Enter 键时,程序会单独转到下一个单元格。我不明白它是如何单独进入下一个单元格的。

这里的所有代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.basic.BasicTextUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;


public class JtabletestOKStackOver {

public static void main(String[] args) {

    JtabletestOKStackOver test = new JtabletestOKStackOver();
    test.go();
}

public void go() {

    //create the frame
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //create a table and add it to a scroll pane in a new tab
    JTable jTable1 = new JTable()

    {
        //  Place cell in edit mode when it 'gains focus'

        public void changeSelection(
                int row, int column, boolean toggle, boolean extend)
        {
            super.changeSelection(row, column, toggle, extend);


            if (column > -1)
            {

                if (editCellAt(row, column))
                {
                    Component editor = getEditorComponent();
                    editor.requestFocusInWindow();
                    if (editor instanceof JTextField) {

                        JTextField jf = (JTextField) editor;
                        jf.select(0, jf.toString().length());
                    }
                    if (editor instanceof JComboBox) {
                        JComboBox jcb = (JComboBox) editor;
                        jcb.setPopupVisible(true);
                        JTextComponent editorCombo = (JTextComponent) jcb.getEditor().getEditorComponent();
                        editorCombo.setSelectionStart(0);
                        editorCombo.setSelectionEnd(editorCombo.getText().length());
                    }



                }
            }
        }
    };





    jTable1.setPreferredScrollableViewportSize(new Dimension(800,100));
    jTable1.setFillsViewportHeight(true);
    jTable1.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

    //Create the scroll pane and add the table to it.
    JScrollPane scrollPane = new JScrollPane(jTable1);

    Object columnNames[] = { "DataCombo", "Data 2", "Data 3", "Data 4"  };
    DefaultTableModel model = new DefaultTableModel(columnNames, 0);

    Object rowData[] = { "", "Row1-Column2", "Row1-Column3", "Row1-Column3" };
    model.addRow(rowData);
    jTable1.setModel(model);


    String[] comboBoxArray = {"proem1","veitem2","atem3"};
    JComboBox jca = new JComboBox(comboBoxArray);
    jca.setSelectedItem("");
    JTextComponent editor = (JTextComponent) jca.getEditor().getEditorComponent();

    editor.addKeyListener(new KeyListener() {

        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if(e.getKeyChar() == KeyEvent.VK_ENTER){
                JComponent ja = (JComponent) e.getSource();
                JComboBox jcbloc = (JComboBox) ja.getParent();
                JTable jtb = (JTable) jcbloc.getParent();
                jtb.changeSelection(0,1,false,false);
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {

        }
    });


    editor.addFocusListener(new FocusListener() {

        @Override
        public void focusGained(FocusEvent e) {
            JComponent ja = (JComponent) e.getSource();
            JComponent jcbloc = (JComponent) ja.getParent();
            JComboBox jcb = (JComboBox) jcbloc;
            jcb.setPopupVisible(true);
            JTextComponent editor = (JTextComponent) jcb.getEditor().getEditorComponent();
            editor.setSelectionStart(0);
            editor.setSelectionEnd(editor.getText().length());
        }

        @Override
        public void focusLost(FocusEvent e) {
        }
    });





    TableColumn colCombo = jTable1.getColumnModel().getColumn(0);
    jca.setEditable(true);
    comboboxEditor cbe = new comboboxEditor(jca);
    colCombo.setCellEditor(cbe);


    TableColumn colAutre = jTable1.getColumnModel().getColumn(1);
    TableColumn colAutre2 = jTable1.getColumnModel().getColumn(2);
    TableColumn colAutre3 = jTable1.getColumnModel().getColumn(3);
    textCellEditor dce = new textCellEditor(new JTextField());

    colAutre.setCellEditor(dce);
    colAutre2.setCellEditor(dce);
    colAutre3.setCellEditor(dce);



    frame.getContentPane().add(scrollPane);
    frame.pack();
    frame.setVisible(true);

}







class comboboxEditor extends AbstractCellEditor implements TableCellEditor{

    JComboBox comboBox;



    public comboboxEditor(JComboBox jcb) {

        comboBox = jcb;
    }


    public Object getCellEditorValue() {
        return comboBox.getSelectedItem();
    }


    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {

        comboBox.setSelectedItem(value);
        return comboBox;
    }

    public boolean stopCellEditing() {
        fireEditingStopped();
        return true;

    }


}

class textCellEditor extends AbstractCellEditor implements TableCellEditor{
    JTextField jtextfield;

    public textCellEditor(JTextField jtf) {
        jtextfield = jtf;
    }


    public Object getCellEditorValue() {
        return jtextfield.getText();
    }


    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        if (isSelected) {
            // cell (and perhaps other cells) are selected
        }
        if (value== null)
        {
            value="";
        }
        value = value.toString();
        if (value instanceof Integer) {
            value = value.toString();
        }
        jtextfield.setText((String) value);

        // Return the configured component
        return jtextfield;
    }

    public boolean stopCellEditing() {
        fireEditingStopped();
        return true;

    }

}



}

感谢您的帮助。

【讨论】:

    【解决方案2】:

    不要在组合框上使用 ActionListener。单击单元格时,编辑器将显示“弹出窗口”。

    我的第一个问题是我不明白为什么教程中的代码在我们实现抽象表模型而不工作 DefaultTableModel 时工作。

    编辑由 TableModel 的isCellEditable(...) 方法控制。当您单击可编辑的单元格时,JTable 将使用适当的编辑器。如果编辑器是组合框,则单击单元格时会显示弹出窗口。

    只要发现问题:注释语句时 jcb.setEditable(true); ,如果我单击comboxcell,它会打开单元格。但我不知道为什么效果更好

    当您单击一个单元格时,我相信 MouseEvent 会转发给编辑器(即组合框)。由于组合框是可编辑的,因此 MouseEvent 转到文本字段,因此文本字段的焦点仍然存在并且不显示弹出窗口。用一个普通的组合框试试这个,不显示在 JTable 中,所以看到相同的行为。

    【讨论】:

    • 你想回答什么问题???对于 isCellEditable(),DefaultTableModel 总是返回 true
    • 我试图告诉 OP 你不需要做任何特别的事情来显示组合框下拉菜单。当单元格可编辑时,表格将选择适当的编辑器。进行了更新。
    • 你是对的。我对基本组合框有相同的行为。我已经删除了动作监听器,你知道如何打开组合下拉列表,即,我是否需要在文本字段上放置一个监听器以在组合中显示弹出窗口?
    • 我认为使用 ActionListener 并没有完全错误。但是您可能有一个更好的选择:FocusListener。当组合框成为焦点时打开弹出窗口(可能使用 invokeLater)。
    • @SergiyMedvynskyy I think it's not completly wrong to use the ActionListener - ActionListener 用于在组合框中选择项目时进行处理。它与显示弹出窗口无关。 possibly a better alternative: FocusListener. 是的,这是可能的。
    【解决方案3】:

    我不知道为什么您的带有 AbstractTableModel 的代码有效(因为我看不到它)。但我可以帮助您使您的示例发挥作用。

        jcb.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                System.out.println("test");
                final JComboBox j= (JComboBox)evt.getSource();
                SwingUtilities.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        if (j.isDisplayable()) j.setPopupVisible(true);
                    }
                });
    
            }});
    

    【讨论】:

    • 你的样本作品!你能解释一下 SwingUtilities.invokeLater 的区别吗?为什么不稍后调用它就不起作用?
    • 可能当组合框编辑器获得焦点时,弹出窗口会自动关闭。所以我们不需要立即打开它。 invokeLater 可以帮助做到这一点。但我不确定我的解释是否正确。
    • -1,不要使用 ActionListener 来显示组合框弹出窗口。这由编辑处理。
    • 不明白你的意思。我只是纠正了他的例子。
    • @SergiyMedvynskyy 另外,如您所见,我终于在编辑器组件上使用了一个简单的 mouslistener,我可以工作了!谢谢你的帮助。另外两点,我应该打开一个新问题吗?
    猜你喜欢
    • 1970-01-01
    • 2013-02-10
    • 2010-11-16
    • 2015-03-07
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 2011-09-27
    相关资源
    最近更新 更多