The goal to write the values of columns into JTable vertically. I read about DefaultTableCellRenderer
, VerticalTableHeaderCellRenderer()
but cannot implement it. Here is my code:
//=========================================================
private JScrollPane getTablePane() {
if (tablePane == null) {
tablePane = new JScrollPane();
tablePane.setRowHeaderView(getTableDictionary());
tablePane.setViewportView(getTableDictionary());
}
return tablePane;
}
//=============================================================
private JTable getTableDictionary(){
if (table == null) {
rowVector = new String[colCount];
for(int i=0; i<colCount;i++) {rowVector[i]="";}
data = new DefaultTableModel(rowVector, 0);
for (int i = 0; i < rowCount; i++) { data.addRow(rowVector); }
table = new JTable(data);
table.getTableHeader().setDefaultRenderer(new VerticalTableHeaderCellRenderer());
for(int i=1; i<colCount; i++) { table.getColumnModel().getColumn(i).setPreferredWidth(withCol);}
table.setSelectionForeground(Color.BLACK);
table.setSelectionBackground(Color.YELLOW);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setAutoscrolls(true);
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(true);
/* DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
int bg = table.getTableHeader().getBackground().getRGB();
defaultTableCellRenderer.setBackground(Color.getHSBColor(125, 125, 125)); //задаем цвет столбца
table.getColumnModel().getColumn(0).setCellRenderer(defaultTableCellRenderer);
*/
return table;
}
Where is my mistake? Thank you
I read more resources and I found a decision, it works. I need to implement a render for that and call it when I am locating the table on the JScrollPane. It means that column header is processing apart from a JTable
using datamodel
. Also, I can define the height of the columns.
private JScrollPane getTablePane() {
if (tablePane == null) {
tablePane = new JScrollPane();
tablePane.setRowHeaderView(getTableDictionary());
tablePane.setViewportView(getTableDictionary());
tablePane.setColumnHeader(new JViewport() {
@Override public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.height = rowColumnHeigth; // Col header Height
return d;
}
});
}
return tablePane;
}
Also, I need for that additional classes:
/**
* @(#)DefaultTableHeaderCellRenderer.java 1.0 02/24/09
*/
import java.awt.Component;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
/**
* A default cell renderer for a JTableHeader.
* <P>
* DefaultTableHeaderCellRenderer attempts to provide identical behavior to the
* renderer which the Swing subsystem uses by default, the Sun proprietary
* class sun.swing.table.DefaultTableCellHeaderRenderer.
* <P>
* To apply any desired customization, DefaultTableHeaderCellRenderer may be
* suitably extended.
*
* @author Darryl
*/
public class DefaultTableHeaderCellRenderer extends DefaultTableCellRenderer {
/**
* Constructs a <code>DefaultTableHeaderCellRenderer</code>.
* <P>
* The horizontal alignment and text position are set as appropriate to a
* table header cell, and the opaque property is set to false.
*/
public DefaultTableHeaderCellRenderer() {
setHorizontalAlignment(CENTER);
setHorizontalTextPosition(LEFT);
setVerticalAlignment(BOTTOM);
setOpaque(false);
}
/**
* Returns the default table header cell renderer.
* <P>
* If the column is sorted, the approapriate icon is retrieved from the
* current Look and Feel, and a border appropriate to a table header cell
* is applied.
* <P>
* Subclasses may overide this method to provide custom content or
* formatting.
*
* @param table the <code>JTable</code>.
* @param value the value to assign to the header cell
* @param isSelected This parameter is ignored.
* @param hasFocus This parameter is ignored.
* @param row This parameter is ignored.
* @param column the column of the header cell to render
* @return the default table header cell renderer
*/
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
JTableHeader tableHeader = table.getTableHeader();
if (tableHeader != null) {
setForeground(tableHeader.getForeground());
}
setIcon(getIcon(table, column));
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
/**
* Overloaded to return an icon suitable to the primary sorted column, or null if
* the column is not the primary sort key.
*
* @param table the <code>JTable</code>.
* @param column the column index.
* @return the sort icon, or null if the column is unsorted.
*/
protected Icon getIcon(JTable table, int column) {
SortKey sortKey = getSortKey(table, column);
if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) {
switch (sortKey.getSortOrder()) {
case ASCENDING:
return UIManager.getIcon("Table.ascendingSortIcon");
case DESCENDING:
return UIManager.getIcon("Table.descendingSortIcon");
}
}
return null;
}
/**
* Returns the current sort key, or null if the column is unsorted.
*
* @param table the table
* @param column the column index
* @return the SortKey, or null if the column is unsorted
*/
protected SortKey getSortKey(JTable table, int column) {
RowSorter rowSorter = table.getRowSorter();
if (rowSorter == null) {
return null;
}
List sortedColumns = rowSorter.getSortKeys();
if (sortedColumns.size() > 0) {
return (SortKey) sortedColumns.get(0);
}
return null;
}
}
Also:
/**
* @(#)VerticalLabelUI.java 1.0 02/18/09
*/
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicLabelUI;
/**
* A UI delegate for JLabel that rotates the label 90є
* <P>
* Extends {@link BasicLabelUI}.
* <P>
* The only difference between the appearance of labels in the Basic and Metal
* L&Fs is the manner in which diabled text is painted. As VerticalLabelUI
* does not override the method paintDisabledText, this class can be adapted
* for Metal L&F by extending MetalLabelUI instead of BasicLabelUI.
* <P>
* No other changes are required.
*
* @author Darryl
*/
public class VerticalLabelUI extends BasicLabelUI {
private boolean clockwise = false;
// see comment in BasicLabelUI
Rectangle verticalViewR = new Rectangle();
Rectangle verticalIconR = new Rectangle();
Rectangle verticalTextR = new Rectangle();
protected static VerticalLabelUI verticalLabelUI =
new VerticalLabelUI();
private final static VerticalLabelUI SAFE_VERTICAL_LABEL_UI =
new VerticalLabelUI();
/**
* Constructs a <code>VerticalLabelUI</code> with the default anticlockwise
* rotation
*/
public VerticalLabelUI() {
}
/**
* Constructs a <code>VerticalLabelUI</code> with the desired rotation.
* <P>
* @param clockwise true to rotate clockwise, false for anticlockwise
*/
public VerticalLabelUI(boolean clockwise) {
this.clockwise = clockwise;
}
/**
* @see ComponentUI#createUI(javax.swing.JComponent)
*/
public static ComponentUI createUI(JComponent c) {
if (System.getSecurityManager() != null) {
return SAFE_VERTICAL_LABEL_UI;
} else {
return verticalLabelUI;
}
}
/**
* Overridden to always return -1, since a vertical label does not have a
* meaningful baseline.
*
* @see ComponentUI#getBaseline(JComponent, int, int)
*/
@Override
public int getBaseline(JComponent c, int width, int height) {
super.getBaseline(c, width, height);
return -1;
}
/**
* Overridden to always return Component.BaselineResizeBehavior.OTHER,
* since a vertical label does not have a meaningful baseline
*
* @see ComponentUI#getBaselineResizeBehavior(javax.swing.JComponent)
*/
@Override
public Component.BaselineResizeBehavior getBaselineResizeBehavior(
JComponent c) {
super.getBaselineResizeBehavior(c);
return Component.BaselineResizeBehavior.OTHER;
}
/**
* Transposes the view rectangles as appropriate for a vertical view
* before invoking the super method and copies them after they have been
* altered by {@link SwingUtilities#layoutCompoundLabel(FontMetrics, String,
* Icon, int, int, int, int, Rectangle, Rectangle, Rectangle, int)}
*/
@Override
protected String layoutCL(JLabel label, FontMetrics fontMetrics,
String text, Icon icon, Rectangle viewR, Rectangle iconR,
Rectangle textR) {
verticalViewR = transposeRectangle(viewR, verticalViewR);
verticalIconR = transposeRectangle(iconR, verticalIconR);
verticalTextR = transposeRectangle(textR, verticalTextR);
text = super.layoutCL(label, fontMetrics, text, icon,
verticalViewR, verticalIconR, verticalTextR);
viewR = copyRectangle(verticalViewR, viewR);
iconR = copyRectangle(verticalIconR, iconR);
textR = copyRectangle(verticalTextR, textR);
return text;
}
/**
* Transforms the Graphics for vertical rendering and invokes the
* super method.
*/
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D) g.create();
if (clockwise) {
g2.rotate(Math.PI / 2, c.getSize().width / 2, c.getSize().width / 2);
} else {
g2.rotate(-Math.PI / 2, c.getSize().height / 2, c.getSize().height / 2);
}
super.paint(g2, c);
}
/**
* Returns a Dimension appropriate for vertical rendering
*
* @see ComponentUI#getPreferredSize(javax.swing.JComponent)
*/
@Override
public Dimension getPreferredSize(JComponent c) {
return transposeDimension(super.getPreferredSize(c));
}
/**
* Returns a Dimension appropriate for vertical rendering
*
* @see ComponentUI#getMaximumSize(javax.swing.JComponent)
*/
@Override
public Dimension getMaximumSize(JComponent c) {
return transposeDimension(super.getMaximumSize(c));
}
/**
* Returns a Dimension appropriate for vertical rendering
*
* @see ComponentUI#getMinimumSize(javax.swing.JComponent)
*/
@Override
public Dimension getMinimumSize(JComponent c) {
return transposeDimension(super.getMinimumSize(c));
}
private Dimension transposeDimension(Dimension from) {
return new Dimension(from.height, from.width + 2);
}
private Rectangle transposeRectangle(Rectangle from, Rectangle to) {
if (to == null) {
to = new Rectangle();
}
to.x = from.y;
to.y = from.x;
to.width = from.height;
to.height = from.width;
return to;
}
private Rectangle copyRectangle(Rectangle from, Rectangle to) {
if (to == null) {
to = new Rectangle();
}
to.x = from.x;
to.y = from.y;
to.width = from.width;
to.height = from.height;
return to;
}
}
Also:
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.Icon;
import javax.swing.JTable;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.UIManager;
/**
* A renderer for a JTableHeader with text rotated 90В° counterclockwise.
* <P>
* Extends {@link DefaultTableHeaderCellRenderer}.
*
* @see VerticalLabelUI
* @author Darryl
*/
public class VerticalTableHeaderCellRenderer
extends DefaultTableHeaderCellRenderer {
/**
* Constructs a <code>VerticalTableHeaderCellRenderer</code>.
* <P>
* The horizontal and vertical alignments and text positions are set as
* appropriate to a vertical table header cell.
*/
public VerticalTableHeaderCellRenderer() {
setHorizontalAlignment(LEFT);
setHorizontalTextPosition(CENTER);
setVerticalAlignment(CENTER);
setVerticalTextPosition(TOP);
setUI(new VerticalLabelUI());
}
/**
* Overridden to return a rotated version of the sort icon.
*
* @param table the <code>JTable</code>.
* @param column the colummn index.
* @return the sort icon, or null if the column is unsorted.
*/
@Override
protected Icon getIcon(JTable table, int column) {
SortKey sortKey = getSortKey(table, column);
if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) {
SortOrder sortOrder = sortKey.getSortOrder();
switch (sortOrder) {
case ASCENDING:
return VerticalSortIcon.ASCENDING;
case DESCENDING:
return VerticalSortIcon.DESCENDING;
}
}
return null;
}
/**
* An icon implementation to paint the contained icon rotated 90В° clockwise.
* <P>
* This implementation assumes that the L&F provides ascending and
* descending sort icons of identical size.
*/
private enum VerticalSortIcon implements Icon {
ASCENDING(UIManager.getIcon("Table.ascendingSortIcon")),
DESCENDING(UIManager.getIcon("Table.descendingSortIcon"));
private final Icon icon;// = ;
private VerticalSortIcon(Icon icon) {
this.icon = icon;
}
/**
* Paints an icon suitable for the header of a sorted table column,
* rotated by 90В° clockwise. This rotation is applied to compensate
* the rotation already applied to the passed in Graphics reference
* by the VerticalLabelUI.
* <P>
* The icon is retrieved from the UIManager to obtain an icon
* appropriate to the L&F.
*
* @param c the component to which the icon is to be rendered
* @param g the graphics context
* @param x the X coordinate of the icon's top-left corner
* @param y the Y coordinate of the icon's top-left corner
*/
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
int maxSide = Math.max(getIconWidth(), getIconHeight()+(Integer)getIconHeight()/4);
Graphics2D g2 = (Graphics2D) g.create(x, y, maxSide, maxSide);
g2.rotate((Math.PI / 2));
g2.translate(0, -maxSide);
icon.paintIcon(c, g2, 0, 0);
g2.dispose();
}
/**
* Returns the width of the rotated icon.
*
* @return the <B>height</B> of the contained icon
*/
@Override
public int getIconWidth() {
return icon.getIconHeight();
}
/**
* Returns the height of the rotated icon.
*
* @return the <B>width</B> of the contained icon
*/
@Override
public int getIconHeight() {
return icon.getIconWidth();
}
}
}
It works fine for me. Thank you! Also, it looks like: