Jtable with Titled Rows and Columns

JTable with titled rows and columns

I think that you searching RowTable

Sample Image

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();
}
});
}
}

How to Display Row Header on JTable Instead of Column Header

This is a proof of concept only

Disclaimer: Before I get a bunch of hate mail about the, obviously, horrible things I've done to make this work, I stole most of the painting code straight out of the source, this is how it's actually done within the look and feel code itself :P

I've also gone to the nth degree, meaning that I've literally assumed that you wanted the row headers to look like the column headers. If this isn't a requirement, it would be SO much easier to do...


Okay, this is a basic proof of concept, which provides the means to generate the row header and render them the same way as they are normally, just as row headers instead.

Things that need to be added/supported:

  • Detect when the table model is changed (that is, a new table model is set to the table)
  • Detect when the column model is changed (that is, a new column model is set to the table)

Much of this functionality would probably need to be added to the TableWithRowHeader implementation...

Basically, what this "tries" to do, is create a custom row header, based on a JTableHeader, remove the existing column header and add itself into the row header view position of the enclosing JScrollPane.

TableRowHeader

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class TableRowHeaderTest {

public static void main(String[] args) {
new TableRowHeaderTest();
}

public TableRowHeaderTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

Object rowData1[][]
= {
{"", "", "", ""},
{"", "", "", ""},
{"", "", "", ""},
{"", "", "", ""}
};

Object columnNames1[] = {"HEADER 1", "HEADER 2", "HEADER 3", "HEADER 4"};

JTable table1 = new TableWithRowHeader(rowData1, columnNames1);

table1.getColumnModel().getColumn(0).setPreferredWidth(120);

JScrollPane scrollPane1 = new JScrollPane(table1);
scrollPane1.setColumnHeaderView(null);

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane1);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TableWithRowHeader extends JTable {

private TableRowHeader rowHeader;

public TableWithRowHeader(final Object[][] rowData, final Object[] columnNames) {
super(rowData, columnNames);
rowHeader = new TableRowHeader(this);
}

@Override
protected void configureEnclosingScrollPane() {
// This is required as it calls a private method...
super.configureEnclosingScrollPane();

Container parent = SwingUtilities.getUnwrappedParent(this);
if (parent instanceof JViewport) {

JViewport port = (JViewport) parent;
Container gp = port.getParent();
if (gp instanceof JScrollPane) {

JScrollPane scrollPane = (JScrollPane) gp;
JViewport viewport = scrollPane.getViewport();
if (viewport == null || SwingUtilities.getUnwrappedView(viewport) != this) {
return;
}
scrollPane.setColumnHeaderView(null);
scrollPane.setRowHeaderView(rowHeader);
}
}
}

}

public class TableRowHeader extends JTableHeader {

private JTable table;

public TableRowHeader(JTable table) {
super(table.getColumnModel());
this.table = table;

table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {

@Override
public void columnAdded(TableColumnModelEvent e) {
repaint();
}

@Override
public void columnRemoved(TableColumnModelEvent e) {
repaint();
}

@Override
public void columnMoved(TableColumnModelEvent e) {
repaint();
}

@Override
public void columnMarginChanged(ChangeEvent e) {
repaint();
}

@Override
public void columnSelectionChanged(ListSelectionEvent e) {
// Don't care about this, want to highlight the row...
}
});
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
repaint();
}
});
}

public JTable getTable() {
return table;
}

@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension();
JTable table = getTable();
if (table != null) {
TableColumnModel model = table.getColumnModel();
if (model != null) {

for (int index = 0; index < model.getColumnCount(); index++) {

TableColumn column = model.getColumn(index);
TableCellRenderer renderer = column.getHeaderRenderer();
if (renderer == null) {

renderer = getDefaultRenderer();

}
Component comp = renderer.getTableCellRendererComponent(table, column.getHeaderValue(), false, false, -1, index);
size.width = Math.max(comp.getPreferredSize().width, size.width);
size.height += table.getRowHeight(index);

}

}
}
return size;

}

/**
* Overridden to avoid propagating a invalidate up the tree when the
* cell renderer child is configured.
*/
@Override
public void invalidate() {
}

/**
* If the specified component is already a child of this then we don't bother doing anything - stacking order doesn't matter for cell renderer components
* (CellRendererPane doesn't paint anyway).
*/
@Override
protected void addImpl(Component x, Object constraints, int index) {
if (x.getParent() == this) {
return;
} else {
super.addImpl(x, constraints, index);
}
}

@Override
protected void paintComponent(Graphics g) {

// super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();

g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());

JTable table = getTable();
if (table != null) {

int width = getWidth();

TableColumnModel model = table.getColumnModel();
if (model != null) {

for (int index = 0; index < model.getColumnCount(); index++) {

TableColumn column = model.getColumn(index);
TableCellRenderer renderer = column.getHeaderRenderer();
if (renderer == null) {

renderer = getDefaultRenderer();

}

boolean selected = table.getSelectedRow() == index;

Component comp = renderer.getTableCellRendererComponent(table, column.getHeaderValue(), selected, false, 0, index);

add(comp);
comp.validate();

int height = table.getRowHeight(index) - 1;
comp.setBounds(0, 0, width, height);
comp.paint(g2d);
comp.setBounds(-width, -height, 0, 0);

g2d.setColor(table.getGridColor());
g2d.drawLine(0, height, width, height);

g2d.translate(0, height + 1);

}

}
}
g2d.dispose();
removeAll();
}

}

}

Disclaimer: This is likely to blow up in your face. I make no checks for preventing the header from responding to things like changes to the column row sortering and ... in theory ... it shouldn't try and "resize" the column but I didn't test that...

Trying to create JTable with proper row header

maybe

Sample Image

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();
}
});
}
}

Here it is with system Look and Feel-
Sample Image

Creating row headers for JTable at run time

I hope my interpretation of the question is correct. To display a row header you need to create a new cell renderer and set it on the required column. For example, here is a basic renderer that mocks a table header:

static class RowHeaderRenderer extends DefaultTableCellRenderer {
public RowHeaderRenderer() {
setHorizontalAlignment(JLabel.CENTER);
}

public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
if (table != null) {
JTableHeader header = table.getTableHeader();

if (header != null) {
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}

if (isSelected) {
setFont(getFont().deriveFont(Font.BOLD));
}

setValue(value);
return this;
}
}

To set it up you can do the following:

table.getColumnModel().getColumn(0).setCellRenderer(new RowHeaderRenderer());

Here is how it looks like based on the posted code:

Sample Image

Java JTable: How to render left column cells for simple row header purposes

Yes - by using a custom TableCellRenderer, you can modify the way the first column (and first column only) displays.

Essentially you can use this to set the TableCellRenderer on the first column only:

table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());

And you can extend the DefaultTableCellRenderer to take care of any special rendering you want to do:

//Custom Renderer - does the default rendering except if told the row should be a different color
public static class CustomRenderer extends DefaultTableCellRenderer{

public CustomRenderer(){
super();
//Customize the rendering however you want
setBackground(UIManager.getColor("TableHeader.background"));
}
}

To put it all together in your example:

import javax.swing.*; 
import javax.swing.table.DefaultTableCellRenderer;

import java.awt.*;
public class TestTable extends JFrame{

public TestTable(){
init();
}

public final void init(){
String[] columnNames = {"", "Gross Weight"};

Object[][] data = {{"", new Integer(100)},};

final JTable table = new JTable(data, columnNames);
// Add Renderer to first column only
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);

JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(300, 200));
add(scrollPane);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {

public void run() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
TestTable ex = new TestTable();
ex.pack();
ex.setVisible(true);

}
});
}

//Custom Renderer - does the default rendering except if told the row should be a different color
public static class CustomRenderer extends DefaultTableCellRenderer{

public CustomRenderer(){
super();
//Customize the rendering however you want
setBackground(UIManager.getColor("TableHeader.background"));
}
}

}

JTable Row Header Text

RowHeader is

  • one way

  • better way



Related Topics



Leave a reply



Submit