Java JComboBox和JTable作为ListCellRenderer组件

Java JComboBox和JTable作为ListCellRenderer组件,java,swing,jtable,jcombobox,tablecelleditor,Java,Swing,Jtable,Jcombobox,Tablecelleditor,我目前正在开发一个JComboBox组件,我希望在一个组合框中有一个JTable用于下拉选择。我已经扩展了ListCellRenderer,并且在弹出窗口中有了表 我想用两种不同的方式来表达它。当弹出窗口不可见时,作为选定行绑定列标签的第一个窗口。第二种方法是在弹出窗口可见时使用JScrollPane显示表 不幸的是,当我这样做时,弹出窗口被缩小到列表的行高,这只为表中的列留出了空间 如果我只是使用滚动窗格,我可以看到完整的表格,但当弹出窗口不可见时,我会看到组合框中的表格,这不是我想要的 如何

我目前正在开发一个JComboBox组件,我希望在一个组合框中有一个JTable用于下拉选择。我已经扩展了ListCellRenderer,并且在弹出窗口中有了表

我想用两种不同的方式来表达它。当弹出窗口不可见时,作为选定行绑定列标签的第一个窗口。第二种方法是在弹出窗口可见时使用JScrollPane显示表

不幸的是,当我这样做时,弹出窗口被缩小到列表的行高,这只为表中的列留出了空间

如果我只是使用滚动窗格,我可以看到完整的表格,但当弹出窗口不可见时,我会看到组合框中的表格,这不是我想要的

如何设置高度,以便在弹出窗口不可见时仍能显示标签的情况下,表格可以容纳

下面是一个编译和运行的简单示例:

import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

public class TableComboBoxMain {
    public static void main(String[] args) {
        JTableComboBox<Employee> combo = new JTableComboBox<>();
        combo.addItem(new Employee("April",3));
        //combo.setMaximumRowCount(10);
        combo.setRenderer(new TableListCellRenderer(combo));
        JFrame frame = new JFrame("Test Table Combo Box");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(combo);
        frame.pack();
        frame.setVisible(true);
    }

    public static class Employee{
        String name;
        int nr;
        public Employee(String name, int number ){
            this.name =name;
            this.nr = number;
        }
    }

    public static class JTableComboBox<E> extends JComboBox<E> implements ListSelectionListener{
        @Override
        public void valueChanged(ListSelectionEvent e) {System.out.println("Row selected"+e.getFirstIndex());
            this.setSelectedIndex(e.getFirstIndex());
        }
    }

    public static class TableListCellRenderer extends JScrollPane implements ListCellRenderer{
    JTable table;
    JTableComboBox combo;
    boolean mouseListenerAdded;
    public TableListCellRenderer(JTableComboBox combo){
        this.combo=combo;
        DefaultTableModel model = new DefaultTableModel();
        String[] cols1 = new String[]{"1","2","3","4"};
        String[] cols2 = new String[]{"Mark","John","April","Mary"};
        model.addColumn("Nr", cols1);model.addColumn("Name",cols2);
        table = new JTable(model);table.setShowGrid(true);table.setGridColor(Color.gray);
        this.getViewport().add(table);
    }
    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        if(!mouseListenerAdded){
            list.addMouseListener(this.getListener());
            mouseListenerAdded = true;
        }//If this is uncommented then the BasicComboPopup size is always no more than 1 row?!!
        if(!combo.isPopupVisible()){
            Employee emp = (Employee) value;
            return new JLabel(emp.name);

        }else
           return this;
    }

    public MouseAdapter getListener(){
        MouseAdapter adapter = new MouseAdapter(){
        @Override
        public void mousePressed(MouseEvent e) {
                if(combo.isPopupVisible()){
                    System.out.println("MouseClicked over list");
                    int row = table.rowAtPoint(e.getPoint());
                    if(row>0){
                        table.setRowSelectionInterval(row-1, row-1);
                        ListDataEvent event = new ListDataEvent(combo,ListDataEvent.CONTENTS_CHANGED,row-1,row-1);
                        combo.contentsChanged(event);
                    }
                }
            }
        };
        return adapter;
    }
}
}
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入javax.swing.JComboBox;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JList;
导入javax.swing.JScrollPane;
导入javax.swing.JTable;
导入javax.swing.ListCellRenderer;
导入javax.swing.event.ListDataEvent;
导入javax.swing.event.ListSelectionEvent;
导入javax.swing.event.ListSelectionListener;
导入javax.swing.table.DefaultTableModel;
公共类TableComboxMain{
公共静态void main(字符串[]args){
JTableComboBox combo=新的JTableComboBox();
合并附件(新员工(“4月3日”);
//combo.setMaximumRowCount(10);
setRenderer(新的TableListCellRenderer(combo));
JFrame frame=新JFrame(“测试表组合框”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(组合);
frame.pack();
frame.setVisible(true);
}
公共静态类雇员{
字符串名;
国际天然气公司;
公共雇员(字符串名称、整数编号){
this.name=名称;
这.nr=数量;
}
}
公共静态类JTableComboBox扩展了JComboBox,实现了ListSelectionListener{
@凌驾
public void valueChanged(ListSelectionEvent e){System.out.println(“选定行”+e.getFirstIndex());
这个.setSelectedIndex(e.getFirstIndex());
}
}
公共静态类TableListCellRenderer扩展JScrollPane实现ListCellRenderer{
JTable表;
JTableComboBox组合;
添加布尔鼠标;
公共TableListCellRenderer(JTableComboBox组合){
this.combo=combo;
DefaultTableModel=新的DefaultTableModel();
字符串[]cols1=新字符串[]{“1”、“2”、“3”、“4”};
字符串[]cols2=新字符串[]{“马克”、“约翰”、“四月”、“玛丽”};
model.addColumn(“Nr”,cols1);model.addColumn(“Name”,cols2);
table=新JTable(模型);table.setShowGrid(真);table.setGridColor(Color.gray);
this.getViewport().add(表);
}
@凌驾
公共组件getListCellRenderComponent(JList列表、对象值、int索引、布尔isSelected、布尔cellHasFocus){
如果(!已添加鼠标){
list.addMouseListener(this.getListener());
mouseListenerAdded=真;
}//如果未注释,则BasicComboPopup大小始终不超过1行?!!
如果(!combo.isPopupVisible()){
员工emp=(员工)价值;
返回新的JLabel(emp.name);
}否则
归还这个;
}
公共MouseAdapter getListener(){
MouseAdapter适配器=新的MouseAdapter(){
@凌驾
公共无效鼠标按下(MouseEvent e){
if(combo.isPopupVisible()){
System.out.println(“鼠标点击列表”);
int row=table.rowAtPoint(如getPoint());
如果(行>0){
表.setRowSelectionInterval(第1行,第1行);
ListDataEvent事件=新建ListDataEvent(组合,ListDataEvent.CONTENTS\u已更改,第1行,第1行);
组合。内容更改(事件);
}
}
}
};
返回适配器;
}
}
}

所以我找到了解决问题的方法。我还没有完成,因为我还想进行一些互动:

  • 我希望能够移动列
  • 我想能够为列弹出菜单
  • 我希望能够用鼠标垂直滚动
  • 我想发布解决方案,以防其他人想要一个起点示例。我将在解决这些附加问题时更新我的答案

    以下是测试等级:

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.DefaultListCellRenderer;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.ScrollPaneConstants;
    import javax.swing.event.ListDataEvent;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    import javax.swing.plaf.basic.BasicComboBoxUI;
    import javax.swing.plaf.basic.BasicComboPopup;
    import javax.swing.plaf.basic.ComboPopup;
    import javax.swing.table.DefaultTableModel;
    
    public class TableComboBoxMain {
        public static void main(String[] args) {
            JTableComboBox<String> combo = new JTableComboBox<>();
            combo.addItem("");
            BasicComboBoxUI ui = new BasicComboBoxUI(){
                @Override
                protected ComboPopup createPopup() {
                    return new BasicComboPopup( comboBox ){
                        @Override
                        protected int getPopupHeightForRowCount(int maxRowCount) {
                            return 100;
                        }
                        @Override
                        protected JScrollPane createScroller() {
                            JScrollPane sp = new JScrollPane( list,
                                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED );
                            sp.getHorizontalScrollBar().setFocusable( false );
                            return sp;
                        }
                    };
                }
            };
            combo.setUI(ui);
            combo.setRenderer(new TableListCellRenderer(combo));
            JFrame frame = new JFrame("Test Table Combo Box");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(combo);
            frame.pack();
            frame.setVisible(true);
        }
    
        public static class Employee{
            String name;
            int nr;
            public Employee(String name, int number ){
                this.name =name;
                this.nr = number;
            }
        }
    
        public static class JTableComboBox<E> extends JComboBox<E> implements ListSelectionListener{
            @Override
            public void valueChanged(ListSelectionEvent e) {
                System.out.println("Row selected"+e.getFirstIndex());
                this.setSelectedIndex(e.getFirstIndex());
            }
        }
    
        public static class TableListCellRenderer extends DefaultListCellRenderer{
            JTable table;
            JTableComboBox combo;
            JPanel renderer = new JPanel();
            JPanel colHeader = new JPanel();
            JScrollPane scroll = new JScrollPane();
            boolean mouseListenerAdded;
            public TableListCellRenderer(JTableComboBox combo){
                this.combo=combo;
                DefaultTableModel model = new DefaultTableModel();
                String[] cols1 = new String[]{"1","2","3","4","5","6"};
                String[] cols2 = new String[]{"Mark","John","April","Mary","Joe","Jack"};
                model.addColumn("Nr", cols1);model.addColumn("Name",cols2);
                table = new JTable(model);
                table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
                colHeader.add(table.getTableHeader());
                renderer.setLayout(new BorderLayout());
                renderer.add(colHeader, BorderLayout.NORTH);
                renderer.add(table,BorderLayout.CENTER);
                scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
                scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
                scroll.getViewport().add(table);
    
            }
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                list.setFixedCellHeight(table.getRowHeight()*(table.getRowCount()+1)+10);
                list.setFixedCellWidth(table.getPreferredSize().width);
                JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                if(!mouseListenerAdded){
                    list.addMouseListener(this.getListener());
                    mouseListenerAdded = true;
                }
                if(!combo.isPopupVisible()){
                    label.setText("Select...");
                    if(table.getSelectedRowCount()>0)
                        label.setText(""+table.getModel().getValueAt(table.getSelectedRow(),1));
                    return label;
                }
                   return scroll;
            }
    
            public MouseAdapter getListener(){
                MouseAdapter adapter = new MouseAdapter(){
                @Override
                public void mousePressed(MouseEvent e) {
                        if(combo.isPopupVisible()){
                            System.out.println("MouseClicked over list");
                            int row = table.rowAtPoint(e.getPoint());
                            if(row>0){
                                table.setRowSelectionInterval(row-1, row-1);
                                ListDataEvent event = new ListDataEvent(combo,ListDataEvent.CONTENTS_CHANGED,row-1,row-1);
                                combo.contentsChanged(event);
                            }
                        }
                    }
                };
                return adapter;
            }
        }
    }
    
    导入java.awt.BorderLayout;
    导入java.awt.Component;
    导入java.awt.event.MouseAdapter;
    导入java.awt.event.MouseEvent;
    导入javax.swing.DefaultListCellRenderer;
    导入javax.swing.JComboBox;
    导入javax.swing.JFrame;
    导入javax.swing.JLabel;
    导入javax.swing.JList;
    导入javax.swing.JPanel;
    导入javax.swing.JScrollPane;
    导入javax.swing.JTable;
    导入javax.swing.ScrollPaneConstants;
    导入javax.swing.event.ListDataEvent;
    导入javax.swing.event.ListSelectionEvent;
    导入javax.swing.event.ListSelectionListener;
    导入javax.swing.plaf.basic.BasicComboxUI;
    导入javax.swing.plaf.basic.basicmbopopup;
    导入javax.swing.plaf.basic.ComboPopup;
    导入javax.swing.table.DefaultTableModel;
    公共类TableComboxMain{
    公共静态void main(字符串[]args){
    JTableComboBox combo=新的JTableComboBox();
    组合添加项(“”);
    BasicComboxUI=新的BasicComboxUI(){
    @凌驾
    受保护的ComboPopup createPopup(){
    返回新的BasicComboPopup(组合框){
    @凌驾
    受保护的int GetPopucRightForRowCount(int maxRowCount){