0

我借助上一篇文章开发了一个带有表格的自动完成组合框,但是当添加到表格单元格并按下一个键时,它会显示以下错误。它在桌子外面工作得很好。

错误:

线程“AWT-EventQueue-0”java.awt.IllegalComponentStateException 中的异常:组件必须显示在屏幕上才能确定其在 java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:2044) at java.awt.Component.getLocationOnScreen 的位置(Component.java:2018) at javax.swing.JPopupMenu.show(JPopupMenu.java:939) at test.DetailedComboBox$TableComboPopup.show(DetailedComboBox.java:203) at javax.swing.plaf.basic.BasicComboBoxUI.setPopupVisible( BasicComboBoxUI.java:878) at javax.swing.JComboBox.setPopupVisible(JComboBox.java:818) at javax.swing.JComboBox.showPopup(JComboBox.java:803) at test.ComboKey​​Handler$1.run(DetailedComboBox.java:339)在 java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251) 在 java.awt.EventQueue.dispatchEventImpl(EventQueue.java:701) 在 java.awt.EventQueue.access$000(EventQueue.java:102) 在 java.awt.EventQueue$3.run(EventQueue.java:662) 在 java.awt.EventQueue$3.run(EventQueue.java:660)在 java.security.AccessController.doPrivileged(Native Method) 在 java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 在 java.awt.EventQueue.dispatchEvent(EventQueue.java:671) 在 java.awt.EventDispatchThread。 pumpOneEventForFilters(EventDispatchThread.java:244) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java :147) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139) 在 java.awt.EventDispatchThread。运行(EventDispatchThread.java:97)

这是我的代码:

//// 详细组合框

  package test;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

/**
 *
 * @author W.A.R.R.Wijesinghe
 */
public class DetailedComboBox extends JComboBox {

    public static enum Alignment {

        LEFT, RIGHT
    }
    private List<List<? extends Object>> tableData;
    private String[] columnNames;
    private int[] columnWidths;
    private int displayColumn;
    private Alignment popupAlignment = Alignment.LEFT;

    /**
     * Construct a TableComboBox object
     */
    public DetailedComboBox(String[] colNames, int[] colWidths, int displayColumnIndex) {
        super();
        this.columnNames = colNames;
        this.columnWidths = colWidths;
        this.displayColumn = displayColumnIndex;

        setUI(new TableComboBoxUI());
        setEditable(true);
        this.setSelectedIndex(-1);

    }

    /**
     * Set the type of alignment for the popup table
     */
    public void setPopupAlignment(Alignment alignment) {
        popupAlignment = alignment;
    }

    /**
     * Populate the combobox and drop-down table with the supplied data. If the
     * supplied List is non-null and non-empty, it is assumed that the data is a
     * List of Lists to be used for the drop-down table. The combobox is also
     * populated with the column data from the column defined by
     * <code>displayColumn</code>.
     */
    public void setTableData(List<List<? extends Object>> tableData) {
        this.tableData = (tableData == null
                ? new ArrayList<List<? extends Object>>() : tableData);

        // even though the incoming data is for the table, we must also
        // populate the combobox's data, so first clear the previous list.
        removeAllItems();

        // then load the combobox with data from the appropriate column
        Iterator<List<? extends Object>> iter = this.tableData.iterator();
        while (iter.hasNext()) {
            List<? extends Object> rowData = iter.next();
            addItem(rowData.get(displayColumn));
        }
    }

    public List<? extends Object> getSelectedRow() {
        return tableData.get(getSelectedIndex());
    }

    public List<? extends Object> getRowAt(int row) {
        return tableData.get(row);
    }

    /**
     * The handler for the combobox's components
     */
    private class TableComboBoxUI extends MetalComboBoxUI {

        /**
         * Create a popup component for the ComboBox
         */
        @Override
        protected ComboPopup createPopup() {
            return new TableComboPopup(comboBox, this);
        }

        /**
         * Return the JList component
         */
        public JList getList() {
            return listBox;
        }
    }

    /**
     * The drop-down of the combobox, which is a JTable instead of a JList.
     */
    private class TableComboPopup extends BasicComboPopup implements ListSelectionListener, ItemListener {

        private final JTable table;
        private TableComboBoxUI comboBoxUI;
        private PopupTableModel tableModel;
        private JScrollPane scroll;
//    private JList list = new JList();
//    private ListSelectionListener selectionListener;
//    private ItemListener itemListener;

        /**
         * Construct a popup component that's a table
         */
        public TableComboPopup(JComboBox combo, TableComboBoxUI ui) {
            super(combo);
            this.comboBoxUI = ui;

            tableModel = new PopupTableModel();
            table = new JTable(tableModel);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            table.getTableHeader().setReorderingAllowed(false);

            TableColumnModel tableColumnModel = table.getColumnModel();
            tableColumnModel.setColumnSelectionAllowed(false);

            for (int index = 0; index < table.getColumnCount(); index++) {
                TableColumn tableColumn = tableColumnModel.getColumn(index);
                tableColumn.setPreferredWidth(columnWidths[index]);
            }

            scroll = new JScrollPane(table);
            scroll.setHorizontalScrollBarPolicy(
                    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

            ListSelectionModel selectionModel = table.getSelectionModel();
            selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            selectionModel.addListSelectionListener(this);
            combo.addItemListener(this);

            table.addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent event) {
                    Point p = event.getPoint();
                    int row = table.rowAtPoint(p);

                    comboBox.setSelectedIndex(row);
                    hide();
                }
            });

            table.setBackground(UIManager.getColor("ComboBox.listBackground"));
            table.setForeground(UIManager.getColor("ComboBox.listForeground"));
        }

        /**
         * This method is overridden from BasicComboPopup
         */
        @Override
        public void show() {
            if (isEnabled()) {
                super.removeAll();

                int scrollWidth = 200;//table.getPreferredSize().width
                      //  + ((Integer) UIManager.get("ScrollBar.width")).intValue() + 1;
                int scrollHeight = 100;//comboBoxUI.getList().
                       // getPreferredScrollableViewportSize().height;
                scroll.setPreferredSize(new Dimension(scrollWidth, scrollHeight));

                super.add(scroll);

                ListSelectionModel selectionModel = table.getSelectionModel();
                selectionModel.removeListSelectionListener(this);
                selectRow();
                selectionModel.addListSelectionListener(this);

                int scrollX = 0;
                int scrollY = 25;//comboBox.getBounds().height;
/*
                if (popupAlignment == Alignment.RIGHT) {
                    scrollX = comboBox.getBounds().width - scrollWidth;
                }

* */
                show(comboBox, scrollX, scrollY);

            }
        }

        /**
         * Implemention of ListSelectionListener
         */
        @Override
        public void valueChanged(ListSelectionEvent event) {
            comboBox.setSelectedIndex(table.getSelectedRow());
        }

        /**
         * Implemention of ItemListener
         */
        @Override
        public void itemStateChanged(ItemEvent event) {
            if (event.getStateChange() != ItemEvent.DESELECTED) {
                ListSelectionModel selectionModel = table.getSelectionModel();
                selectionModel.removeListSelectionListener(this);
                selectRow();
                selectionModel.addListSelectionListener(this);
            }
        }

        /**
         * Sync the selected row of the table with the selected row of the
         * combo.
         */
        private void selectRow() {
            int index = comboBox.getSelectedIndex();

            if (index != -1) {
                table.setRowSelectionInterval(index, index);
                table.scrollRectToVisible(table.getCellRect(index, 0, true));
            }
        }
    }

    /**
     * A model for the popup table's data
     */
    private class PopupTableModel extends AbstractTableModel {

        /**
         * Return the # of columns in the drop-down table
         */
        @Override
        public int getColumnCount() {
            return columnNames.length;
        }

        /**
         * Return the # of rows in the drop-down table
         */
        @Override
        public int getRowCount() {
            return tableData == null ? 0 : tableData.size();
        }

        /**
         * Determine the value for a given cell
         */
        @Override
        public Object getValueAt(int row, int col) {
            if (tableData == null || tableData.isEmpty()) {
                return "";
            }

            return tableData.get(row).get(col);
        }

        /**
         * All cells in the drop-down table are uneditable
         */
        @Override
        public boolean isCellEditable(int row, int col) {
            return false;
        }

        /**
         * Pull the column names out of the tableInfo object for the header
         */
        @Override
        public String getColumnName(int column) {
            String columnName = null;

            if (column >= 0 && column < columnNames.length) {
                columnName = columnNames[column].toString();
            }

            return (columnName == null) ? super.getColumnName(column) : columnName;
        }
    }
}

class ComboKeyHandler extends KeyAdapter {

    private final DetailedComboBox comboBox;
    //  private final Vector<String> list = new Vector<String>();
    private final List<List<?>> list = new ArrayList<>();

    public ComboKeyHandler(DetailedComboBox combo) {

        this.comboBox = combo;

        for (int i = 0; i < comboBox.getItemCount(); i++) {

            List<? extends Object> rowData = combo.getRowAt(i);
            // name.setText(rowData.get(1).toString());
            //  capital.setText(rowData.get(2).toString());
            list.add(rowData);
            System.out.println("List Create: " + list);
            // list.addElement((String) comboBox.getItemAt(i));
        }
    }
    private boolean shouldHide = false;

    @Override
    public void keyTyped(final KeyEvent e) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                String text = ((JTextField) e.getSource()).getText();
                System.out.println(text);
                if (text.length() == 0) {
                    setSuggestionModel(comboBox, list, "");
                    comboBox.hidePopup();
                } else {
                    List<List<?>> m = getSuggestedModel(list, text);
                    if (m.isEmpty() || shouldHide) {
                        comboBox.hidePopup();
                    } else {
                        setSuggestionModel(comboBox, m, text);
                        comboBox.showPopup();
                    }
                }
            }
        });
    }

    @Override
    public void keyPressed(KeyEvent e) {
        JTextField textField = (JTextField) e.getSource();
        String text = textField.getText();
        shouldHide = false;
        switch (e.getKeyCode()) {
            case KeyEvent.VK_RIGHT:


                    if (!list.isEmpty()) {

                    }


                break;
            case KeyEvent.VK_ENTER:
                if (list.isEmpty()) {
                    //list.add(new ArrayList<>(Arrays.asList(text, "a", "a")));
                    //  setSuggestionModel(comboBox, getSuggestedModel(list, text), text);
                }
                shouldHide = true;
                break;
            case KeyEvent.VK_ESCAPE:
                shouldHide = true;
                break;
            default:
                break;
        }
    }

    private static void setSuggestionModel(DetailedComboBox comboBox, List<List<?>> newList, String str) {
        comboBox.setTableData(newList);
        comboBox.setSelectedIndex(-1);
        ((JTextField) comboBox.getEditor().getEditorComponent()).setText(str);
    }

    private static List<List<?>> getSuggestedModel(List<List<?>> list, String text) {

        List<List<?>> BacktableData = new ArrayList<>();
        System.out.println("List before: " + list);

        for (int i = 0; i < list.size(); i++) {
            List<List<?>> Innerlist = new ArrayList<>();
            Innerlist = (List<List<?>>) list.get(i);

            String[] toArray = Innerlist.toArray(new String[Innerlist.size()]);
            List<String> Stringlist = new ArrayList<>(Arrays.asList(toArray));
            System.out.println("String List ::::::: " + Stringlist);
            boolean isSearch = false;
            for (Iterator<String> it = Stringlist.iterator(); it.hasNext();) {
                isSearch = false;

                if (it.next().contains(text)) {
                    //it.remove(); // NOTE: Iterator's remove method, not ArrayList's, is used.
                    isSearch = true;
                    if (isSearch) {
                        break;
                    }
                }

            }

            if (isSearch) {
                BacktableData.add(new ArrayList<>(Innerlist));

            }
            System.out.println("BackList : " + BacktableData);
        }
        System.out.println("Filter Text: " + text);
        System.out.println("List After: " + list);
        return BacktableData;

        /*
         * for (String s : list) { if (s.startsWith(text)) { m.addElement(s); }
         * } return m;
         *
         */
    }
}

//////TestTbl

package test;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultCellEditor;
import javax.swing.JTextField;
import javax.swing.table.TableColumn;


public class TestTbl extends javax.swing.JFrame {

    JTextField field;
    private DetailedComboBox combo;

    public TestTbl() {
        initComponents();
        List<List<?>> tableData = new ArrayList<>();
        tableData.add(new ArrayList<>(Arrays.asList("MD", "Maryland", "Annapolis")));

        tableData.add(new ArrayList<>(
                Arrays.asList("NH", "New Hampshire", "Concord")));
        tableData.add(new ArrayList<>(
                Arrays.asList("NJ", "New Jersey", "Trenton")));
        tableData.add(new ArrayList<>(
                Arrays.asList("NM", "New Mexico", "Santa Fe")));
        tableData.add(new ArrayList<>(
                Arrays.asList("ND", "North Dakota", "Bismark")));

        String[] columns = new String[]{"State", "Name", "Capital"};
        int[] widths = new int[]{50, 100, 100};

        combo = new DetailedComboBox(columns, widths, 0);
        System.out.println(tableData);
        combo.setTableData(tableData);
        combo.setSelectedIndex(0);
        combo.setPopupAlignment(DetailedComboBox.Alignment.LEFT);
        field = (JTextField) combo.getEditor().getEditorComponent();
        field.setText("");
        field.addKeyListener(new ComboKeyHandler(combo));

        combo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (field.getText().trim().length() != 0) {
                    showDetails();
                }
            }
        });

        name = new JTextField(10);
        capital = new JTextField(10);
        name.setEditable(true);
        capital.setEditable(false);


        TableColumn Item = jTable1.getColumnModel().getColumn(0);
        Item.setCellEditor(new DefaultCellEditor(combo));
    }

    private void showDetails() {
        List<? extends Object> rowData = combo.getSelectedRow();
        name.setText(rowData.get(1).toString());
        capital.setText(rowData.get(2).toString());
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        name = new javax.swing.JTextField();
        capital = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        jTable1.setRowHeight(25);
        jScrollPane1.setViewportView(jTable1);

        name.setText("jTextField1");

        capital.setText("jTextField2");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap(82, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 375, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(68, 68, 68))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(name, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(34, 34, 34)
                        .addComponent(capital, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(110, 110, 110))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(28, 28, 28)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(name, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(capital, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 45, Short.MAX_VALUE)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(21, 21, 21))
        );

        pack();
    }// </editor-fold>

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(TestTbl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(TestTbl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(TestTbl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(TestTbl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestTbl().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JTextField capital;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    private javax.swing.JTextField name;
    // End of variables declaration
}
4

1 回答 1

3

不要重新发明轮子,没有问题

  1. SwingX 中的自动完成装饰器

  2. 自动完成 JComboBox / JTextField

for JTable( JTable/ JXTableby using SwingX) as TableCellEditor

于 2013-02-25T08:49:54.997 回答