Checkbox in some cells but not all, in a particula

2020-03-28 02:27发布

This may be a vague query, so please pardon me.

Customized JTable (I've modified the query and will discuss based on the SSCCE provided). I've to create a JTable to provide authorization based on selected checkboxes in JTable

Purpose of this JTable is to show users with all of the menu options of the application. This JTable have three columns: First column: class Bollean (checkbox) Second column: class String (main menu items) Third column: class String (sub-menu items)

To provide authorization user shall select checkbox corresponding to sub-menu items and finally select "Authorize" button (I haven't included authorize button in this as my authorize functionality is working fine)

Now the UI requirement is that in the first column of JTable, I should display checkboxes corresponding to sub-menu items only instead of displaying checkbox in each cell of first column (in other words it should not display checkbox corresponding to main menu menu item)

Pic below is expected output (although I'm getting all cells in first column with checkbox)

Expected UI

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();
            }
        });
    }
}

I tried various things with cell renderer and googled about JTable and custom cells but couldn't figured it out. Any help will be greatly appreciated

3条回答
何必那么认真
2楼-- · 2020-03-28 02:46

Override the getCellRenderer() method to return an appropriate renderer. Something like:

@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);
}

You would also need to change the data in the model:

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

Finally you would also override the isCellEditable() method to make the empty cell non editable.

Then you can just use the default Boolean renderer/editor for the other rows in the column.

查看更多
对你真心纯属浪费
3楼-- · 2020-03-28 02:58

Basically, you're going to have supply you're cell renderer and editor.

In this case, I changed the first columns value/type to int. This allows me to supply additional meaning beyond boolean.

If the column value is 0 then the cell is not "selectable", 1 is unchecked, 2 is checked.

I also altered the isCellEditable method of the TableModel to only allow the "active" cells to be editable.

enter image description here

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();
            }
        });
    }
}

I've not done the editor, but the basic concept is the same...

查看更多
相关推荐>>
4楼-- · 2020-03-28 03:01

You can use the Boolean wrapper class instead of the raw type and write your own TableCellRenderer and override the getTableCellRendererComponent(..) method.

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;
    }
}

Then just simply set infos.setDefaultRenderer(Boolean.class, new CustomTableCellRenderer()); and replace your raw types in the array with new Boolean(true). Wherever you don't want to have a JCeckBox you put a null instead of a Boolean and an empty JPanel will appear.

查看更多
登录 后发表回答