Best way to display components in JTable?

I am not asking how to render a component in JTable, as there are several tutorials and examples on the Internet. However, I want to know that the BEST way around this can be.

For example, in most of the tutorials I come across, there are examples that create separate classes (The main class that extends JTable ), which extends TableModel , which extends TableCellRenderer , etc.). However, I found that you can not only do this in one class, but in one method, simply using the following:

Sample Code (SSCCE)


the main

 public class Main { public static void main(String[] args) { javax.swing.JFrame jf = new javax.swing.JFrame("A table with components"); jf.setLayout(new java.awt.BorderLayout()); jf.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); jf.add(new TableWithCompsPanel(), java.awt.BorderLayout.CENTER); jf.setVisible(true); } } 

TableWithComps

 public class TableWithCompsPanel extends java.awt.Container { private Class<?> tableColumnClassArray[]; private javax.swing.JTable jTableWithComps; private Object tableContentsArray[][]; public TableWithCompsPanel() { tableContentsArray = new Object[][] { {"This is plain text", new javax.swing.JButton("This is a button") }, {new javax.swing.JLabel("This is an improperly rendered label!"), new javax.swing.JCheckBox("This is a checkbox")} }; tableColumnClassArray = new Class<?>[]{String.class, java.awt.Component.class}; initGUI(); } private void initGUI() { setLayout(new java.awt.BorderLayout()); jTableWithComps = new javax.swing.JTable(new javax.swing.table.AbstractTableModel() { @Override public int getRowCount() { return tableContentsArray.length; } @Override public int getColumnCount() { return tableContentsArray[0].length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return tableContentsArray[rowIndex][columnIndex]; } @Override public Class<?> getColumnClass(int columnIndex) { return tableColumnClassArray[columnIndex]; } }); jTableWithComps.setDefaultRenderer(java.awt.Component.class, new javax.swing.table.TableCellRenderer() { @Override public java.awt.Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { return value instanceof java.awt.Component ? (java.awt.Component)value : new javax.swing.table.DefaultTableCellRenderer(); } }); add(jTableWithComps, java.awt.BorderLayout.CENTER); } } 

Question


I am wondering that if this can be done in such a short amount of code, why do the examples go out of their way to divide it into three, and sometimes even more? Is my code somehow less efficient at runtime? I understand that I am sharing the main class and the class with the GUI example, but not why you separate the GUI example from several classes.

Edit: I see a lot of people giving good reasons why this code is impractical. I would be grateful for your answers more if you provided an alternative!

+4
source share
4 answers

TableModel models the data you want to track in the simplest way, for the sake of memory efficiency. TableCellRenderer defines how to display this data in a table cell.

In your iTunes checkbox example, the simplest way to model the information from the checkbox is a boolean (true / false). To store a collection of 10,000 boolean objects than 10,000 JCheckBox objects, memory is much more efficient.

Then the TableCellRenderer can store one JCheckBox object, and when it is offered to use the component to draw a cell, it can check / uncheck the box based on the value and return the same component every time, this way you do not create thousands of user interface components over and over again when the user scrolls this table.

+5
source

In general, the separation in many interacting components is due to the design. This scheme attempts to apply good principles, such as separation of concerns. You can build one big thing that does everything or identifies smaller parts, each of which is responsible. In a later case, your code is more suitable for changes because each class does only one thing and changes a lot of time, implying moving one or two responsibilities without violating the general architecture of the solution.

In particular, Swing uses the MVC pattern, which is a little detailed, but tries to understand many good design principles. I understand that this is not always the easiest thing to maintain, but I must admit that the answers are very untied.

Samples may be short. But they must adhere to the philosophy and architecture of Swing. This is why they implement the same roles regardless of code size.

The rule of thumb for this (IMHO) is to find for each division the reason why the division was performed.

Performance: don’t worry if your code is divided into several classes. This does not affect performance. Another thing (for example, temporary complexity). Or, perhaps, the incorrect use of components, but if everything is used, as expected, everything will be in order.

Edit: I hope that this answer will be helpful! As you can see, this is not swing oriented at all ...

+3
source

What to consider:

  • From your example, you can see that the cell value is a Component. Won't it take up huge memory for every non-trivial table?
  • Is the component correctly colored when the row row is selected, is in focus, etc.
  • If your component is very smart, you may have problems editing the cell.
+2
source
  • Renderer is only for visual decoration of the contents of the cell, for example. setFont, setForeground, setBackground, isEnable, isVisible, etc.

  • Do not create, install, modify, or modify JComponents enter a Renderer in Runtime; this is a job for TableModel .

  • If possible, use DefaultTableModel and use existing renderers for types known by JTable .

  • You know that type of Object/JComponent is / is present in a JTable cell.

+1
source

Source: https://habr.com/ru/post/1396856/


All Articles