具有非均匀对象数组的 JTable,自定义 TableCellRenderer 实现的 return
JTable with nonuniform Object Array, return of Custom TableCellRenderer implementation
我从 JPanel 扩展了自定义组件。
名称是:PanelButton
和 PanelSlider
问题 1:
使用非均匀矩阵创建 xxxTableModel(...)
是否有效(或安全)?
String[] hdrsObjects = {"PanelButton Class", "PanelSlider Class"};
Object[][] objectMatrix = new Object[3][2];
objectMatrix[0][0] = new PanelButtonData(...);
objectMatrix[1][0] = new PanelButtonData(...);
objectMatrix[2][0] = new PanelButtonData(...);
// objectMatrix[0][1] = /*Non Assigned*/
objectMatrix[1][1] = new PanelSliderData(0, 20, 40);
objectMatrix[2][1] = new PanelSliderData(30, 40, 60);
JTable Mytable = new JTable(new MyTableModel(objectMatrix, hdrsObjects)) {...}
这相当于 3 行不同的长度:
jtblGeneral.setModel(new DefaultTableModel(
new Object [][] { {"Cell Row:0,Col:0"}, {"Cell Row:1,Col:0", "Cell Row:1,Col:1"}, {"Cell Row:2,Col:0", "Cell Row:2,Col:1"}
},
new String [] {
"Title 1", "Title 2"
}
));
现在我正在实施我自己的 TableCellRenderer
class MyTableCellRenderer implements TableCellRenderer {
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
return ps;
}
//if (value != null)
// return (Component) value;
//return this;
//return null;
// return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
// table, value, isSelected, hasFocus, row, column);
return new JLabel();
}
}
问题 2:
如果前一个问题的答案是肯定的。当该值为 null 且未在我的自定义 JPanel Classes 中定义(如 row:0、col:1 中的单元格)时,我必须 return 的类型对象是什么?
return null;
当我 return 为空时(我会遇到 Nimbus 和 GTK 外观问题)
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
或
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
这里是异常 java.lang.NullPointerException:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
return new JLabel();
return new Component();
问题 3:
但是,当值不为null且我不知道Class类型时,如何处理return?
if (value != null) return (Component) value;
return table.getDefaultRenderer(String.class).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
- 扩展我的
MyTableCellRenderer
class 的 Component
和 return this;
所有代码
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableButtonSlider extends JFrame {
public TableButtonSlider() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(600, 300);
setVisible(true);
setLocationRelativeTo(null);
}
public static void setLAF(Container container, String laf) {
try {
UIManager.setLookAndFeel(laf);
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
}
SwingUtilities.updateComponentTreeUI(container);
}
static final JFrame frame = new JFrame();
public JComponent makeUI() {
String[] hdrsObjects = {"PanelButton Class", "PanelSlider Class"};
Object[][] objectMatrix = new Object[3][2];
objectMatrix[0][0] = new PanelButtonData(true);
objectMatrix[1][0] = new PanelButtonData(false);
objectMatrix[2][0] = new PanelButtonData(false);
// objectMatrix[0][1] = new PanelSliderData(10, 30, 40);
objectMatrix[1][1] = new PanelSliderData(0, 20, 40);
objectMatrix[2][1] = new PanelSliderData(30, 40, 60);
JTable Mytable = new JTable(new MyTableModel(objectMatrix, hdrsObjects)) {
@Override public void updateUI() {
super.updateUI();
setRowHeight(30);
TableColumn tc;
tc = getColumn("PanelSlider Class");
tc.setCellRenderer(new MyTableCellRenderer());
tc.setCellEditor(new MyTableCellEditor());
tc = getColumn("PanelButton Class");
tc.setCellRenderer(new MyTableCellRenderer());
tc.setCellEditor(new MyTableCellEditor());
}
};
JScrollPane scrollPane = new JScrollPane(Mytable);
JPanel pH = new JPanel();
pH.setLayout(new BoxLayout(pH, BoxLayout.LINE_AXIS));
JPanel pV = new JPanel();
pV.setLayout(new BoxLayout(pV, BoxLayout.PAGE_AXIS));
JButton bInsert = new JButton("Insert");
bInsert.addActionListener((ActionEvent e) -> {
((MyTableModel)Mytable.getModel()).addRow(
new Object[] {
new PanelButtonData(false),
new PanelSliderData(0, 25, 50)
}
);
Mytable.updateUI();
});
JButton bMetal = new JButton("Metal");
bMetal.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "javax.swing.plaf.metal.MetalLookAndFeel");
});
JButton bMotif = new JButton("Motif");
bMotif.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
});
JButton bNimbus = new JButton("Nimbus");
bNimbus.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "javax.swing.plaf.nimbus.NimbusLookAndFeel");
});
JButton bMacOS = new JButton("mac");
bMacOS.addActionListener((ActionEvent evt) -> {
setLAF(TableButtonSlider.this, "com.apple.laf.AquaLookAndFeel");
});
JButton bWindows = new JButton("win");
bWindows.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
});
JButton bLinux = new JButton("lnx");
bLinux.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
});
pH.add(bInsert);
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(new JSeparator(JSeparator.VERTICAL));
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(bLinux);
pH.add(bMacOS);
pH.add(bWindows);
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(new JSeparator(JSeparator.VERTICAL));
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(bMetal);
pH.add(bMotif);
pH.add(bNimbus);
pV.add(pH);
pV.add(scrollPane);
return pV;
}
public static void main(String... args) {
UIManager.put("Slider.paintValue", false);
EventQueue.invokeLater(() -> {
TableButtonSlider f = new TableButtonSlider();
f.getContentPane().add(f.makeUI());
});
}
}
class PanelButton extends JPanel {
JButton jbtWavRow = new JButton();
private final JPanel panel = new JPanel();
PanelButton(PanelButtonData data) {
super();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createRigidArea(new Dimension(2,0)));
panel.add(jbtWavRow);
panel.add(Box.createRigidArea(new Dimension(2,0)));
jbtWavRow.setFont(new Font("Monospaced", Font.PLAIN, 10));
setData(data);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(panel);
}
public PanelButtonData getData() {
return new PanelButtonData(jbtWavRow.getActionCommand().equals("+"));
}
public void setData(PanelButtonData data) {
for (ActionListener al : jbtWavRow.getActionListeners()) {
jbtWavRow.removeActionListener(al);
}
if(data.getIns()) {
jbtWavRow.setText("Insert");
jbtWavRow.setActionCommand("+");
jbtWavRow.addActionListener((ActionEvent e) -> {
JTable table = (JTable)SwingUtilities.getAncestorOfClass(
JTable.class, (Component) e.getSource());
table.getCellEditor().stopCellEditing();
((MyTableModel)table.getModel()).addRow(
new Object[] {
new PanelButtonData(false),
new PanelSliderData(0, 25, 50)
}
);
table.updateUI();
});
} else {
jbtWavRow.setText("Remove");
jbtWavRow.setActionCommand("-");
jbtWavRow.addActionListener((ActionEvent e) -> {
JTable table = (JTable) SwingUtilities.getAncestorOfClass(
JTable.class, (Component) e.getSource());
int row = table.getEditingRow();
table.getCellEditor().stopCellEditing();
((MyTableModel) table.getModel()).removeRow(row);
// table.updateUI();
});
}
}
}
class PanelButtonData {
private boolean add = false;
PanelButtonData(Boolean add) { this.add = add; }
public void setIns(Boolean add) { this.add = add; }
public boolean getIns() { return add; }
}
class PanelSlider extends JPanel {
private final JSlider jslChanger = new JSlider(SwingConstants.HORIZONTAL);
private final JPanel panel = new JPanel();
PanelSlider(PanelSliderData data) {
super();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createRigidArea(new Dimension(2,0)));
panel.add(jslChanger);
panel.add(Box.createRigidArea(new Dimension(2,0)));
setData(data);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(panel);
}
public void setData(PanelSliderData data) {
jslChanger.setMinimum(data.getMin());
jslChanger.setValue(data.getVal());
jslChanger.setMaximum(data.getMax());
}
// Used in MyTableCellRenderer.getCellEditorValue()
public PanelSliderData getData() {
return new PanelSliderData(jslChanger.getMinimum(), jslChanger.getValue(), jslChanger.getMaximum());
}
}
class PanelSliderData {
private Integer Min = 0;
private Integer Val = 25;
private Integer Max = 50;
PanelSliderData(int Min, int Val, int Max) {
this.Min = Min;
this.Val = Val;
this.Max = Max;
}
public Integer getMin() { return Min; }
public Integer getVal() { return Val; }
public Integer getMax() { return Max; }
}
class MyTableCellRenderer implements TableCellRenderer {
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
return ps;
}
//if (value != null)
// return (Component) value;
//return this;
return null;
//return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
// table, value, isSelected, hasFocus, row, column);
//return new JLabel();
}
}
class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
protected Object output;
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
@Override public Object getCellEditorValue() {
if (output instanceof PanelButton) {
return pb.getData();
}
if (output instanceof PanelSlider) {
return ps.getData();
}
return null;
}
@Override public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
output = pb;
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
output = ps;
return ps;
}
return null;
}
}
class MyTableModel extends AbstractTableModel {
//class MyTableModel extends DefaultTableModel {
private Object[][] data;
private Object[] columns;
public MyTableModel(Object[][] data, Object[] columns) {
this.data = data;
this.columns = columns;
}
@Override public Object getValueAt(int rowIndex, int columnIndex) {
if (data != null) {
if (data.length > 0) {
return data[rowIndex][columnIndex];
}
}
return null;
}
@Override public int getColumnCount() {
return ((columns == null) ? 0: columns.length);
}
@Override public int getRowCount() {
return ((data == null) ? 0: data.length);
}
@Override public Class getColumnClass(int columnIndex) {
if (data != null) {
if (data.length > 0) {
if (data[0][columnIndex] instanceof PanelButton) {
return PanelButton.class;
}
if (data[0][columnIndex] instanceof PanelSlider) {
return PanelSlider.class;
}
//return data[0][columnIndex].getClass();
return String.class;
}
}
return Object.class;
}
@Override public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
@Override public String getColumnName(int columnIndex) {
return (String)columns[columnIndex];
}
//@Override
public void removeRow(int row) {
Object[][] newData = new Object[data.length - 1][data[0].length];
int rown = 0;
for (int row1 = 0; row1 <data.length; row1++) {
if (row1 != row) {
for (int col = 0; col < data[0].length; col++) {
newData[rown][col] = data[row1][col];
}
rown++;
}
}
data = newData;
}
//@Override
public void addRow(Object[] rowData) {
Object[][] newData;
int maxCol;
if ((data != null) && (data.length > 0)) {
newData = new Object[data.length + 1][data[0].length];
for (int row = 0; row <data.length; row++) {
for (int col = 0; col < data[0].length; col++) {
newData[row][col] = data[row][col];
}
}
maxCol = data[0].length < rowData.length?data[0].length:rowData.length;
} else {
newData = new Object[1][rowData.length];
maxCol = rowData.length;
}
//Insert rowData objects
for (int col = 0; col < maxCol; col++) {
newData[newData.length - 1][col] = rowData[col];
}
data = newData;
}
}
编辑 1
public static void main(String... args) {
UIManager.put("Slider.paintValue", false);
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) { }
EventQueue.invokeLater(() -> {
TableButtonSlider f = new TableButtonSlider();
f.getContentPane().add(f.makeUI());
});
}
建立 nimbus
LookAndFeel 就像在 main
方法上的第一个操作引发异常:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JViewport.paint(JViewport.java:728)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent.paint(JComponent.java:1042)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
at java.awt.Container.paint(Container.java:1975)
at java.awt.Window.paint(Window.java:3904)
at javax.swing.RepaintManager.run(RepaintManager.java:842)
at javax.swing.RepaintManager.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access00(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Is it valid (or secure) to create a xxxTableModel(...) with nonuniform Matrix?
是的,你可以做到,但你需要付出很多努力才能让它发挥作用,因为 JTable
确实不是为这种方式设计的
If Answer is YES for before Question. When the value is null and not defined (like cell in row:0, col:1) in my custom JPanel Classes, what Type Object I must return?
您必须 return Component
的一个实例,您不能 return null
But, When the value Is not null and I don't know the Class type, How handle the return?
这与你的第二个问题的答案相同,你必须 return Component
的一个实例,这取决于你想如何处理 null
之间的差异和“未知”值
观察结果
在深入了解你的代码后,你正在调用 updateUI
这是不合适的,这不是在你改变它的状态时触发对 UI 的“更新”的方法,它是仅用于(由系统)用于通知组件外观委托已更改
在您的 TableModel
中,您应该在更新模型时触发适当的事件,这将通知父级 JTable
并进行适当的更改。
我删除了您代码中对 updateUI
的所有调用,并简单地更新了您的 addRow
方法以调用 fireTableRowsInserted
public void addRow(Object[] rowData) {
Object[][] newData;
int maxCol;
if ((data != null) && (data.length > 0)) {
newData = new Object[data.length + 1][data[0].length];
for (int row = 0; row < data.length; row++) {
for (int col = 0; col < data[0].length; col++) {
newData[row][col] = data[row][col];
}
}
maxCol = data[0].length < rowData.length ? data[0].length : rowData.length;
} else {
newData = new Object[1][rowData.length];
maxCol = rowData.length;
}
//Insert rowData objects
for (int col = 0; col < maxCol; col++) {
newData[newData.length - 1][col] = rowData[col];
}
data = newData;
fireTableRowsInserted(data.length - 1, data.length - 1);
}
并且 NullPointerException
消失了。您还必须对 removeRow
进行适当的更改
我从 JPanel 扩展了自定义组件。
名称是:PanelButton
和 PanelSlider
问题 1:
使用非均匀矩阵创建 xxxTableModel(...)
是否有效(或安全)?
String[] hdrsObjects = {"PanelButton Class", "PanelSlider Class"};
Object[][] objectMatrix = new Object[3][2];
objectMatrix[0][0] = new PanelButtonData(...);
objectMatrix[1][0] = new PanelButtonData(...);
objectMatrix[2][0] = new PanelButtonData(...);
// objectMatrix[0][1] = /*Non Assigned*/
objectMatrix[1][1] = new PanelSliderData(0, 20, 40);
objectMatrix[2][1] = new PanelSliderData(30, 40, 60);
JTable Mytable = new JTable(new MyTableModel(objectMatrix, hdrsObjects)) {...}
这相当于 3 行不同的长度:
jtblGeneral.setModel(new DefaultTableModel(
new Object [][] { {"Cell Row:0,Col:0"}, {"Cell Row:1,Col:0", "Cell Row:1,Col:1"}, {"Cell Row:2,Col:0", "Cell Row:2,Col:1"}
},
new String [] {
"Title 1", "Title 2"
}
));
现在我正在实施我自己的 TableCellRenderer
class MyTableCellRenderer implements TableCellRenderer {
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
return ps;
}
//if (value != null)
// return (Component) value;
//return this;
//return null;
// return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
// table, value, isSelected, hasFocus, row, column);
return new JLabel();
}
}
问题 2:
如果前一个问题的答案是肯定的。当该值为 null 且未在我的自定义 JPanel Classes 中定义(如 row:0、col:1 中的单元格)时,我必须 return 的类型对象是什么?
return null;
当我 return 为空时(我会遇到 Nimbus 和 GTK 外观问题)UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
或UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
这里是异常 java.lang.NullPointerException:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
return new JLabel();
return new Component();
问题 3:
但是,当值不为null且我不知道Class类型时,如何处理return?
if (value != null) return (Component) value;
return table.getDefaultRenderer(String.class).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
- 扩展我的
MyTableCellRenderer
class 的Component
和return this;
所有代码
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableButtonSlider extends JFrame {
public TableButtonSlider() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(600, 300);
setVisible(true);
setLocationRelativeTo(null);
}
public static void setLAF(Container container, String laf) {
try {
UIManager.setLookAndFeel(laf);
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
}
SwingUtilities.updateComponentTreeUI(container);
}
static final JFrame frame = new JFrame();
public JComponent makeUI() {
String[] hdrsObjects = {"PanelButton Class", "PanelSlider Class"};
Object[][] objectMatrix = new Object[3][2];
objectMatrix[0][0] = new PanelButtonData(true);
objectMatrix[1][0] = new PanelButtonData(false);
objectMatrix[2][0] = new PanelButtonData(false);
// objectMatrix[0][1] = new PanelSliderData(10, 30, 40);
objectMatrix[1][1] = new PanelSliderData(0, 20, 40);
objectMatrix[2][1] = new PanelSliderData(30, 40, 60);
JTable Mytable = new JTable(new MyTableModel(objectMatrix, hdrsObjects)) {
@Override public void updateUI() {
super.updateUI();
setRowHeight(30);
TableColumn tc;
tc = getColumn("PanelSlider Class");
tc.setCellRenderer(new MyTableCellRenderer());
tc.setCellEditor(new MyTableCellEditor());
tc = getColumn("PanelButton Class");
tc.setCellRenderer(new MyTableCellRenderer());
tc.setCellEditor(new MyTableCellEditor());
}
};
JScrollPane scrollPane = new JScrollPane(Mytable);
JPanel pH = new JPanel();
pH.setLayout(new BoxLayout(pH, BoxLayout.LINE_AXIS));
JPanel pV = new JPanel();
pV.setLayout(new BoxLayout(pV, BoxLayout.PAGE_AXIS));
JButton bInsert = new JButton("Insert");
bInsert.addActionListener((ActionEvent e) -> {
((MyTableModel)Mytable.getModel()).addRow(
new Object[] {
new PanelButtonData(false),
new PanelSliderData(0, 25, 50)
}
);
Mytable.updateUI();
});
JButton bMetal = new JButton("Metal");
bMetal.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "javax.swing.plaf.metal.MetalLookAndFeel");
});
JButton bMotif = new JButton("Motif");
bMotif.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
});
JButton bNimbus = new JButton("Nimbus");
bNimbus.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "javax.swing.plaf.nimbus.NimbusLookAndFeel");
});
JButton bMacOS = new JButton("mac");
bMacOS.addActionListener((ActionEvent evt) -> {
setLAF(TableButtonSlider.this, "com.apple.laf.AquaLookAndFeel");
});
JButton bWindows = new JButton("win");
bWindows.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
});
JButton bLinux = new JButton("lnx");
bLinux.addActionListener((ActionEvent) -> {
setLAF(TableButtonSlider.this, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
});
pH.add(bInsert);
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(new JSeparator(JSeparator.VERTICAL));
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(bLinux);
pH.add(bMacOS);
pH.add(bWindows);
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(new JSeparator(JSeparator.VERTICAL));
pH.add(Box.createRigidArea(new Dimension(1,0)));
pH.add(bMetal);
pH.add(bMotif);
pH.add(bNimbus);
pV.add(pH);
pV.add(scrollPane);
return pV;
}
public static void main(String... args) {
UIManager.put("Slider.paintValue", false);
EventQueue.invokeLater(() -> {
TableButtonSlider f = new TableButtonSlider();
f.getContentPane().add(f.makeUI());
});
}
}
class PanelButton extends JPanel {
JButton jbtWavRow = new JButton();
private final JPanel panel = new JPanel();
PanelButton(PanelButtonData data) {
super();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createRigidArea(new Dimension(2,0)));
panel.add(jbtWavRow);
panel.add(Box.createRigidArea(new Dimension(2,0)));
jbtWavRow.setFont(new Font("Monospaced", Font.PLAIN, 10));
setData(data);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(panel);
}
public PanelButtonData getData() {
return new PanelButtonData(jbtWavRow.getActionCommand().equals("+"));
}
public void setData(PanelButtonData data) {
for (ActionListener al : jbtWavRow.getActionListeners()) {
jbtWavRow.removeActionListener(al);
}
if(data.getIns()) {
jbtWavRow.setText("Insert");
jbtWavRow.setActionCommand("+");
jbtWavRow.addActionListener((ActionEvent e) -> {
JTable table = (JTable)SwingUtilities.getAncestorOfClass(
JTable.class, (Component) e.getSource());
table.getCellEditor().stopCellEditing();
((MyTableModel)table.getModel()).addRow(
new Object[] {
new PanelButtonData(false),
new PanelSliderData(0, 25, 50)
}
);
table.updateUI();
});
} else {
jbtWavRow.setText("Remove");
jbtWavRow.setActionCommand("-");
jbtWavRow.addActionListener((ActionEvent e) -> {
JTable table = (JTable) SwingUtilities.getAncestorOfClass(
JTable.class, (Component) e.getSource());
int row = table.getEditingRow();
table.getCellEditor().stopCellEditing();
((MyTableModel) table.getModel()).removeRow(row);
// table.updateUI();
});
}
}
}
class PanelButtonData {
private boolean add = false;
PanelButtonData(Boolean add) { this.add = add; }
public void setIns(Boolean add) { this.add = add; }
public boolean getIns() { return add; }
}
class PanelSlider extends JPanel {
private final JSlider jslChanger = new JSlider(SwingConstants.HORIZONTAL);
private final JPanel panel = new JPanel();
PanelSlider(PanelSliderData data) {
super();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createRigidArea(new Dimension(2,0)));
panel.add(jslChanger);
panel.add(Box.createRigidArea(new Dimension(2,0)));
setData(data);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(panel);
}
public void setData(PanelSliderData data) {
jslChanger.setMinimum(data.getMin());
jslChanger.setValue(data.getVal());
jslChanger.setMaximum(data.getMax());
}
// Used in MyTableCellRenderer.getCellEditorValue()
public PanelSliderData getData() {
return new PanelSliderData(jslChanger.getMinimum(), jslChanger.getValue(), jslChanger.getMaximum());
}
}
class PanelSliderData {
private Integer Min = 0;
private Integer Val = 25;
private Integer Max = 50;
PanelSliderData(int Min, int Val, int Max) {
this.Min = Min;
this.Val = Val;
this.Max = Max;
}
public Integer getMin() { return Min; }
public Integer getVal() { return Val; }
public Integer getMax() { return Max; }
}
class MyTableCellRenderer implements TableCellRenderer {
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
return ps;
}
//if (value != null)
// return (Component) value;
//return this;
return null;
//return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
// table, value, isSelected, hasFocus, row, column);
//return new JLabel();
}
}
class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
protected Object output;
private final PanelButton pb = new PanelButton(new PanelButtonData(false));
private final PanelSlider ps = new PanelSlider(new PanelSliderData(0, 25, 50));
@Override public Object getCellEditorValue() {
if (output instanceof PanelButton) {
return pb.getData();
}
if (output instanceof PanelSlider) {
return ps.getData();
}
return null;
}
@Override public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
if (value instanceof PanelButtonData) {
pb.setData((PanelButtonData) value);
output = pb;
return pb;
}
if (value instanceof PanelSliderData) {
ps.setData((PanelSliderData) value);
output = ps;
return ps;
}
return null;
}
}
class MyTableModel extends AbstractTableModel {
//class MyTableModel extends DefaultTableModel {
private Object[][] data;
private Object[] columns;
public MyTableModel(Object[][] data, Object[] columns) {
this.data = data;
this.columns = columns;
}
@Override public Object getValueAt(int rowIndex, int columnIndex) {
if (data != null) {
if (data.length > 0) {
return data[rowIndex][columnIndex];
}
}
return null;
}
@Override public int getColumnCount() {
return ((columns == null) ? 0: columns.length);
}
@Override public int getRowCount() {
return ((data == null) ? 0: data.length);
}
@Override public Class getColumnClass(int columnIndex) {
if (data != null) {
if (data.length > 0) {
if (data[0][columnIndex] instanceof PanelButton) {
return PanelButton.class;
}
if (data[0][columnIndex] instanceof PanelSlider) {
return PanelSlider.class;
}
//return data[0][columnIndex].getClass();
return String.class;
}
}
return Object.class;
}
@Override public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
@Override public String getColumnName(int columnIndex) {
return (String)columns[columnIndex];
}
//@Override
public void removeRow(int row) {
Object[][] newData = new Object[data.length - 1][data[0].length];
int rown = 0;
for (int row1 = 0; row1 <data.length; row1++) {
if (row1 != row) {
for (int col = 0; col < data[0].length; col++) {
newData[rown][col] = data[row1][col];
}
rown++;
}
}
data = newData;
}
//@Override
public void addRow(Object[] rowData) {
Object[][] newData;
int maxCol;
if ((data != null) && (data.length > 0)) {
newData = new Object[data.length + 1][data[0].length];
for (int row = 0; row <data.length; row++) {
for (int col = 0; col < data[0].length; col++) {
newData[row][col] = data[row][col];
}
}
maxCol = data[0].length < rowData.length?data[0].length:rowData.length;
} else {
newData = new Object[1][rowData.length];
maxCol = rowData.length;
}
//Insert rowData objects
for (int col = 0; col < maxCol; col++) {
newData[newData.length - 1][col] = rowData[col];
}
data = newData;
}
}
编辑 1
public static void main(String... args) {
UIManager.put("Slider.paintValue", false);
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) { }
EventQueue.invokeLater(() -> {
TableButtonSlider f = new TableButtonSlider();
f.getContentPane().add(f.makeUI());
});
}
建立 nimbus
LookAndFeel 就像在 main
方法上的第一个操作引发异常:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:684)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JViewport.paint(JViewport.java:728)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent.paint(JComponent.java:1042)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
at java.awt.Container.paint(Container.java:1975)
at java.awt.Window.paint(Window.java:3904)
at javax.swing.RepaintManager.run(RepaintManager.java:842)
at javax.swing.RepaintManager.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access00(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Is it valid (or secure) to create a xxxTableModel(...) with nonuniform Matrix?
是的,你可以做到,但你需要付出很多努力才能让它发挥作用,因为 JTable
确实不是为这种方式设计的
If Answer is YES for before Question. When the value is null and not defined (like cell in row:0, col:1) in my custom JPanel Classes, what Type Object I must return?
您必须 return Component
的一个实例,您不能 return null
But, When the value Is not null and I don't know the Class type, How handle the return?
这与你的第二个问题的答案相同,你必须 return Component
的一个实例,这取决于你想如何处理 null
之间的差异和“未知”值
观察结果
在深入了解你的代码后,你正在调用 updateUI
这是不合适的,这不是在你改变它的状态时触发对 UI 的“更新”的方法,它是仅用于(由系统)用于通知组件外观委托已更改
在您的 TableModel
中,您应该在更新模型时触发适当的事件,这将通知父级 JTable
并进行适当的更改。
我删除了您代码中对 updateUI
的所有调用,并简单地更新了您的 addRow
方法以调用 fireTableRowsInserted
public void addRow(Object[] rowData) {
Object[][] newData;
int maxCol;
if ((data != null) && (data.length > 0)) {
newData = new Object[data.length + 1][data[0].length];
for (int row = 0; row < data.length; row++) {
for (int col = 0; col < data[0].length; col++) {
newData[row][col] = data[row][col];
}
}
maxCol = data[0].length < rowData.length ? data[0].length : rowData.length;
} else {
newData = new Object[1][rowData.length];
maxCol = rowData.length;
}
//Insert rowData objects
for (int col = 0; col < maxCol; col++) {
newData[newData.length - 1][col] = rowData[col];
}
data = newData;
fireTableRowsInserted(data.length - 1, data.length - 1);
}
并且 NullPointerException
消失了。您还必须对 removeRow
进行适当的更改