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