繁体   English   中英

可扩展 JTable 单元格编辑器

[英]Expandable JTable Cell Editor

我有一行数据,我可以在其中对远程服务器进行操作。

我在JTable中显示这些数据,因为它避免了为每一行创建一个组件的成本,而且有很多。

在此处输入图像描述

我已经设法显示组件并能够与单元格交互,(但我仍然是第一次点击)。

在此处输入图像描述

但我正在苦苦挣扎的是我希望我的编辑器组件是可扩展的,当然还要更新当前行高。 当然,在折叠时恢复到正常的行高。 我想我需要向单元格编辑器注册一些听众,但我目前无法正确地做到这一点。

  • ComponentListner::componentResized使整个表不断重绘。
  • editorComponent.addPropertyChangeListener("preferredSize", propertyChangeListener) ,并不总是重新绘制表格
  • editorComponent.addPropertyChangeListener("preferredSize", propertyChangeListener) ,并不总是重新绘制表格

因此这个问题。

在此处输入图像描述 在此处输入图像描述

有点超出 scope,我目前正在争论组件是否应该在转到另一个单元格时保持扩展(但这可以是模型的一部分的expanded属性)。

这是一个最小的示例,我没有尝试在编辑器组件(在getTableCellEditorComponent中)上注册侦听器。

在此先感谢您的指点。

package io.github.bric3.fireplace.ui;

import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;

public class DynamicCellRow {
    @NotNull
    private static JTable makeTable() {
        var jTable = new JTable(
                new Object[][]{
                        {"a", "charly"},
                        {"b", "tango"}
                },
                new Object[]{"id", "control"}
        );
        {
            var richColumn = jTable.getColumnModel().getColumn(1);
            richColumn.setCellRenderer(new TableCellRenderer() {
                private final ExpandablePanel expandablePanelRenderComponent = new ExpandablePanel();
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                    expandablePanelRenderComponent.setValue(value);
                    return updatePreferredRowHeight(table, expandablePanelRenderComponent, row, column);
                }
            });

            richColumn.setCellEditor(new DynamicCellEditor());
        }
        return jTable;
    }

    public static <T extends JComponent> T updatePreferredRowHeight(JTable table, T cellComponent, int row, int column) {
        // Adjust cell height per component
        int originalPreferredHeight = cellComponent.getPreferredSize().height;
        cellComponent.setSize(
                table.getColumnModel().getColumn(column).getWidth(),
                originalPreferredHeight
        );
        int newPreferredHeight = cellComponent.getPreferredSize().height;
        if (table.getRowHeight(row) < newPreferredHeight) {
            table.setRowHeight(row, newPreferredHeight);
        }
        return cellComponent;
    }

    static class ExpandablePanel extends JPanel {

        private final JLabel comp;

        ExpandablePanel() {
            setBorder(BorderFactory.createLineBorder(Color.black));
            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            // horizontal left-to-right layout
            gbc.gridx = 0;
            gbc.gridy = 0;

            // resizing behavior
            gbc.weightx = 1;
            gbc.weighty = 1;

            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.fill = GridBagConstraints.BOTH;

            JPanel advanced = new JPanel();
            {
                advanced.setLayout(new BoxLayout(advanced, BoxLayout.Y_AXIS));
                advanced.setBorder(new TitledBorder("Advance Settings"));
                advanced.add(new JCheckBox("Live"));
                advanced.add(new JCheckBox("Condition"));
                advanced.add(new JCheckBox("Disable"));
            }
            advanced.setVisible(false);

            var standard = new JPanel();
            {
                standard.setLayout(new BoxLayout(standard, BoxLayout.X_AXIS));
                comp = new JLabel("Label 1");
                standard.add(comp);
                standard.add(new JButton("Button 1"));
                var expandButton = new JButton("+");
                expandButton.addActionListener(e -> {
                    if (advanced.isVisible()) {
                        advanced.setVisible(false);
                        expandButton.setText("+");
                    } else {
                        advanced.setVisible(true);
                        expandButton.setText("-");
                    }
                });
                standard.add(expandButton);
            }
            add(standard, gbc);


            gbc.gridy++;
            gbc.weighty = 0;
            add(advanced, gbc);
        }

        public void setValue(Object value) {
            comp.setText(value.toString());
        }
    }

    private static class DynamicCellEditor extends AbstractCellEditor implements TableCellEditor {
        Object value;
        @Override
        public Object getCellEditorValue() {
            return value; // not changing
        }

        private final ExpandablePanel expandablePanel = new ExpandablePanel();

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            this.value = value;
            expandablePanel.setValue(value);
            return updatePreferredRowHeight(table, expandablePanel, row, column);
        }
    }


    public static void main(String[] args) {

        var contentPane = new JPanel(new BorderLayout());
        contentPane.add(new JScrollPane(makeTable()));

        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("DynamicCellRow");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(contentPane);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

@kleopatra 谢谢。 你的提示让我走上了正确的轨道。 我编写了以下代码来在布局操作期间预先计算行高。

当一个单元格被编辑时,编辑器被添加到表中,然后重新验证,并相应地计算高度。

我之前有一个问题,因为在渲染器中设置高度实际上阻止了单元格组件的正确显示。

在下面的代码中,请注意doLayout如何根据单元格组件的首选大小(无论是渲染还是编辑单元格)调整行高。

请注意,我选择在编辑停止后折叠组件,因此DynamicExpndablePanelCellEditor中的侦听器。

import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;

public class DynamicCellRow {
    public static void main(String[] args) {

        var contentPane = new JPanel(new BorderLayout());
        contentPane.add(new JScrollPane(makeTable()));

        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("DynamicCellRow");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(contentPane);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }

    @NotNull
    private static JTable makeTable() {
        var jTable = new JTable(
                new Object[][]{
                        {"a", "charly"},
                        {"b", "tango"}
                },
                new Object[]{"id", "control"}
        ) {
            @Override
            public void doLayout() {
                super.doLayout();
                adjustRowHeights();
            }

            private void adjustRowHeights() {
                for (int row = 0; row < getRowCount(); row++) {
                    int rowHeight = getRowHeight();

                    for (int column = 0; column < getColumnCount(); column++) {
                        var editorComponent = getEditorComponent();
                        if (getEditingRow() == row && getEditingColumn() == column && editorComponent != null) {
                            editorComponent.setSize(getColumnModel().getColumn(column).getWidth(), 0);
                            rowHeight = Math.max(rowHeight, editorComponent.getPreferredSize().height);
                        } else {
                            var comp = prepareRenderer(getCellRenderer(row, column), row, column);
                            rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
                        }
                    }

                    setRowHeight(row, rowHeight);
                }
            }
        };
        {
            var richColumn = jTable.getColumnModel().getColumn(1);
            richColumn.setCellRenderer(new ExpandablePanelCellRenderer());
            richColumn.setCellEditor(new DynamicExpndablePanelCellEditor());
        }
        return jTable;
    }


    static class ExpandablePanel extends JPanel {

        private final JLabel comp;
        private final JPanel advanced;

        ExpandablePanel() {
            setBorder(BorderFactory.createLineBorder(Color.black));
            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            // horizontal left-to-right layout
            gbc.gridx = 0;
            gbc.gridy = 0;

            // resizing behavior
            gbc.weightx = 1;
            gbc.weighty = 1;

            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.fill = GridBagConstraints.BOTH;

            advanced = new JPanel();
            {
                advanced.setLayout(new BoxLayout(advanced, BoxLayout.Y_AXIS));
                advanced.setBorder(new TitledBorder("Advance Settings"));
                advanced.add(new JCheckBox("Live"));
                advanced.add(new JCheckBox("Condition"));
                advanced.add(new JCheckBox("Disable"));
            }
            advanced.setVisible(false);

            var standard = new JPanel();
            {
                standard.setLayout(new BoxLayout(standard, BoxLayout.X_AXIS));
                comp = new JLabel("Label 1");
                standard.add(comp);
                standard.add(new JButton("Button 1"));
                var expandButton = new JButton("+");
                expandButton.addActionListener(e -> {
                    if (advanced.isVisible()) {
                        advanced.setVisible(false);
                        expandButton.setText("+");
                    } else {
                        advanced.setVisible(true);
                        expandButton.setText("-");
                    }
                });
                standard.add(expandButton);
            }
            add(standard, gbc);


            gbc.gridy++;
            gbc.weighty = 0;
            add(advanced, gbc);
        }

        public void setValue(Object value) {
            comp.setText(value.toString());
        }

        public void setAdvancedVisibility(boolean visible) {
            advanced.setVisible(visible);
        }
    }

    private static class DynamicExpndablePanelCellEditor extends AbstractCellEditor implements TableCellEditor {
        Object value;
        @Override
        public Object getCellEditorValue() {
            return value; // not changing
        }

        private final ExpandablePanel expandablePanel = new ExpandablePanel();
        {
            addCellEditorListener(new CellEditorListener() {
                @Override
                public void editingStopped(ChangeEvent e) {
                    expandablePanel.setAdvancedVisibility(false);
                }

                @Override
                public void editingCanceled(ChangeEvent e) {
                    expandablePanel.setAdvancedVisibility(false);
                }
            });
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            this.value = value;
            expandablePanel.setValue(value);

            return expandablePanel;
        }
    }

    private static class ExpandablePanelCellRenderer implements TableCellRenderer {
        private final ExpandablePanel expandablePanelRenderComponent = new ExpandablePanel();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM