I have Custom Components extended from JPanel.
The name are: PanelButton
and PanelSlider
QUESTION 1:
Is it valid (or secure) to create a xxxTableModel(...)
with nonuniform Matrix?
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)) {...}
That's equivalent to 3 Rows with different lengths:
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"
}
));
Now I'm implementing my own 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();
}
}
QUESTION 2:
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 null;
When I return null (I will have problem with Nimbus and GTK Look And Feels)UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
orUIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
Here the Exception 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();
QUESTION 3:
But, When the value Is not null and I don't know the Class type, How handle the return?
if (value != null) return (Component) value;
return table.getDefaultRenderer(String.class).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
- extend my
MyTableCellRenderer
class ofComponent
andreturn this;
ALL CODE
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;
}
}
EDIT 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());
});
}
Establishing the nimbus
LookAndFeel like first operation on main
method the Exception raise up:
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$4.run(RepaintManager.java:842)
at javax.swing.RepaintManager$4.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.access$1200(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.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.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)