java swing header jtable look-and-feel

java - Intentando crear JTable con el encabezado de fila adecuado



swing header (2)

Intento crear una JTable que tenga un encabezado de fila que se parezca a un encabezado de columna y he dedicado demasiado tiempo a ello: / Mi situación es similar a esta pregunta: Implementación de encabezado de fila JTable y tal vez esta: personalización de jtable Cellrenderer con el color del encabezado de la tabla

Parece que todavía no me han llevado hasta allí. He buscado muchos ejemplos y todos faltan. Ni siquiera hay ejemplos de tablas con encabezados de filas de Oracle / Sun. Parece que este tipo de tabla no debería ser tan raro.

Este solo formatea la primera columna, pero no se ve ni actúa como el encabezado de la columna: http://java-swing-tips.blogspot.com/2011/01/jtable-rowheader.html

Parece que este usa una JList para el encabezado de la fila y tiene problemas de alineación (menos de +1 píxel cada fila) y no se ve mejor cuando configuro Look and Feel. http://www.java2s.com/Code/Java/Swing-Components/TableRowHeaderExample.htm

Esta parece ser la idea que necesitaba usar (el encabezado de la fila es una JTable separada pero luego se carga en el JScrollPane como el encabezado de la fila), pero tengo que adaptarlo a mi código y luego asegurarme de que el encabezado de la fila obtiene el correcto apariencia del encabezado
http://www.chka.de/swing/table/row-headers/JTable.html

Eso es lo que he hecho menos el último bit. Intento que el renderizador del encabezado de la tabla sea también el procesador del encabezado de la fila. El encabezado de fila / primera columna ahora es gris en lugar de blanco como lo era cuando era solo otra columna de datos, pero aún no se parece al encabezado de columna. ¿Es esto correcto? ¿O debería dejarlo como una columna regular en la mesa principal y hacer algo más con él?

Así que aquí está mi código para actualizar la tabla. Este método solo está tomando una matriz de cadenas para el encabezado de columna, una matriz de cadenas para el encabezado de fila y una matriz de cadenas 2D para los datos principales. Tengo un dispTableRowHeader de JTable para el encabezado de fila y un dispTable de JTable para la tabla de datos principal.

private void updateDispTable(String[][] graphicalTable, String[] graphicalTableColumnHeader, String[] graphicalTableRowHeader) { //set model for the main data table, put in data. Also prevent editing cells dispTable.setModel(new javax.swing.table.DefaultTableModel( graphicalTable, graphicalTableColumnHeader ){ @Override public boolean isCellEditable(int rowIndex, int mColIndex) { return false; } }); //some mods for main data table dispTable.getTableHeader().setReorderingAllowed(false);//Was also able to do this within NetBeans GUI Builder by doing Table Contents from Jtable inspector item dispTable.getTableHeader().setResizingAllowed(false); //load main table to scrollpane jScrollPane2.setViewportView(dispTable); //get model for JTable that will be used as the row header, fill in values DefaultTableModel rowHeaderTableModel = new DefaultTableModel(0, 1);//one column for (int i = 0; i < graphicalTable.length; i++) rowHeaderTableModel.addRow(new Object[] { graphicalTableRowHeader[i] } ); //set model for row header, put in data. Alter renderer to make it like col header dispTableRowHeader.setModel(rowHeaderTableModel); dispTableRowHeader.setDefaultRenderer(Object.class, dispTableRowHeader.getTableHeader().getDefaultRenderer());//makes it gray but not like the header :/ //dispTableRowHeader.setDefaultRenderer(Object.class, jScrollPane2.getColumnHeader().getDefaultRenderer()); //load row header to scrollpane''s row header jScrollPane2.setRowHeaderView(dispTableRowHeader); //set the table corner and disallow reordering and resizing JTableHeader corner = dispTableRowHeader.getTableHeader(); corner.setReorderingAllowed(false); corner.setResizingAllowed(false); jScrollPane2.setCorner(JScrollPane.UPPER_LEFT_CORNER, corner);//load to scrollpane }

¡Agradezco enormemente cualquier ayuda!

EDITAR A CONTINUACIÓN EDITAR A CONTINUACIÓN Creé un proyecto completamente nuevo para experimentar y probé el método de trashgod (aunque lo hice para un encabezado de fila en lugar de como una segunda fila) y encontré que daba el mismo resultado que las celdas con estilo gris en lugar de estilo como el encabezamiento. Entonces traté de eliminar mi ajuste de Mirar y Sentir

// Set System L&F UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );

¡y luego el encabezado de la fila se veía igual que el encabezado de la columna! .. pero eso está en Nimbus o lo que sea por defecto Look and Feel. Vea las imágenes a continuación. El primero es con mi Look and Feel configurado en el sistema como el anterior (en Win7), y el segundo es el predeterminado.

Sistema Look and Feel (Win7) -

Look and Feel- de Java

Efectivamente, lo mismo sucede con mi programa. Entonces ahora parece que mi problema es con el Look and Feel. Quiero que se vea como la primera imagen (apariencia y sensación del sistema), pero con el estilo del lado izquierdo también.

Por cierto, he aquí un ejemplo en Win7 de MySQL Workbench que tiene los encabezados de fila y columna correctamente diseñados e incluso ambos sombrean las celdas azuladas al pasar el ratón sobre ellas. Lástima que no está hecho en Java, así que podría intentar comprobar cómo lo hicieron.

MySQL Workbench screenshot-

EDITAR A CONTINUACIÓN EDITAR DEBAJO DEL CÓDIGO SSCCE

package mytableexample2; import java.awt.Component; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; public class MyTableExample2 extends javax.swing.JFrame { public MyTableExample2() { initComponents(); } @SuppressWarnings("unchecked") private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); jTable1 = new javax.swing.JTable(){ @Override public Component prepareRenderer( TableCellRenderer renderer, int row, int col) { if (col == 0) { return this.getTableHeader().getDefaultRenderer() .getTableCellRendererComponent(this, this.getValueAt(row, col), false, false, row, col); } else { return super.prepareRenderer(renderer, row, col); } } }; jTable1.setAutoCreateRowSorter(false); final JTableHeader header = jTable1.getTableHeader(); header.setDefaultRenderer(new HeaderRenderer(jTable1)); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); jTable1.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {"Row 1", "Data 2", "Data 3", "Data 4", "Data 5"}, {"Row 2", "Data 6", "Data 7", "Data 8", "Data 9"}, {"Row 3", "Data 10", "Data 11", "Data 12", "Data 13"} }, new String [] { "", "Col 1", "Col 2", "Col 3", "Col 4" } )); jScrollPane1.setViewportView(jTable1); //Netbeans generated layout javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE) .addContainerGap()) ); pack(); } public static void main(String args[]) { try { //THIS SETS TO SYSTEM''S LOOK AND FEEL UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() ); //THIS SETS TO OTHER JAVA LOOK AND FEEL //UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); //UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(MyTableExample2.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(MyTableExample2.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(MyTableExample2.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(MyTableExample2.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new MyTableExample2().setVisible(true); } }); } // Variables declaration - do not modify private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTable jTable1; } class HeaderRenderer implements TableCellRenderer { TableCellRenderer renderer; public HeaderRenderer(JTable jTable1) { renderer = jTable1.getTableHeader().getDefaultRenderer(); } @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { return renderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, col); } }


tal vez

import java.awt.*; import java.awt.event.ActionEvent; import javax.swing.*; import javax.swing.UIManager.*; import javax.swing.event.*; import javax.swing.table.*; public class JTableRowHeader { private JFrame frame = new JFrame("JTable RowHeader"); private JScrollPane scrollPane; private JTable table; private DefaultTableModel model; private TableRowSorter<TableModel> sorter; private JTable headerTable; public JTableRowHeader() { table = new JTable(4, 4); for (int i = 0; i < table.getRowCount(); i++) { table.setValueAt(i, i, 0); } sorter = new TableRowSorter<TableModel>(table.getModel()); table.setRowSorter(sorter); model = new DefaultTableModel() { private static final long serialVersionUID = 1L; @Override public int getColumnCount() { return 1; } @Override public boolean isCellEditable(int row, int col) { return false; } @Override public int getRowCount() { return table.getRowCount(); } @Override public Class<?> getColumnClass(int colNum) { switch (colNum) { case 0: return String.class; default: return super.getColumnClass(colNum); } } }; headerTable = new JTable(model); for (int i = 0; i < table.getRowCount(); i++) { headerTable.setValueAt("Row " + (i + 1), i, 0); } headerTable.setShowGrid(false); headerTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); headerTable.setPreferredScrollableViewportSize(new Dimension(50, 0)); headerTable.getColumnModel().getColumn(0).setPreferredWidth(50); headerTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable x, Object value, boolean isSelected, boolean hasFocus, int row, int column) { boolean selected = table.getSelectionModel().isSelectedIndex(row); Component component = table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, value, false, false, -1, -2); ((JLabel) component).setHorizontalAlignment(SwingConstants.CENTER); if (selected) { component.setFont(component.getFont().deriveFont(Font.BOLD)); component.setForeground(Color.red); } else { component.setFont(component.getFont().deriveFont(Font.PLAIN)); } return component; } }); table.getRowSorter().addRowSorterListener(new RowSorterListener() { @Override public void sorterChanged(RowSorterEvent e) { model.fireTableDataChanged(); } }); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { model.fireTableRowsUpdated(0, model.getRowCount() - 1); } }); scrollPane = new JScrollPane(table); scrollPane.setRowHeaderView(headerTable); table.setPreferredScrollableViewportSize(table.getPreferredSize()); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.add(scrollPane); frame.add(new JButton(new AbstractAction("Toggle filter") { private static final long serialVersionUID = 1L; private RowFilter<TableModel, Object> filter = new RowFilter<TableModel, Object>() { @Override public boolean include(javax.swing.RowFilter.Entry<? extends TableModel, ? extends Object> entry) { return ((Number) entry.getValue(0)).intValue() % 2 == 0; } }; @Override public void actionPerformed(ActionEvent e) { if (sorter.getRowFilter() != null) { sorter.setRowFilter(null); } else { sorter.setRowFilter(filter); } } }), BorderLayout.SOUTH); frame.pack(); frame.setLocation(150, 150); frame.setVisible(true); } public static void main(String[] args) { try {// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if (info.getName().equals("Nimbus")) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (Exception e) { //e.printStackTrace(); } EventQueue.invokeLater(new Runnable() { @Override public void run() { JTableRowHeader TestTableRowHeader = new JTableRowHeader(); } }); } }

Aquí está con el sistema Look and Feel-


El uso de este HeaderRenderer como el renderizador de la primera fila de columnas puede producir el efecto que desee:

Adición: He actualizado el ejemplo para reflejar su sscce con un diseño manual. El getSystemLookAndFeelClassName() mi plataforma es com.apple.laf.AquaLookAndFeel , por lo que no veo el mismo resultado. Dos observaciones: Ya ha setAutoCreateRowSorter(false) para evitar que el widget de clasificación prolifere, y Nimbus lo conserva alternando fila resaltada.

import java.awt.Component; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; public class MyTableExample3 extends JFrame { private JScrollPane scrollPane; private JTable table; public MyTableExample3() { initComponents(); } @SuppressWarnings("unchecked") private void initComponents() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); table = new javax.swing.JTable() { @Override public Component prepareRenderer( TableCellRenderer renderer, int row, int col) { if (col == 0) { return this.getTableHeader().getDefaultRenderer() .getTableCellRendererComponent(this, this.getValueAt( row, col), false, false, row, col); } else { return super.prepareRenderer(renderer, row, col); } } }; table.setAutoCreateRowSorter(false); final JTableHeader header = table.getTableHeader(); header.setDefaultRenderer(new HeaderRenderer(table)); table.setModel(new javax.swing.table.DefaultTableModel( new Object[][]{ {"Row 1", "Data 2", "Data 3", "Data 4", "Data 5"}, {"Row 2", "Data 6", "Data 7", "Data 8", "Data 9"}, {"Row 3", "Data 10", "Data 11", "Data 12", "Data 13"} }, new String[]{ "", "Col 1", "Col 2", "Col 3", "Col 4" })); scrollPane = new JScrollPane(table); this.add(scrollPane); pack(); } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { new MyTableExample3().setVisible(true); } }); } private static class HeaderRenderer implements TableCellRenderer { TableCellRenderer renderer; public HeaderRenderer(JTable table) { renderer = table.getTableHeader().getDefaultRenderer(); } @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { return renderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, col); } } }