jtable 到图像的转换未正确发生
我正在尝试从表格创建缓冲图像,当我将表格添加到应用程序框架并设置大小时,我可以正确查看它,但是当我将其转换为图像时,我只能看到表格的第一行其余的在表格之外并且没有标题。
生成表格的代码是
table = new JTable();
String[] table_header = null;
TextAreaRenderer textAreaRenderer = new TextAreaRenderer();
table_model = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
table.setModel(table_model);
table.setSize(300, 700);
JScrollPane pane = new JScrollPane(table);
createTableDataSet(input1, input2, varient, headertype);
TableColumnModel cmodel = table.getColumnModel();
table_header = obtainTableHeader(headertype);
for (int i = 0; i < table_header.length; i++) {
cmodel.getColumn(i).setCellRenderer(textAreaRenderer);
}
return table;
生成图像的代码是:
JTableHeader header =table.getTableHeader();
int w = Math.max(table.getWidth(), header.getWidth());
int h = table.getHeight() + header.getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bi.createGraphics();
header.paint(g2);
g2.translate(0, header.getHeight());
table.paint(g2);
g2.dispose();
try {
ImageIO.write(bi, "png", new File("year.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
表格的图像是
更新 1 :我可以已经找到问题的原因了。我使用以下代码片段来增加单元格的大小,以便将文本包装到单元格中。包括导致问题的代码 私有最终 DefaultTableCellRenderer 渲染器 = new DefaultTableCellRenderer();
// Column heights are placed in this Map
private final Map<JTable, Map<Object, Map<Object, Integer>>> tablecellSizes = new HashMap<JTable, Map<Object, Map<Object, Integer>>>();
/**
* Creates a text area renderer.
*/
public TextAreaRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
}
/**
* Returns the component used for drawing the cell. This method is
* used to configure the renderer appropriately before drawing.
*
* @param table - JTable object
* @param value - the value of the cell to be rendered.
* @param isSelected - isSelected true if the cell is to be rendered with the selection highlighted;
* otherwise false.
* @param hasFocus - if true, render cell appropriately.
* @param row - The row index of the cell being drawn.
* @param column - The column index of the cell being drawn.
* @return - Returns the component used for drawing the cell.
*/
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
// set the Font, Color, etc.
renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
setForeground(renderer.getForeground());
setBackground(renderer.getBackground());
setBorder(renderer.getBorder());
setFont(renderer.getFont());
setText(renderer.getText());
TableColumnModel columnModel = table.getColumnModel();
setSize(columnModel.getColumn(column).getWidth(), 0);
int height_wanted = (int) getPreferredSize().getHeight();
addSize(table, row, column, height_wanted);
height_wanted = findTotalMaximumRowSize(table, row);
if (height_wanted != table.getRowHeight(row)) {
table.setRowHeight(row, height_wanted);
}
return this;
}
/**
* @param table - JTable object
* @param row - The row index of the cell being drawn.
* @param column - The column index of the cell being drawn.
* @param height - Row cell height as int value
* This method will add size to cell based on row and column number
*/
private void addSize(JTable table, int row, int column, int height) {
Map<Object, Map<Object, Integer>> rowsMap = tablecellSizes.get(table);
if (rowsMap == null) {
tablecellSizes.put(table, rowsMap = new HashMap<Object, Map<Object, Integer>>());
}
Map<Object, Integer> rowheightsMap = rowsMap.get(row);
if (rowheightsMap == null) {
rowsMap.put(row, rowheightsMap = new HashMap<Object, Integer>());
}
rowheightsMap.put(column, height);
}
/**
* Look through all columns and get the renderer. If it is
* also a TextAreaRenderer, we look at the maximum height in
* its hash table for this row.
*
* @param table -JTable object
* @param row - The row index of the cell being drawn.
* @return row maximum height as integer value
*/
private int findTotalMaximumRowSize(JTable table, int row) {
int maximum_height = 0;
Enumeration<TableColumn> columns = table.getColumnModel().getColumns();
while (columns.hasMoreElements()) {
TableColumn tc = columns.nextElement();
TableCellRenderer cellRenderer = tc.getCellRenderer();
if (cellRenderer instanceof TextAreaRenderer) {
TextAreaRenderer tar = (TextAreaRenderer) cellRenderer;
maximum_height = Math.max(maximum_height,
tar.findMaximumRowSize(table, row));
}
}
return maximum_height;
}
/**
* This will find the maximum row size
*
* @param table - JTable object
* @param row - The row index of the cell being drawn.
* @return row maximum height as integer value
*/
private int findMaximumRowSize(JTable table, int row) {
Map<Object, Map<Object, Integer>> rows = tablecellSizes.get(table);
if (rows == null) return 0;
Map<Object, Integer> rowheights = rows.get(row);
if (rowheights == null) return 0;
int maximum_height = 0;
for (Map.Entry<Object, Integer> entry : rowheights.entrySet()) {
int cellHeight = entry.getValue();
maximum_height = Math.max(maximum_height, cellHeight);
}
return maximum_height;
}
这导致单元格无法正确显示。一旦我删除此代码,该表就会通过包含 kleopatra 的代码正确生成。但我遇到了单元格中自动换行的问题。
谢谢, Bhavya
PS 当在我的代码中使用 new JTable(row,fields) 创建表对象时,我使用了上面相同的代码来生成图像,序列化的哈希图被读取并插入到 table_model 中
I am trying to create a buffered image from a table, when i add the table to a application frame and set the size I am able to view it properly but when I convert it into an image I can only see the first row with the table and the rest outside the table and without the header.
The code generate the table is
table = new JTable();
String[] table_header = null;
TextAreaRenderer textAreaRenderer = new TextAreaRenderer();
table_model = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
table.setModel(table_model);
table.setSize(300, 700);
JScrollPane pane = new JScrollPane(table);
createTableDataSet(input1, input2, varient, headertype);
TableColumnModel cmodel = table.getColumnModel();
table_header = obtainTableHeader(headertype);
for (int i = 0; i < table_header.length; i++) {
cmodel.getColumn(i).setCellRenderer(textAreaRenderer);
}
return table;
The code to generate the image is :
JTableHeader header =table.getTableHeader();
int w = Math.max(table.getWidth(), header.getWidth());
int h = table.getHeight() + header.getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bi.createGraphics();
header.paint(g2);
g2.translate(0, header.getHeight());
table.paint(g2);
g2.dispose();
try {
ImageIO.write(bi, "png", new File("year.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The image of the table is
update 1 :I may have found the cause of the problem . I am using the following code snippet in order to increase the size of the cell so that the text gets wrapped into the cell. Including the code which is causing the problem
private final DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
// Column heights are placed in this Map
private final Map<JTable, Map<Object, Map<Object, Integer>>> tablecellSizes = new HashMap<JTable, Map<Object, Map<Object, Integer>>>();
/**
* Creates a text area renderer.
*/
public TextAreaRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
}
/**
* Returns the component used for drawing the cell. This method is
* used to configure the renderer appropriately before drawing.
*
* @param table - JTable object
* @param value - the value of the cell to be rendered.
* @param isSelected - isSelected true if the cell is to be rendered with the selection highlighted;
* otherwise false.
* @param hasFocus - if true, render cell appropriately.
* @param row - The row index of the cell being drawn.
* @param column - The column index of the cell being drawn.
* @return - Returns the component used for drawing the cell.
*/
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
// set the Font, Color, etc.
renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
setForeground(renderer.getForeground());
setBackground(renderer.getBackground());
setBorder(renderer.getBorder());
setFont(renderer.getFont());
setText(renderer.getText());
TableColumnModel columnModel = table.getColumnModel();
setSize(columnModel.getColumn(column).getWidth(), 0);
int height_wanted = (int) getPreferredSize().getHeight();
addSize(table, row, column, height_wanted);
height_wanted = findTotalMaximumRowSize(table, row);
if (height_wanted != table.getRowHeight(row)) {
table.setRowHeight(row, height_wanted);
}
return this;
}
/**
* @param table - JTable object
* @param row - The row index of the cell being drawn.
* @param column - The column index of the cell being drawn.
* @param height - Row cell height as int value
* This method will add size to cell based on row and column number
*/
private void addSize(JTable table, int row, int column, int height) {
Map<Object, Map<Object, Integer>> rowsMap = tablecellSizes.get(table);
if (rowsMap == null) {
tablecellSizes.put(table, rowsMap = new HashMap<Object, Map<Object, Integer>>());
}
Map<Object, Integer> rowheightsMap = rowsMap.get(row);
if (rowheightsMap == null) {
rowsMap.put(row, rowheightsMap = new HashMap<Object, Integer>());
}
rowheightsMap.put(column, height);
}
/**
* Look through all columns and get the renderer. If it is
* also a TextAreaRenderer, we look at the maximum height in
* its hash table for this row.
*
* @param table -JTable object
* @param row - The row index of the cell being drawn.
* @return row maximum height as integer value
*/
private int findTotalMaximumRowSize(JTable table, int row) {
int maximum_height = 0;
Enumeration<TableColumn> columns = table.getColumnModel().getColumns();
while (columns.hasMoreElements()) {
TableColumn tc = columns.nextElement();
TableCellRenderer cellRenderer = tc.getCellRenderer();
if (cellRenderer instanceof TextAreaRenderer) {
TextAreaRenderer tar = (TextAreaRenderer) cellRenderer;
maximum_height = Math.max(maximum_height,
tar.findMaximumRowSize(table, row));
}
}
return maximum_height;
}
/**
* This will find the maximum row size
*
* @param table - JTable object
* @param row - The row index of the cell being drawn.
* @return row maximum height as integer value
*/
private int findMaximumRowSize(JTable table, int row) {
Map<Object, Map<Object, Integer>> rows = tablecellSizes.get(table);
if (rows == null) return 0;
Map<Object, Integer> rowheights = rows.get(row);
if (rowheights == null) return 0;
int maximum_height = 0;
for (Map.Entry<Object, Integer> entry : rowheights.entrySet()) {
int cellHeight = entry.getValue();
maximum_height = Math.max(maximum_height, cellHeight);
}
return maximum_height;
}
This is causing the cell not to be displayed properly. Once I remove this code the table is beig generated properly by including kleopatra's code. But I am stuck with the problem of word wrap in the cell.
Thanks,
Bhavya
P.S. I have used the same code above to generate an image when the table object is created using new JTable(row,fields) in my code the serialized hashmap is read and inserted into the table_model
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
基本上,您必须通过设置它们的大小(使用下面的首选项)来为要绘制到图像的所有组件(在本例中是表和tableHeader)进行布局工作。
顺便说一句,添加到 JScrollPane 没有帮助(如您所见),除非实现了窗格 - 添加标题是由 addNotify 中的表完成的。
编辑:对 TextAreaRenderer 的评论
一般规则是永远不要更改渲染器的 getXXRendererComponent 中的调用表,作为参数给出的表严格地被视为只读。违反规则可能会导致丑陋的循环(在绘制时设置新的 rowHeight 会触发新的绘制请求)或伪像(无法保证何时调用渲染器,因此可能已设置或未设置正确的 rowheight),如您在此处看到的。
而是在外面的某个地方进行测量。在检测到可能导致更新大小的变化(模型中的 fi)时,遍历行,测量其所有单元格并更新到最大。只需从渲染器中提取所有大小调整代码即可。
Basically, you have to do the layout work for all components you want to paint to the image, that is in this case both the table and the tableHeader, by setting their sizes (below the pref is used).
BTW, adding to a JScrollPane is not helpful (as you have seen), except when the pane is realized - adding the header is done by the table in addNotify.
Edit: comment on TextAreaRenderer
The general rule is to never-ever-ever change the calling table in the renderer's getXXRendererComponent, the table given as parameter is to be regarded read-only, strictly. Breaking the rule can lead to ugly loops (setting a new rowHeight while painting triggers a new painting request) or artefacts (there is no guarantee when the renderer is called, so the correct rowheight might or not have been set) as you see here.
Instead do the measuring somewhere outside. On detecting a change (f.i. in the model) which might lead to updating the sizes, walk the rows, measure all its cells and update to the largest. Simply extract all your sizing code from the renderer.
我在这里可以看到一些问题。
在绘制图像时,您应该使用 printAll 而不是 Paint。
表格的高度是在调用 pack 方法时设置的,但这是在填充表格之前。如果您在生成表后立即创建图像,则可能无法设置大小。您应该在打包框架之前填充表格 - 这应该确保在需要时可以使用尺寸。编辑:在代码更改之后,我建议删除滚动窗格(如 kleopatra 建议的那样),然后使用 printAll。 Paint 不应用于图像,因为它可以使用双缓冲。要查看标题,您需要使用 kleopatra 提供的代码设置其大小。标头的大小与表无关,因此在表上调用 setSize 不会更改标头。
There are a few issues I can see here.
You should use printAll rather than paint when drawing to the image.
The height of the table is set when the pack method is called, but this is before the table is populated. If you are creating the image immediately after generating the table then the size may not be set. You should populate the table before you pack the frame - that should ensure the size is available when you need it.EDIT: Following your code change I would suggest removing the scroll pane (as kleopatra suggested) and then using printAll. paint should not be used for images as it can use double buffering. To see the header you will need to set its size using the code provided by kleopatra. The header's size is independent of the table so calling setSize on the table does not alter the header.
我浏览了这个位置的帖子 截断的 JTable 打印输出 并在该位置包含了答案现在似乎工作正常。
感谢您的帮助
I went through the post at this location Truncated JTable print output and included the answer at that location it seems to be working fine now.
Thank you for your help