I am writing one application in which I have to draw JTable component on a canvas. But after my several attempts still unable to draw a completely perfect picture of a JTabl
Several problems are apparent:
You appear to be creating your own table view using the geometry of an exiting JTable
; those sizes may not be valid until after pack()
.
You loop through the columns in adjustColumns
, but only the last column width is set in panel
, which then becomes the constant width seen in your table.
Your implementation will scale poorly compared JTable
itself, which uses flyweight rendering, illustrated here.
Your panel
disappears when the frame is resized; you should either call repaint
explicitly, listen to the TableModel
, or use JTable
itself.
Since Java 5, autoboxing allows the following; compare:
{"John", "Doe", "Rowing", new Integer(3), new Boolean(true)}
{"John", "Doe", "Rowing", 3, true}
Don't replace the content pane; add()
your panel to it; compare:
frame.setContentPane(newContentPane);
frame.add(newContentPane);
Your use of GridLayout(3,0)
suggests a misunderstanding; to get an arbitrary number of rows in one column use GridLayout(0, 1)
.
As you extend JPanel
, note that "Swing programs should override paintComponent()
instead of overriding paint()
;" see also Painting in AWT and Swing: The Paint Methods.
I got success in mapping one to one drawing using the below code:-
Panel1.java
package com.swing.data;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import javax.swing.JPanel;
import javax.swing.JTable;
class Panel1 extends JPanel
{
int x;
int y;
int width;
int height;
String str;
JTable model;
Font font;
public Font getFont() {
return font;
}
public void setFont(Font font) {
this.font = font;
}
public void setModel(JTable model)
{
this.model = model;
}
public JTable getModel()
{
return 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 paint(Graphics g)
{
super.paint(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);
// String str = model.getModel().getValueAt(row, col).toString();
// int xloc = (x+10);
// int yloc = y +10;
//// System.out.println("xloc : "+xloc);
//// System.out.println("yloc : "+yloc);
//// System.out.println("width : "+width);
//// System.out.println("height : "+height);
//// System.out.println("str : "+str);
//
// g.drawString(model.getModel().getValueAt(row,col).toString(),x + 10,y + 10);
// x = x + width;
// }
// x = initX;
// y = y + height;
//
// }
System.out.println("Inside paint() >>>>>>>>>>>>>>>>>>>>>");
FontMetrics fm = g.getFontMetrics(font);
JTable table = getModel();
int columnCount = table.getModel().getColumnCount();
int rowCount = table.getModel().getRowCount();
int yLoc =10;
int rowHeight = 0 ;
int columnWidth = 0 ;
double w = 0;
double h = 0;
FontRenderContext frc = fm.getFontRenderContext();
g.setFont(font);
for(int r = 0 ; r < rowCount; r++)
{
int xLoc = 0 ;
int yPad = 0;
for(int c= 0 ; c< columnCount; c++)
{
Rectangle rect = table.getCellRect(r, c, true);
String displayString = table.getValueAt(r, c).toString();
columnWidth = rect.width;
rowHeight = rect.height;
w = (double)font.getStringBounds(displayString, frc).getWidth();
h = (double)font.getStringBounds(displayString, frc).getHeight();
//yPad = (int) Math.ceil((rowHeight - h)/2);
yPad = Math.abs((int)(rowHeight - h)/2);
System.out.println("displayString ::"+displayString + "rowHeight:" + rowHeight +"String height:" + h+"yPad:"+yPad +"xLoc:"+xLoc+"yLoc:"+yLoc);
g.drawString(displayString, xLoc , yLoc + rowHeight - yPad);
g.drawRect(xLoc, yLoc, columnWidth, rowHeight);
xLoc+= columnWidth + table.getIntercellSpacing().width;
}
yLoc+= rowHeight + table.getIntercellSpacing().height;
}
}
}
Thanks
An alternative is to render the table as HTML in a JLabel
.
import java.awt.*;
import javax.swing.*;
public class HTMLTableDemo {
HTMLTableDemo() {
StringBuilder sb = new StringBuilder();
sb.append("<html><body><table border=1>");
sb.append("<tr>");
for ( String columnName : columnNames ) {
sb.append("<th>");
sb.append(columnName);
sb.append("</th>");
}
sb.append("</tr>");
for (Object[] row : data) {
sb.append("<tr>");
for (Object value : row) {
sb.append("<td>");
sb.append(value);
sb.append("</td>");
}
sb.append("</tr>");
}
sb.append("</table>");
JLabel html = new JLabel(sb.toString());
JOptionPane.showMessageDialog(null, html);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
new HTMLTableDemo();
}
};
SwingUtilities.invokeLater(r);
}
String[] columnNames = {
"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"
};
Object[][] data = {
{"Kathy", "Smith", "Snowboarding", 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)}
};
}
For rendering it to a Graphics
instance, see the LabelRenderTest.java
source on this answer.