[英]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.