JTable Multiple Header Rows - java

I am using a JTable in my application and wish to have 2 rows for headings, similar to this:
Is this even possible or will I have to do something else? If so, what? Using Supertitle-titleA, SuperTitle-titleB will take up too much space and make information redundant.

We had the same requirement in our last project. What I have found is an Implementation for a GroupableTableHeader on java2s.com. However, I have pimped it a bit, although I cannot recall what exactly. Beneath is the implementation of the three classes as how we use them.
ColumnGroup.java
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
/**
* ColumnGroup
*
* #version 1.0 20.10.1998
* #author Nobuo Tamemasa
*/
public class ColumnGroup {
protected TableCellRenderer renderer;
protected List<TableColumn> columns;
protected List<ColumnGroup> groups;
protected String text;
protected int margin = 0;
public ColumnGroup(String text) {
this(text, null);
}
public ColumnGroup(String text, TableCellRenderer renderer) {
this.text = text;
this.renderer = renderer;
this.columns = new ArrayList<TableColumn>();
this.groups = new ArrayList<ColumnGroup>();
}
public void add(TableColumn column) {
columns.add(column);
}
public void add(ColumnGroup group) {
groups.add(group);
}
/**
* #param column
* TableColumn
*/
public List<ColumnGroup> getColumnGroups(TableColumn column) {
if (!contains(column)) {
return Collections.emptyList();
}
List<ColumnGroup> result = new ArrayList<ColumnGroup>();
result.add(this);
if (columns.contains(column)) {
return result;
}
for (ColumnGroup columnGroup : groups) {
result.addAll(columnGroup.getColumnGroups(column));
}
return result;
}
private boolean contains(TableColumn column) {
if (columns.contains(column)) {
return true;
}
for (ColumnGroup group : groups) {
if (group.contains(column)) {
return true;
}
}
return false;
}
public TableCellRenderer getHeaderRenderer() {
return renderer;
}
public void setHeaderRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
}
public String getHeaderValue() {
return text;
}
public Dimension getSize(JTable table) {
TableCellRenderer renderer = this.renderer;
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(table, getHeaderValue() == null || getHeaderValue().trim().isEmpty() ? " "
: getHeaderValue(), false, false, -1, -1);
int height = comp.getPreferredSize().height;
int width = 0;
for (ColumnGroup columnGroup : groups) {
width += columnGroup.getSize(table).width;
}
for (TableColumn tableColumn : columns) {
width += tableColumn.getWidth();
width += margin;
}
return new Dimension(width, height);
}
public void setColumnMargin(int margin) {
this.margin = margin;
for (ColumnGroup columnGroup : groups) {
columnGroup.setColumnMargin(margin);
}
}
}
GroupableTableHeader.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
/**
* GroupableTableHeader
*
* #version 1.0 20.10.1998
* #author Nobuo Tamemasa
*/
#SuppressWarnings("serial")
public class GroupableTableHeader extends JTableHeader {
#SuppressWarnings("unused")
private static final String uiClassID = "GroupableTableHeaderUI";
protected List<ColumnGroup> columnGroups = new ArrayList<ColumnGroup>();
public GroupableTableHeader(TableColumnModel model) {
super(model);
setUI(new GroupableTableHeaderUI());
setReorderingAllowed(false);
// setDefaultRenderer(new MultiLineHeaderRenderer());
}
#Override
public void updateUI() {
setUI(new GroupableTableHeaderUI());
}
#Override
public void setReorderingAllowed(boolean b) {
super.setReorderingAllowed(false);
}
public void addColumnGroup(ColumnGroup g) {
columnGroups.add(g);
}
public List<ColumnGroup> getColumnGroups(TableColumn col) {
for (ColumnGroup group : columnGroups) {
List<ColumnGroup> groups = group.getColumnGroups(col);
if (!groups.isEmpty()) {
return groups;
}
}
return Collections.emptyList();
}
public void setColumnMargin() {
int columnMargin = getColumnModel().getColumnMargin();
for (ColumnGroup group : columnGroups) {
group.setColumnMargin(columnMargin);
}
}
}
GroupableTableHeaderUI.java
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class GroupableTableHeaderUI extends BasicTableHeaderUI {
protected GroupableTableHeader getHeader() {
return (GroupableTableHeader) header;
}
#Override
public void paint(Graphics g, JComponent c) {
Rectangle clipBounds = g.getClipBounds();
if (header.getColumnModel().getColumnCount() == 0) {
return;
}
int column = 0;
Dimension size = header.getSize();
Rectangle cellRect = new Rectangle(0, 0, size.width, size.height);
Map<ColumnGroup, Rectangle> groupSizeMap = new HashMap<ColumnGroup, Rectangle>();
for (Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) {
cellRect.height = size.height;
cellRect.y = 0;
TableColumn aColumn = enumeration.nextElement();
List<ColumnGroup> groups = getHeader().getColumnGroups(aColumn);
int groupHeight = 0;
for (ColumnGroup group : groups) {
Rectangle groupRect = groupSizeMap.get(group);
if (groupRect == null) {
groupRect = new Rectangle(cellRect);
Dimension d = group.getSize(header.getTable());
groupRect.width = d.width;
groupRect.height = d.height;
groupSizeMap.put(group, groupRect);
}
paintCell(g, groupRect, group);
groupHeight += groupRect.height;
cellRect.height = size.height - groupHeight;
cellRect.y = groupHeight;
}
cellRect.width = aColumn.getWidth();
if (cellRect.intersects(clipBounds)) {
paintCell(g, cellRect, column);
}
cellRect.x += cellRect.width;
column++;
}
}
private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
TableCellRenderer renderer = aColumn.getHeaderRenderer();
if (renderer == null) {
renderer = getHeader().getDefaultRenderer();
}
Component c = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false,
-1, columnIndex);
c.setBackground(UIManager.getColor("control"));
rendererPane.paintComponent(g, c, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true);
}
private void paintCell(Graphics g, Rectangle cellRect, ColumnGroup cGroup) {
TableCellRenderer renderer = cGroup.getHeaderRenderer();
if (renderer == null) {
renderer = getHeader().getDefaultRenderer();
}
Component component = renderer.getTableCellRendererComponent(header.getTable(), cGroup.getHeaderValue(), false,
false, -1, -1);
rendererPane
.paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true);
}
private int getHeaderHeight() {
int headerHeight = 0;
TableColumnModel columnModel = header.getColumnModel();
for (int column = 0; column < columnModel.getColumnCount(); column++) {
TableColumn aColumn = columnModel.getColumn(column);
TableCellRenderer renderer = aColumn.getHeaderRenderer();
if (renderer == null) {
renderer = getHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false,
false, -1, column);
int cHeight = comp.getPreferredSize().height;
List<ColumnGroup> groups = getHeader().getColumnGroups(aColumn);
for (ColumnGroup group : groups) {
cHeight += group.getSize(header.getTable()).height;
}
headerHeight = Math.max(headerHeight, cHeight);
}
return headerHeight;
}
#Override
public Dimension getPreferredSize(JComponent c) {
int width = 0;
for (Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) {
TableColumn aColumn = enumeration.nextElement();
width += aColumn.getPreferredWidth();
}
return createHeaderSize(width);
}
private Dimension createHeaderSize(int width) {
TableColumnModel columnModel = header.getColumnModel();
width += columnModel.getColumnMargin() * columnModel.getColumnCount();
if (width > Integer.MAX_VALUE) {
width = Integer.MAX_VALUE;
}
return new Dimension(width, getHeaderHeight());
}
}

Yes, you need to supply your own JTableHeader. The difficult comes in trying to layout it out.
You'll need to look at JTableHeader.getHeaderRect(column), this tells the renderer how to layout the column headers.
You're going to have to take into consideration the height of each column renderer as well as the height of the component you want to use a label renderer (I'd suggest using the Header's column renderer as a bases, but that's up to you)

Take account of space between columns (when more then two columns join to group - right border of group column become invisible).
Here is solution:
public Dimension getSize(JTable table) {
Component comp = renderer.getTableCellRendererComponent(
table, getHeaderValue(), false, false,-1, -1);
int height = comp.getPreferredSize().height;
int width = 0;
Enumeration e = v.elements();
int testNum = 0;
while (e.hasMoreElements()) {
Object obj = e.nextElement();
if (obj instanceof TableColumn) {
TableColumn aColumn = (TableColumn)obj;
width += aColumn.getWidth()-table.getIntercellSpacing().width;
width += margin;
} else {
width += ((ColumnGroup)obj).getSize(table).width-table.getIntercellSpacing().width;
}
}
return new Dimension(width+2*table.getIntercellSpacing().width, height);
}

Related

Jtable with conditional formatting like Excel

Does JTable supports 3 color conditional formatting like excel does.
Example:
I checked on google and all I could find assigning single color at a time to a cell which matches the criteria. I was wondering if I could just provide three colors and Jtable would assign shades of color according to the value of the cell.
Here is one of the ways, how you can do this. Additional classes we can find here.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import static javax.swing.SwingConstants.CENTER;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import general.VerticalTableHeaderCellRenderer;
import java.awt.Color;
import java.util.Random;
import javax.swing.table.TableCellRenderer;
// The class of template for table's presentation of knowledge
//==============================================================================
public class ExcelTable extends JFrame {
public static int rowCount = 1024;
public static int colCount = 1024;
public static int CHLength = 100;
public static int RWLength = 50;
public static int DCW = 20;
// The constructor of this class
//==============================================================================
public ExcelTable() {
super("Draw cell rotate");
setSize(400, 400);
//The abstract model of table's presentation
ListModel lm = new AbstractListModel() {
String[] headers = new String[rowCount];
#Override
public int getSize() {
return headers.length;
}
#Override
public Object getElementAt(int index) {
return headers[index];
}
};
DefaultTableModel dtm = new DefaultTableModel(lm.getSize(), colCount);
JTable table = new JTable(dtm) {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
Component comp = super.prepareRenderer(renderer, row, col);
Object value = getModel().getValueAt(row, col);
setCellSelectionEnabled(true);
// Here you can write you schemes
final Random r = new Random();
Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256), r.nextInt(256));
if (getSelectedRow() != 0) {
if (row % 2 == 0 && col % 2 == 1) {
comp.setBackground(c);
} else if (row % 2 == 1 && row % 2 == 1) {
comp.setBackground(c);
} else {
comp.setBackground(c);
}
} else {
comp.setBackground(Color.white);
}
return comp;
}
};
table.getTableHeader().setDefaultRenderer(new VerticalTableHeaderCellRenderer());
for (int i = 0; i < colCount; i++) {
table.getColumnModel().getColumn(i).setPreferredWidth(DCW);// .setTotalColumnWidth();
}
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setCellSelectionEnabled(true);
// Create header rotation
JList rowHeader = new JList(lm);
// if (fieldlength)
rowHeader.setFixedCellWidth(RWLength); //RowHeaser width
rowHeader.setFixedCellHeight(table.getRowHeight());
//Set render
rowHeader.setCellRenderer(new RowRenderer(table));
//JScrollPane
JScrollPane pane = new JScrollPane(table);
pane.setColumnHeader(new JViewport() {
#Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.height = CHLength; // Col header Height
return d;
}
});
pane.setRowHeaderView(rowHeader);
getContentPane().add(pane, BorderLayout.CENTER);
}
//=========================================
public static void main(String[] args) {
ExcelTable jr = new ExcelTable();
jr.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jr.setVisible(true);
}
}
class RowRenderer extends JLabel implements ListCellRenderer {
public RowRenderer(JTable table) {
JTableHeader header = table.getTableHeader();
setOpaque(true);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
setHorizontalAlignment(CENTER);
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setText((value == null) ? "" : value.toString());
return this;
}
}
OUTPUT:
also:
or
The desired color scheme you must implement into override method:
#Override
public Component prepareRenderer
(TableCellRenderer renderer, int row, int col
) {
Component comp = super.prepareRenderer(renderer, row, col);
Object value = getModel().getValueAt(row, col);
setCellSelectionEnabled(true);
// Here you can write you schemes in RGB
// of course you need to describe it before mathematicaly
// and using variable `row` and `col` you will have coordinates to the cells
final Random r = new Random();
int R = r.nextInt(Math.round(256 / (row + 1)));
int G = r.nextInt(Math.round(256 / (col + 1)));
int B = r.nextInt(Math.round(256 / (row + col + 1)));
Color c = new Color(R, G, B);
if (getSelectedRow() != 0) {
if (row % 2 == 0 && col % 2 == 1) {
comp.setBackground(c);
} else if (row % 2 == 1 && row % 2 == 1) {
comp.setBackground(c);
} else {
comp.setBackground(c);
}
} else {
comp.setBackground(Color.white);
}
return comp;
}
};

Groupable table header with filter below header

Problem
I'd like to create a groupable table header with a filter row below the header.
I guess the straightforward approach would be to include the filter components in the header. The problem is that the components aren't editable.
I searched, but didn't find a good or working approach. The best and working solution I found so far regarding filter components was putting them outside of the table. But when you have a grouped table that just looks and feels ugly. They must be below the header. Putting the filter components in the footer isn't an option either.
I used the groupable table header code form this thread and added a filter component.
The problem is now that when I click on the components, I can't access them. Instead the row sorting is triggered. Even adding a mouse listener to the textfield doesn't help.
Question
Does anyone know how to make the textfields in the table header editable? Or does anyone have a better approach about placing a table filter below the table header?
Code
The code so far:
FilterHeader.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
public class FilterHeader extends JPanel {
public FilterHeader( JTable table, Object value, int columnIndex) {
setLayout( new BorderLayout());
// header
JLabel header = new JLabel();
header.setForeground(table.getTableHeader().getForeground());
header.setBackground(table.getTableHeader().getBackground());
header.setFont(table.getTableHeader().getFont());
header.setHorizontalAlignment(JLabel.CENTER);
header.setText(value.toString());
header.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
add( header, BorderLayout.CENTER);
// append filter components to header
if( columnIndex == 3) {
JComboBox cb = new JComboBox();
cb.setBackground(Color.yellow);
cb.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
cb.setBorder(new EmptyBorder(0, 0, 0, 0));
cb.setForeground(table.getTableHeader().getForeground());
cb.setPreferredSize(new Dimension(0,table.getRowHeight() + 4));
add( cb, BorderLayout.SOUTH);
} else {
JTextField tf = new JTextField( "enter filtertext");
tf.setBackground(Color.yellow);
tf.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
tf.setForeground(table.getTableHeader().getForeground());
tf.setHorizontalAlignment(JLabel.CENTER);
add( tf, BorderLayout.SOUTH);
tf.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("textfield clicked"); // doesn't work
}
});
}
}
}
ColumnGroup.java
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class ColumnGroup {
protected TableCellRenderer renderer;
protected List<TableColumn> columns;
protected List<ColumnGroup> groups;
protected String text;
protected int margin = 0;
public ColumnGroup(String text) {
this(text, null);
}
public ColumnGroup(String text, TableCellRenderer renderer) {
this.text = text;
this.renderer = renderer;
this.columns = new ArrayList<TableColumn>();
this.groups = new ArrayList<ColumnGroup>();
}
public void add(TableColumn column) {
columns.add(column);
}
public void add(ColumnGroup group) {
groups.add(group);
}
/**
* #param column
* TableColumn
*/
public List<ColumnGroup> getColumnGroups(TableColumn column) {
if (!contains(column)) {
return Collections.emptyList();
}
List<ColumnGroup> result = new ArrayList<ColumnGroup>();
result.add(this);
if (columns.contains(column)) {
return result;
}
for (ColumnGroup columnGroup : groups) {
result.addAll(columnGroup.getColumnGroups(column));
}
return result;
}
private boolean contains(TableColumn column) {
if (columns.contains(column)) {
return true;
}
for (ColumnGroup group : groups) {
if (group.contains(column)) {
return true;
}
}
return false;
}
public TableCellRenderer getHeaderRenderer() {
return renderer;
}
public void setHeaderRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
}
public String getHeaderValue() {
return text;
}
public Dimension getSize(JTable table) {
TableCellRenderer renderer = this.renderer;
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(table, getHeaderValue() == null || getHeaderValue().trim().isEmpty() ? " "
: getHeaderValue(), false, false, -1, -1);
int height = comp.getPreferredSize().height;
int width = 0;
for (ColumnGroup columnGroup : groups) {
width += columnGroup.getSize(table).width;
}
for (TableColumn tableColumn : columns) {
width += tableColumn.getWidth();
width += margin;
}
return new Dimension(width, height);
}
public void setColumnMargin(int margin) {
this.margin = margin;
for (ColumnGroup columnGroup : groups) {
columnGroup.setColumnMargin(margin);
}
}
}
GroupableTableHeader.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
#SuppressWarnings("serial")
public class GroupableTableHeader extends JTableHeader {
#SuppressWarnings("unused")
private static final String uiClassID = "GroupableTableHeaderUI";
protected List<ColumnGroup> columnGroups = new ArrayList<ColumnGroup>();
public GroupableTableHeader(TableColumnModel model) {
super(model);
setUI(new GroupableTableHeaderUI());
setReorderingAllowed(false);
// setDefaultRenderer(new MultiLineHeaderRenderer());
}
#Override
public void updateUI() {
setUI(new GroupableTableHeaderUI());
}
#Override
public void setReorderingAllowed(boolean b) {
super.setReorderingAllowed(false);
}
public void addColumnGroup(ColumnGroup g) {
columnGroups.add(g);
}
public List<ColumnGroup> getColumnGroups(TableColumn col) {
for (ColumnGroup group : columnGroups) {
List<ColumnGroup> groups = group.getColumnGroups(col);
if (!groups.isEmpty()) {
return groups;
}
}
return Collections.emptyList();
}
public void setColumnMargin() {
int columnMargin = getColumnModel().getColumnMargin();
for (ColumnGroup group : columnGroups) {
group.setColumnMargin(columnMargin);
}
}
}
GroupableTableHeaderUI.java
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class GroupableTableHeaderUI extends BasicTableHeaderUI {
protected GroupableTableHeader getHeader() {
return (GroupableTableHeader) header;
}
#Override
public void paint(Graphics g, JComponent c) {
Rectangle clipBounds = g.getClipBounds();
if (header.getColumnModel().getColumnCount() == 0) {
return;
}
int column = 0;
Dimension size = header.getSize();
Rectangle cellRect = new Rectangle(0, 0, size.width, size.height);
Map<ColumnGroup, Rectangle> groupSizeMap = new HashMap<ColumnGroup, Rectangle>();
for (Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) {
cellRect.height = size.height;
cellRect.y = 0;
TableColumn aColumn = enumeration.nextElement();
List<ColumnGroup> groups = getHeader().getColumnGroups(aColumn);
int groupHeight = 0;
for (ColumnGroup group : groups) {
Rectangle groupRect = groupSizeMap.get(group);
if (groupRect == null) {
groupRect = new Rectangle(cellRect);
Dimension d = group.getSize(header.getTable());
groupRect.width = d.width;
groupRect.height = d.height;
groupSizeMap.put(group, groupRect);
}
paintCell(g, groupRect, group);
groupHeight += groupRect.height;
cellRect.height = size.height - groupHeight;
cellRect.y = groupHeight;
}
cellRect.width = aColumn.getWidth();
if (cellRect.intersects(clipBounds)) {
paintCell(g, cellRect, column);
}
cellRect.x += cellRect.width;
column++;
}
}
private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
TableCellRenderer renderer = aColumn.getHeaderRenderer();
if (renderer == null) {
// original
renderer = getHeader().getDefaultRenderer();
// modified
renderer = new DefaultTableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
FilterHeader header = new FilterHeader( table, value, column);
return header;
}
};
}
Component c = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false,
-1, columnIndex);
c.setBackground(UIManager.getColor("control"));
rendererPane.paintComponent(g, c, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true);
}
private void paintCell(Graphics g, Rectangle cellRect, ColumnGroup cGroup) {
TableCellRenderer renderer = cGroup.getHeaderRenderer();
if (renderer == null) {
renderer = getHeader().getDefaultRenderer();
}
Component component = renderer.getTableCellRendererComponent(header.getTable(), cGroup.getHeaderValue(), false,
false, -1, -1);
rendererPane
.paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true);
}
private int getHeaderHeight() {
int headerHeight = 0;
TableColumnModel columnModel = header.getColumnModel();
for (int column = 0; column < columnModel.getColumnCount(); column++) {
TableColumn aColumn = columnModel.getColumn(column);
TableCellRenderer renderer = aColumn.getHeaderRenderer();
if (renderer == null) {
renderer = getHeader().getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false,
false, -1, column);
int cHeight = comp.getPreferredSize().height;
List<ColumnGroup> groups = getHeader().getColumnGroups(aColumn);
for (ColumnGroup group : groups) {
cHeight += group.getSize(header.getTable()).height;
}
headerHeight = Math.max(headerHeight, cHeight);
}
return headerHeight;
}
#Override
public Dimension getPreferredSize(JComponent c) {
int width = 0;
for (Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) {
TableColumn aColumn = enumeration.nextElement();
width += aColumn.getPreferredWidth();
}
return createHeaderSize(width);
}
private Dimension createHeaderSize(int width) {
TableColumnModel columnModel = header.getColumnModel();
width += columnModel.getColumnMargin() * columnModel.getColumnCount();
if (width > Integer.MAX_VALUE) {
width = Integer.MAX_VALUE;
}
return new Dimension(width, getHeaderHeight());
}
}
GroupableHeaderExample.java
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
// original from https://stackoverflow.com/questions/21347647/how-to-combine-two-column-headers-in-jtable-in-swings
public class GroupableHeaderExample extends JFrame {
GroupableHeaderExample() {
super( "Groupable Header Example" );
DefaultTableModel dm = new DefaultTableModel();
dm.setDataVector(new Object[][]{
{"1","a","b","c","d","e"},
{"2","f","g","h","i","j"},
{"3","k","l","m","n","o"},
{"4","p","q","r","s","t"}
},
new Object[]{"SNo.","1","2","Native","2","3"});
JTable table = new JTable( dm ) {
protected JTableHeader createDefaultTableHeader() {
return new GroupableTableHeader(columnModel);
}
};
TableColumnModel cm = table.getColumnModel();
ColumnGroup g_name = new ColumnGroup("Name");
g_name.add(cm.getColumn(1));
g_name.add(cm.getColumn(2));
ColumnGroup g_lang = new ColumnGroup("Language");
g_lang.add(cm.getColumn(3));
ColumnGroup g_other = new ColumnGroup("Others");
g_other.add(cm.getColumn(4));
g_other.add(cm.getColumn(5));
g_lang.add(g_other);
GroupableTableHeader header = (GroupableTableHeader)table.getTableHeader();
header.addColumnGroup(g_name);
header.addColumnGroup(g_lang);
JScrollPane scroll = new JScrollPane( table );
getContentPane().add( scroll );
setSize( 400, 120 );
// allow sorting
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(dm);
table.setRowSorter(sorter);
}
public static void main(String[] args) {
GroupableHeaderExample frame = new GroupableHeaderExample();
frame.setSize(1024,768);
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
System.exit(0);
}
});
frame.setVisible(true);
}
}
And a screenshot:
Thank you very much for the help!
Solved it by combining various sources.
One source was this post on StackOverflow, but that solution put the filter only outside of the table.
Another source was the open source version of a TableFilter on coderazzi. That's very awesome, but also very heavy weight for my needs. And doesn't support grouped columns. So all in all what I needed was this piece of code:
JViewport headerViewport = new JViewport() {
#Override
public void setView(Component view) {
if (view instanceof JTableHeader) {
filterHeader.add(view, BorderLayout.NORTH);
super.setView(filterHeader);
}
}
};
scroll.setColumnHeader(headerViewport);
and
private class TableFilterHeader extends JPanel {
public TableFilterHeader(JTableHeader th) {
setLayout(new BorderLayout());
add(new TableFilterRow(th.getTable()), BorderLayout.SOUTH);
}
}
A screenshot:
Interested ones can get the full code from this gist. What's missing is the filter itself, but that's just straightforward: Add a document listener and apply the filter.

Set row height depend on JTextArea height

I have a problem and really don't know how to solve it.
I used some solutions from this forum but they don't work.
This is the piece of code:
package own_components.custom_components;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import own_components.localizable_components.LocalizableComponent;
import localization.GUILocalizationTags;
import localization.LocalizationManager;
public class OutputJTable extends JTable implements CustomComponent
{
private CustomTableModel dataModel = new CustomTableModel();
private List<String[]> data = new ArrayList<String[]>();
private final int COLUMNS_AMOUNT = 3;
private final int _1ST_COL_WIDTH = 25;
private final int _2ST_COL_WIDTH = 45;
private final int _3ND_COL_WIDTH = 505;
public OutputJTable()
{
setModel(dataModel);
setTableProperties();
dataModel.addTableModelListener(new TableModelListener(){
#Override
public void tableChanged(TableModelEvent paramTableModelEvent)
{
fitRowsHeight();
}
});
}
private void setTableProperties()
{
//some properties of table
}
public void setResultOutput(List<String[]> result)
{
data = new ArrayList<String[]>();
data.add(new String[] { "l", "code", "222222222222222222222222222 22ddddddddddddddddddddddddddd22222222222222222222222222222222" });
data.add(new String[] { "l", "code", "sssssssssssssssssssssssssssssss sssssssssssssssssssssssssssssssssssssssssssssssssss222222222" });
dataModel.fireTableDataChanged();
}
private void fitRowsHeight()
{
for (int row = 0; row < getRowCount(); row++)
{
int rowHeight = getRowHeight();
Component comp = prepareRenderer(getCellRenderer(row, 2), row, 2);
rowHeight = Math.max(rowHeight, comp.getSize().height);
setRowHeight(row, rowHeight);
}
}
public int getSelectedRow()
{
return selectedRow;
}
private class CustomTableModel extends AbstractTableModel implements LocalizableComponent
{
private static final long serialVersionUID = -992340559233338699L;
private String[] columnsNames = { "a", "b", "c" };
#Override
public String getColumnName(int paramInt)
{
return columnsNames[paramInt];
}
#Override
public boolean isCellEditable(int paramInt1, int paramInt2)
{
return false;
}
#Override
public int getColumnCount()
{
return COLUMNS_AMOUNT;
}
#Override
public int getRowCount()
{
return data.size();
}
#Override
public String getValueAt(int arg0, int arg1)
{
return data.get(arg0)[arg1];
}
#Override
public void useTranslatedText(String tag)
{
columnsNames[1] = tag;
getColumnModel().getColumn(2).setHeaderValue(tag);
repaint();
}
#Override
public void registerToLocalization(LocalizationManager lm, String key)
{
lm.registerToTranslationList(this, GUILocalizationTags.OUT_TAB_DESCRIPTION);
}
}
private class CustomTableRenderer extends DefaultTableCellRenderer
{
JTextArea cellTemp = new JTextArea();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
cellTemp = new JTextArea(data.get(row)[column]);
cellTemp.setLineWrap(true);
return cellTemp;
}
}
}
This is little bit long but rather simple: my table uses custom cell renderer which contains JTextArea. I use JTA because I need Strings wrapping. After put such JTextAreas I expect to set row heights to highest JTA in a row.
And here is the problem. In code above I expect to receive JTA.height but I still receive "0". The same situation with JTA.getRows().
I really don't understand why. Can anybody explain me what is wrong with this code?
This is working JTable with wrapped strings.
(I used solutions introduced by mKorbel in this thread How to make a JTable column to contain not JTextFields, but JTextAreas)
package own_components.custom_components;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.View;
public class OutputJTable extends JTable
{
private static final long serialVersionUID = 1L;
private List<String[]> data = new ArrayList<String[]>();
private CustomTableModel dataModel = new CustomTableModel();
private final int COLUMNS_AMOUNT = 3;
private final int _1ST_COL_WIDTH = 25;
private final int _2ST_COL_WIDTH = 45;
private final int _3ND_COL_WIDTH = 505;
private int selectedRow = -1;
public OutputJTable()
{
setModel(dataModel);
setDefaultRenderer(Object.class, new CustomTableRenderer());
setTableProperties();
}
/**
* Sets basic table properties.
*/
private void setTableProperties()
{
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
getColumnModel().getColumn(0).setMaxWidth(_1ST_COL_WIDTH);
getColumnModel().getColumn(0).setMinWidth(_1ST_COL_WIDTH);
getColumnModel().getColumn(1).setMaxWidth(_2ST_COL_WIDTH);
getColumnModel().getColumn(1).setMinWidth(_2ST_COL_WIDTH);
getColumnModel().getColumn(2).setMaxWidth(_3ND_COL_WIDTH);
getColumnModel().getColumn(2).setMinWidth(_3ND_COL_WIDTH);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setIntercellSpacing(new Dimension(0, 0));
setShowGrid(false);
}
/**
* Receives data used to modified data showned in table.
* This should be only access point to add data used by data model (which is used by jtable).
*
* #param result
*/
public void setResultOutput(List<String[]> result)
{
data = new ArrayList<String[]>();
data = result;
dataModel.fireTableDataChanged();
}
#Override
public void doLayout()
{
super.doLayout();
for (int row = 0; row < getRowCount(); row++)
{
JTextArea a = (JTextArea) prepareRenderer(getDefaultRenderer(Object.class), row, 2);
int rowHeight = (int) a.getUI().getRootView(a).getView(0).getPreferredSpan(View.Y_AXIS) + getIntercellSpacing().height;
setRowHeight(row, rowHeight);
}
}
/**
* Returns which row is selected. Main purpose of this method is provide data to PrintManager what should be printed.
*/
public int getSelectedRow()
{
return selectedRow;
}
#Override
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
{
if (rowIndex != selectedRow)
{
selectedRow = rowIndex;
}
else
{
selectedRow = -1;
}
super.changeSelection(rowIndex, columnIndex, true, false);
}
/**
* This is model used to fill this table with data.
*/
private class CustomTableModel extends DefaultTableModel implements LocalizableComponent
{
private static final long serialVersionUID = -992340559233338699L;
private String[] columnsNames = { "a", "b", "c" };
#Override
public String getColumnName(int paramInt)
{
return columnsNames[paramInt];
}
#Override
public boolean isCellEditable(int paramInt1, int paramInt2)
{
return false;
}
#Override
public int getColumnCount()
{
return COLUMNS_AMOUNT;
}
#Override
public int getRowCount()
{
return data.size();
}
#Override
public String getValueAt(int arg0, int arg1)
{
return data.get(arg0)[arg1];
}
}
/**
* This class is used to render single cell.
*/
private class CustomTableRenderer extends JTextArea implements TableCellRenderer
{
private final Color SELECTION_BORDER = new Color(200, 200, 200);
private final Color ODD_BACKGR_COLOR = new Color(240, 240, 240);
private final Color EVEN_BACKGR_COLOR = Color.WHITE;
CustomTableRenderer()
{
setLineWrap(true);
setWrapStyleWord(true);
setEditable(false);
setFont(getFont());
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
setText((String) value);
setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
if (isSelected)
{
setBackground(SELECTION_BORDER);
}
else if (row % 2 != 0)
{
setBackground(ODD_BACKGR_COLOR);
}
else
{
setBackground(EVEN_BACKGR_COLOR);
}
return this;
}
}
}
Remarks:
formating of row height is based on third column, if you want to take under consideration all columns, you have to use additional "for" loop in doLayout(),
'dataModel' of this JTable is based on the List 'model',
setResultOutput() expect String[3]
Thanks for everybodys help.
Regards.

How to make row header draggable

Hi I am using a JTable to display data from a file. For this I like to have row headers and column headers. Since row headers are not there I implemented a seprate JTable for it.
But now I like to resize row headers and row grids. Is there anyway I can implement such excel like functionality.
I followed row header functionality from the url:-
http://tips4java.wordpress.com/2008/11/18/row-number-table/ and grid resize from the url:- http://www.jroller.com/santhosh/entry/make_jtable_resiable_better_than
Now after integrating both the codes I sucessfully got the row header and draggable grid.
But now after resizing grids I didn't find a way to make row headers draggable.
Please suggest something to make rowheaders draggable.
**SimpleTableDemo.java**
package com.swing.table;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.table.*;
import java.util.*;
import java.awt.*;
public class SimpleTableDemo extends JPanel {
private boolean DEBUG = false;
private int spacing = 6;
private Map columnSizes = new HashMap();
String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years",
"Vegetarian" };
Object[][] data = {
{
"Kathy",
"Smith",
"SnowboardingXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
new Integer(5), new Boolean(false) },
{ "John", "Doe", "Rowing", new Integer(3), new Boolean(true) },
{ "Sue", "Black", "Knitting", new Integer(2), new Boolean(false) },
{ "Jane", "White", "Speed reading", new Integer(20),
new Boolean(true) },
{ "Joe", "Brown", "Pool", new Integer(10), new Boolean(false) } };
final JTable table = new JTable(data, columnNames);
Panel1 panel;
public SimpleTableDemo() {
super(new GridLayout(0, 1));
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
// table.setFillsViewportHeight(true);
if (DEBUG) {
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
printDebugData(table);
}
});
}
// Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
JTable rowTable = new RowNumberTable(table);
scrollPane.setRowHeaderView(rowTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
rowTable.getTableHeader());
// Add the scroll pane to this panel.
add(scrollPane);
/*
* panel = new Panel1(); Rectangle rect = table.getCellRect(0,0,true);
*
* panel.setX(table.getWidth()); panel.setY(0);
* panel.setWidth(rect.width); panel.setHeight(rect.height);
* panel.setStr(table.getModel().getValueAt(0,0).toString());
* panel.setModel(table);
*
* add(panel);
*/
/*
* final JComboBox jNumberComboBoxSize = new JComboBox();
* jNumberComboBoxSize.setModel(new javax.swing.DefaultComboBoxModel(new
* String[] { "11", "12", "14", "16", "18", "20", "24", "30", "36",
* "48", "72" })); jNumberComboBoxSize.addActionListener(new
* java.awt.event.ActionListener() { public void
* actionPerformed(java.awt.event.ActionEvent evt) {
* jNumberComboBoxSizeActionPerformed(jNumberComboBoxSize); } });
*
* JPanel panel2 = new JPanel(); panel2.add(jNumberComboBoxSize);
*
* add(panel2);
*/
TableRowResizer rowResizer = new TableRowResizer(table);
adjustColumns();
}
private void jNumberComboBoxSizeActionPerformed(
JComboBox jNumberComboBoxSize) {
int fontSize = Integer.parseInt(jNumberComboBoxSize.getSelectedItem()
.toString());
table.setRowHeight(fontSize);
table.setFont(new Font("Serif", Font.BOLD, fontSize));
Rectangle rect = table.getCellRect(0, 0, true);
panel.setX(0);
panel.setY(0);
// panel.setWidth(rect.width);
panel.setHeight(rect.height);
panel.setStr(table.getModel().getValueAt(0, 0).toString());
panel.setModel(table);
panel.repaint();
table.revalidate();
}
private void printDebugData(JTable table) {
int numRows = table.getRowCount();
int numCols = table.getColumnCount();
javax.swing.table.TableModel model = table.getModel();
System.out.println("Value of data: ");
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
System.out.print(" " + model.getValueAt(i, j));
}
System.out.println();
}
System.out.println("--------------------------");
}
/*
* Adjust the widths of all the columns in the table
*/
public void adjustColumns() {
TableColumnModel tcm = table.getColumnModel();
for (int i = 0; i < tcm.getColumnCount(); i++) {
adjustColumn(i);
}
}
/*
* Adjust the width of the specified column in the table
*/
public void adjustColumn(final int column) {
TableColumn tableColumn = table.getColumnModel().getColumn(column);
if (!tableColumn.getResizable())
return;
int columnHeaderWidth = getColumnHeaderWidth(column);
int columnDataWidth = getColumnDataWidth(column);
int preferredWidth = Math.max(columnHeaderWidth, columnDataWidth);
panel.setWidth(preferredWidth);
updateTableColumn(column, preferredWidth);
}
/*
* Calculated the width based on the column name
*/
private int getColumnHeaderWidth(int column) {
TableColumn tableColumn = table.getColumnModel().getColumn(column);
Object value = tableColumn.getHeaderValue();
TableCellRenderer renderer = tableColumn.getHeaderRenderer();
if (renderer == null) {
renderer = table.getTableHeader().getDefaultRenderer();
}
Component c = renderer.getTableCellRendererComponent(table, value,
false, false, -1, column);
return c.getPreferredSize().width;
}
/*
* Calculate the width based on the widest cell renderer for the given
* column.
*/
private int getColumnDataWidth(int column) {
int preferredWidth = 0;
int maxWidth = table.getColumnModel().getColumn(column).getMaxWidth();
for (int row = 0; row < table.getRowCount(); row++) {
preferredWidth = Math.max(preferredWidth,
getCellDataWidth(row, column));
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth)
break;
}
return preferredWidth;
}
/*
* Get the preferred width for the specified cell
*/
private int getCellDataWidth(int row, int column) {
// Inovke the renderer for the cell to calculate the preferred width
TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
Component c = table.prepareRenderer(cellRenderer, row, column);
int width = c.getPreferredSize().width
+ table.getIntercellSpacing().width;
return width;
}
/*
* Update the TableColumn with the newly calculated width
*/
private void updateTableColumn(int column, int width) {
final TableColumn tableColumn = table.getColumnModel()
.getColumn(column);
if (!tableColumn.getResizable())
return;
width += spacing;
// Don't shrink the column width
width = Math.max(width, tableColumn.getPreferredWidth());
columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
table.getTableHeader().setResizingColumn(tableColumn);
tableColumn.setWidth(width);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the content pane.
SimpleTableDemo newContentPane = new SimpleTableDemo();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
class Panel1 extends JPanel {
int x;
int y;
int width;
int height;
String str;
JTable model;
public void setModel(JTable model) {
this.model = model;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setWidth(int w) {
this.width = w;
}
public void setHeight(int h) {
this.height = h;
}
public void setStr(String s) {
this.str = s;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int initX = 0;
for (int row = 0; row < 5; ++row) {
initX = x;
for (int col = 0; col < 5; ++col) {
g.drawRect(x, y, width, height);
g.drawString(model.getModel().getValueAt(row, col).toString(),
x + 10, y + 10);
x = x + width;
}
x = initX;
y = y + height;
}
}
};
**TableRowResizer.java**
package com.swing.table;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.JTable;
import javax.swing.event.MouseInputAdapter;
// #author Santhosh Kumar T - santhosh#in.fiorano.com
public class TableRowResizer extends MouseInputAdapter {
public static Cursor resizeCursor = Cursor
.getPredefinedCursor(Cursor.N_RESIZE_CURSOR);
private int mouseYOffset, resizingRow;
private Cursor otherCursor = resizeCursor;
private JTable table;
public TableRowResizer(JTable table) {
this.table = table;
table.addMouseListener(this);
table.addMouseMotionListener(this);
}
private int getResizingRow(Point p) {
return getResizingRow(p, table.rowAtPoint(p));
}
private int getResizingRow(Point p, int row) {
if (row == -1) {
return -1;
}
int col = table.columnAtPoint(p);
if (col == -1)
return -1;
Rectangle r = table.getCellRect(row, col, true);
r.grow(0, -3);
if (r.contains(p))
return -1;
int midPoint = r.y + r.height / 2;
int rowIndex = (p.y < midPoint) ? row - 1 : row;
return rowIndex;
}
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
resizingRow = getResizingRow(p);
mouseYOffset = p.y - table.getRowHeight(resizingRow);
}
private void swapCursor() {
Cursor tmp = table.getCursor();
table.setCursor(otherCursor);
otherCursor = tmp;
}
public void mouseMoved(MouseEvent e) {
if ((getResizingRow(e.getPoint()) >= 0) != (table.getCursor() == resizeCursor)) {
swapCursor();
}
}
public void mouseDragged(MouseEvent e) {
int mouseY = e.getY();
if (resizingRow >= 0) {
int newHeight = mouseY - mouseYOffset;
if (newHeight > 0)
table.setRowHeight(resizingRow, newHeight);
}
}
}
**RowNumberTable.java**
package com.swing.table;
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
/*
* Use a JTable as a renderer for row numbers of a given main table.
* This table must be added to the row header of the scrollpane that
* contains the main table.
*/
public class RowNumberTable extends JTable implements ChangeListener,
PropertyChangeListener {
private final JTable table;
public RowNumberTable(JTable table) {
this.table = table;
table.addPropertyChangeListener(this);
setFocusable(false);
setAutoCreateColumnsFromModel(false);
updateRowHeight();
updateModel();
updateSelectionModel();
TableColumn column = new TableColumn();
column.setHeaderValue("");
addColumn(column);
column.setCellRenderer(new RowNumberRenderer());
getColumnModel().getColumn(0).setPreferredWidth(50);
setPreferredScrollableViewportSize(getPreferredSize());
getTableHeader().setReorderingAllowed(false);
}
#Override
public void addNotify() {
super.addNotify();
Component c = getParent();
// Keep scrolling of the row table in sync with the main table.
if (c instanceof JViewport) {
JViewport viewport = (JViewport) c;
viewport.addChangeListener(this);
}
}
/*
* Delegate method to main table
*/
#Override
public int getRowCount() {
return table.getRowCount();
}
#Override
public int getRowHeight(int row) {
return table.getRowHeight(row);
}
/*
* This table does not use any data from the main TableModel, so just return
* a value based on the row parameter.
*/
#Override
public Object getValueAt(int row, int column) {
return Integer.toString(row + 1);
}
/*
* Don't edit data in the main TableModel by mistake
*/
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
// implements ChangeListener
public void stateChanged(ChangeEvent e) {
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane) viewport.getParent();
scrollPane.getVerticalScrollBar()
.setValue(viewport.getViewPosition().y);
}
// implements PropertyChangeListener
public void propertyChange(PropertyChangeEvent e) {
// Keep the row table in sync with the main table
if ("rowHeight".equals(e.getPropertyName())) {
updateRowHeight();
}
if ("selectionModel".equals(e.getPropertyName())) {
updateSelectionModel();
}
if ("model".equals(e.getPropertyName())) {
updateModel();
}
}
private void updateRowHeight() {
setRowHeight(table.getRowHeight());
}
private void updateModel() {
setModel(table.getModel());
}
private void updateSelectionModel() {
setSelectionModel(table.getSelectionModel());
}
/*
* Borrow the renderer from JDK1.4.2 table header
*/
private static class RowNumberRenderer extends DefaultTableCellRenderer {
public RowNumberRenderer() {
setHorizontalAlignment(JLabel.CENTER);
}
#Override
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));
}
setText((value == null) ? "" : value.toString());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
}
}

JTable Row selection background problem.

I have a JTable and to set a picture as background in JTable and other properties i used this code.
tblMainView= new JTable(dtModel){
public Component prepareRenderer(TableCellRenderer renderer, int row,
int column)
{
Component c = super.prepareRenderer( renderer, row, column);
// We want renderer component to be transparent so background image
// is visible
if( c instanceof JComponent )
((JComponent)c).setOpaque(false);
return c;
}
ImageIcon image = new ImageIcon( "images/watermark.png" );
public void paint( Graphics g )
{
// First draw the background image - tiled
Dimension d = getSize();
for( int x = 0; x < d.width; x += image.getIconWidth() )
for( int y = 0; y < d.height; y += image.getIconHeight() )
g.drawImage( image.getImage(), x, y, null, null );
// Now let the regular paint code do it's work
super.paint(g);
}
public boolean isCellEditable(int rowIndex, int colIndex) {
return false;
}
public Class getColumnClass(int col){
if (col == 0)
{
return Icon.class;
}else if(col==7){
return String.class;
} else
return String.class;
}
public boolean getScrollableTracksViewportWidth() {
if (autoResizeMode != AUTO_RESIZE_OFF) {
if (getParent() instanceof JViewport) {
return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
}
}
return false;
}
};
tblMainView.setOpaque(false);
Every thing is working correctly. But when i select a row, the row data hides.it shows my row like
i want the result same like this,
dtModel is the deafultTableModel for my JTable named tblMainView
Overriding prepareRenderer() is a recommended way to do custom rendering for an entire table row, but you can't make it do everything. In particular, the default renderer for Icon should do what you want, and there's no reason to override paint(), at all.
Addendum: Looking closer, your selected field appears empty because setOpaque(false) interferes with the optimization mentioned in the DefaultTableCellRenderer API. The example you copied won't work.
For reference, the example below overrides the getColumnClass() of DefaultTableModel to obtain the default renderer for types Icon and Date.
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.Calendar;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
/** #see https://stackoverflow.com/questions/6873665 */
public class JavaGUI extends JPanel {
private static final int ICON_COL = 0;
private static final int DATE_COL = 1;
private static final Icon icon = UIManager.getIcon("Tree.closedIcon");
private final Calendar calendar = Calendar.getInstance();
public JavaGUI() {
CustomModel model = new CustomModel();
JTable table = new JTable(model) {
#Override
public Component prepareRenderer(
TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (isRowSelected(row)) {
c.setBackground(Color.blue);
} else {
c.setBackground(Color.white);
}
return c;
}
};
for (int i = 1; i <= 16; i++) {
model.addRow(newRow(i));
}
this.add(table);
}
private Object[] newRow(int i) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
return new Object[]{icon, calendar.getTime()};
}
private static class CustomModel extends DefaultTableModel {
private final String[] columnNames = {"Icon", "Date"};
#Override
public Class<?> getColumnClass(int col) {
if (col == ICON_COL) {
return Icon.class;
} else if (col == DATE_COL) {
return Date.class;
}
return super.getColumnClass(col);
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col];
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
}
private void display() {
JFrame f = new JFrame("JavaGUI");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new JavaGUI().display();
}
});
}
}

Categories