2

这可能是一个模糊的查询,所以请原谅我。

定制的 JTable(我已经修改了查询,将根据提供的 SSCCE 进行讨论)。我必须创建一个 JTable 以根据 JTable 中选定的复选框提供授权

此 JTable 的目的是向用户展示应用程序的所有菜单选项。这个 JTable 有三列: 第一列:Bollean 类(复选框) 第二列:String 类(主菜单项) 第三列:String 类(子菜单项)

要提供授权,用户应选择与子菜单项对应的复选框,最后选择“授权”按钮(我没有在其中包含授权按钮,因为我的授权功能工作正常)

现在的 UI 要求是在 JTable 的第一列中,我应该只显示与子菜单项对应的复选框,而不是在第一列的每个单元格中显示复选框(换句话说,它不应该显示与主菜单菜单项对应的复选框)

下面的图片是预期的输出(尽管我在第一列中使用复选框获取所有单元格)

预期的用户界面

public class SwingSolution extends JPanel {

    public SwingSolution() {
        super(new GridLayout(1,0));

        String[] columnNames = {"", "Main Menu", "Sub Menu"};

        Object[][] data = {
        {false, "File", ""},
        {false, "", "New"},
        {false, "", "Save"},
        {false, "", "Close"},
        {false, "Edit", ""},
        {false, "", "Delete"},
        {false, "", "Format"},
        {false, "Project", ""},
        {false, "", "Create New"},
        {false, "", "Delete"},
        {false, "", "Build"},
        {false, "", "Properties"},
        };

        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        final JTable table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public Class getColumnClass(int column) {
                switch (column) {
                    case 0:
                        return Boolean.class;
                    case 1:
                        return String.class;
                    case 2:
                        return String.class;
                    default:
                        return Boolean.class;
                }
            }
        };

        table.getColumnModel().getColumn(0).setMaxWidth(30);
        table.getColumnModel().getColumn(1).setMaxWidth(100);
        table.getColumnModel().getColumn(2).setMaxWidth(120);

        table.setPreferredScrollableViewportSize(new Dimension(250, 195));
        table.setFillsViewportHeight(true);

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

        //Add the scroll pane to this panel.
        add(scrollPane);
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        SwingSolution newContentPane = new SwingSolution();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

我用单元格渲染器尝试了各种事情,并在谷歌上搜索了 JTable 和自定义单元格,但无法弄清楚。任何帮助将不胜感激

4

3 回答 3

5

基本上,您将拥有单元格渲染器和编辑器。

在这种情况下,我将第一列 value/type 更改为int. 这使我能够提供超出boolean.

如果列值是0,则单元格不是“可选择的”,1未选中,2已选中。

我还更改了 的isCellEditable方法,TableModel只允许“活动”单元格可编辑。

在此处输入图像描述

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class LimitedTableCellEditor extends JPanel {

    public LimitedTableCellEditor() {
        super(new GridLayout(1, 0));

        String[] columnNames = {"", "Main Menu", "Sub Menu",};

        Object[][] data = {
            {0, "File", ""},
            {1, "", "New"},
            {1, "", "Save"},
            {1, "", "Close"},
            {0, "Edit", ""},
            {1, "", "Delete"},
            {1, "", "Format"},
            {0, "Project", ""},
            {1, "", "Create New"},
            {1, "", "Delete"},
            {1, "", "Build"},
            {1, "", "Properties"},};

        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        final JTable table = new JTable(model) {
            private static final long serialVersionUID = 1L;

            @Override
            public Class getColumnClass(int column) {
                switch (column) {
                    case 0:
                        return Integer.class;
                    case 1:
                        return String.class;
                    case 2:
                        return String.class;
                    default:
                        return Boolean.class;
                }
            }

            @Override
            public boolean isCellEditable(int row, int column) {
                boolean editable = false;
                if (column == 0) {
                    Object value = getValueAt(row, column);
                    if (value instanceof Integer) {
                        editable = ((int)value) != 0;
                    }
                }
                return editable;
            }
        };

        table.getColumnModel().getColumn(0).setMaxWidth(30);
        table.getColumnModel().getColumn(0).setCellRenderer(new ConditionalCheckBoxRenderer());
        table.getColumnModel().getColumn(1).setMaxWidth(100);
        table.getColumnModel().getColumn(2).setMaxWidth(120);

        table.setPreferredScrollableViewportSize(new Dimension(250, 195));
        table.setFillsViewportHeight(true);

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

        //Add the scroll pane to this panel.
        add(scrollPane);
    }

    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        LimitedTableCellEditor newContentPane = new LimitedTableCellEditor();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static class ConditionalCheckBoxRenderer extends JPanel implements TableCellRenderer {

        private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
        private JCheckBox cb;

        public ConditionalCheckBoxRenderer() {
            setLayout(new GridBagLayout());
            setOpaque(false);
            cb = new JCheckBox();
            cb.setOpaque(false);
            cb.setContentAreaFilled(false);
            cb.setMargin(new Insets(0, 0, 0, 0));
            add(cb);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setOpaque(isSelected);
            if (isSelected) {
                setForeground(table.getSelectionForeground());
                setBackground(table.getSelectionBackground());
            } else {
                setForeground(table.getForeground());
            }
            if (value instanceof Integer) {
                int state = (int) value;
                cb.setVisible(state != 0);
                cb.setSelected(state == 2);
            }
            if (hasFocus) {
                setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
            } else {
                setBorder(NO_FOCUS_BORDER);
            }
            return this;
        }
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

编辑器我没做过,但基本概念是一样的……

于 2013-05-09T02:19:40.120 回答
2

覆盖该getCellRenderer()方法以返回适当的渲染器。就像是:

@Override
public TableCellRenderer getCellRenderer(int row, int column)
{
    int modelColumn = convertColumnIndexToView(column);

    if (modelColumn == 0 && getValueAt(row, column).equals(""))
        return getDefaultRenderer(String.class);
    else
        return super.getCellRenderer(row, column);
}

您还需要更改模型中的数据:

{"", "File", ""},

最后,您还将覆盖该isCellEditable()方法以使空单元格不可编辑。

然后,您可以对列中的其他行使用默认的布尔渲染器/编辑器。

于 2013-05-09T02:45:15.943 回答
2

您可以使用Boolean包装类而不是原始类型并编写自己的TableCellRenderer并覆盖该getTableCellRendererComponent(..)方法。

public class CustomTableCellRenderer extends DefaultTableCellRenderer
{
    public CustomTableCellRenderer()
    {
        super();
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, 
            boolean isSelected, boolean hasFocus, int row, int column)
    {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        if(value instanceof Boolean)
        {
            if(value != null)
            {
                 JCheckBox jcb = new JCheckBox();
                 jcb.setSelected((Boolean) value);

                 return jcb;
            }
            return new JPanel();
        }
    return this;
    }
}

然后只需简单地将infos.setDefaultRenderer(Boolean.class, new CustomTableCellRenderer());数组中的原始类型设置并替换为new Boolean(true). 无论你不想在哪里放 a ,JCeckBox你都放 anull而不是 a ,就会出现Boolean一个空的。JPanel

于 2013-05-09T02:47:39.503 回答