JTable set column width not working - java

I am trying to set column width to the length of the column name. My problem is, I am not able to set it. When I use the following code the table is becoming like this,
tableA.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for(int i = 0; i < tableA.getColumnCount(); i++) {
int columnLength = (modelA.getColumnName(i)).length();
tableA.getColumnModel().getColumn(i).setPreferredWidth(columnLength);
// tableA.getColumnModel().getColumn(i).setMinWidth(columnLength);
// tableA.getColumnModel().getColumn(i).setMaxWidth(columnLength);
}
I am getting the column length correctly from my table model.
When I use the above code the table is getting packed like this,
I am not able to understand where I am doing wrong.

As Dan has pointed out, you need to calculate the actual width of the column name based on the Font that is being used.
Something like:
String name = modelA.getColumnName(i);
Font f = tableA.getFont();
FontMetrics fm = tableA.getFontMetrics(f);
int width = fm.stringWidth(name);
tableA.getColumnModel().getColumn(i).setPreferredWidth(width);
Note that this is an extremely abbreviated example.
If you want to get it completely correct, you will need to query each column's renderer for the Font and the FontMetrics in order to get the correct values.
If all your renderers use the same font as the JTable, then this should be OK.

The setPreferredWidth expects a value in pixels while the length of the column name is the length of a String (number of characters in a String).

If you do not mind using SwingX, you can use the TableColumnExt#setPrototypeValue method which allows you to set a 'prototype' value which will be used to determine the column width.

columnLength == number or columns from ColumnModel,
standard size is 80pixels
minimum columns size is at 10pixels
see How to get/set PreferredSize

Related

Java - getting/setting line height of JTextPane with content type "text/html"

I have a JTextPane with content type "text/html". It is integrated in a JScrollPane.
The user can scroll down in this JTextPane and hits a button. At this moment I want to compute the topmost actual visible line of the JTextPane!
What I found in another post here where these lines:
public Integer getActualDisplayedRows() {
int y1 = jtextpane.getVisibleRect().y;
int lineHeight = jtextpane.getFontMetrics(jtextpane.getFont()).getHeight();
int topMostRow = (int) Math.ceil((double) y1 / lineHeight);
return topMostRow;
}
But this does not compute correct.. The number in lineHeight is too small. So, if I scroll to the 20th row -for example- the method returns more then 20..
I tried to set the height of the line via stylesheet (like here):
StyleSheet sh = editorKit.getStyleSheet();
sh.addRule("body {line-height: 50px}");
But doesn't matter what pixel number I set there, the resulting JTextPane has always the same height (and I am using the body tag)..
Do you have any suggestions??
Thank you very much for your help!
If I understand your requirement you just want to know the line number at the top of the viewport?
Here is some code for getting the line at the caret position:
public static int getLineAtCaret(JTextComponent component)
{
int caretPosition = component.getCaretPosition();
Element root = component.getDocument().getDefaultRootElement();
return root.getElementIndex( caretPosition ) + 1;
}
Don't know if this will work for HTML with all kinds of weird tags with images and tables etc. In this case I'm not sure what the meaning of "line" would be.
Now obviously the caret will not be at the top of the viewport, so you need to modify the logic to get an "offset" of the text at the top of the viewport.
So you should be able to use the viewToModel(...) method of the text pane. Something like:
int y = textPane.getVisibleRect().y;
Point p = new Point(5, y);
int offset = textPane.viewToModel( p );

Trigger the update of a TableView's CellValue without changing the value

Each row contains three cells with RGB values. I use these RGB values to set the background of another cell in the same row. On the cells that need to have the background colored I have a callback that picks up the RGB values and sets the background perfectly. So the whole TableView looks exactly as I needed. I have a color picker and this picker needs to update the selected row containing the three RGB values. I'm able to set the new three RGB values but I also need the cell with the colored background to updated itself to the new RGB values. In the code below I have found a way to do this but I believe this is rather ugly.
#FXML void handleColorPicker(ActionEvent event)
{
int r = (int) (comColorPicker.getValue().getRed()*255);
int g = (int) (comColorPicker.getValue().getGreen()*255);
int b = (int) (comColorPicker.getValue().getBlue()*255);
ComTableView.getSelectionModel().getSelectedItem().setRCom(r);
ComTableView.getSelectionModel().getSelectedItem().setGCom(g);
ComTableView.getSelectionModel().getSelectedItem().setBCom(b);
// we need to kick the cell value so it updates also the background color so we clear and rewrite the text string
String currentName = ComTableView.getSelectionModel().getSelectedItem().getCommodityName();
ComTableView.getSelectionModel().getSelectedItem().setCommodityName(" ");
ComTableView.getSelectionModel().getSelectedItem().setCommodityName(currentName);
}
The above code's last three lines trigger the cell's updateItem but I think I'm doing this in an ugly way. I'm wondering, is there a better way to do it?
There are two ways of doing this:
Use JavaFX property value extractors
Partially rewrite your data class
If you are going down route 2:
Lets assume your data class in the table is ColorData` and has the three attributes:
int RCom
int GCom
int BCom
String CommodityName
Now if you change your CommodityName from String to StringProperty and provide this to the TableView via
commodityNameColumn.setCellValueFactory(cellData -> cellData.getValue().commodityNameProperty());
Where commodityNameColumn is the TableColumn of your TableView displaying the commodityNameProperty() a new method of ColorData giving access to the new StringProperty.
Now if you change the StringProperty via its setter, and the value actually changes, the TableCell will update accordingly.
If there is still something unclear how to link a data class to the JavaFX TableView I recommend this tutorial.

Set columnwidth of a table in XWPFTableCell (docx)

I'm generating a docx file with apache-poi. In the wordfile, I add tables, whose columns have a width I would like to see fixed.
Currently, I use the technique described here: http://apache-poi.1045710.n5.nabble.com/Is-there-a-way-to-set-the-width-of-a-column-in-XWPFTableCell-td5711491.html
Basically, this entails setting
cell.getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(cols[j]));
on each cell of that column.
The problem is that while the file opens perfectly in MS Word, open office interprets the values I set to the columnwidth differently. Whereas MS Word apparantly assumes 20-th of a point as units, open office seems to use points instead and therefore all columns are 20 times wider when I open the generated document in OO.
Usually when I see something weird in the generated output, I unpack the docx file, see what the value should be and change my code. But open office does not seem to be able to save to docx, so I can't change the value in OO save it back and see if Word still interprets the document correctly in order to find a cross-application solution.
Any idea how I set the width of the table column so that both OO and MS Wordt interprets it the same?
Don't touch single cells.
Add a GRID:
XWPFDocument doc = new XWPFDocument();
XWPFTable table = doc.createTable(1,2);
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(6000));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(2000));
table.getRow(0).getCell(0).setText("1A");
table.getRow(0).getCell(1).setText("1B");
XWPFTableRow newrow = table.createRow();
newrow.getCell(0).setText("2A");
newrow.getCell(1).setText("2B");
The grid sets widths for entire columns. You don't need to do any cycles to set a width for every cell. It works in LibreOffice and GoogleDocs.
To watch the seted width in MS Word too, you may set widths of cells in the first row:
widthCellsAcrossRow(table, 0, 0, 4000);
widthCellsAcrossRow(table, 0, 0, 5000);
private static void widthCellsAcrossRow (XWPFTable table, int rowNum, int colNum, int width) {
XWPFTableCell cell = table.getRow(rowNum).getCell(colNum);
if (cell.getCTTc().getTcPr() == null)
cell.getCTTc().addNewTcPr();
if (cell.getCTTc().getTcPr().getTcW()==null)
cell.getCTTc().getTcPr().addNewTcW();
cell.getCTTc().getTcPr().getTcW().setW(BigInteger.valueOf((long) width));
}
Answer extracted from question:
It was recently pointed out to me that LibreOffice is able to save to docx. By changing the generated file and saving it back and decompiling the result, I have been able to resolve the issue.
Key is to put an explicit width to the table itself first. Word doesn't seem to care about its presence, and OpenOffice/LibreOffice are able to render the table correctly.
So, after creation of the table, I did as follows:
CTTblWidth width = table.getCTTbl().addNewTblPr().addNewTblW();
width.setType(STTblWidth.DXA);
width.setW(BigInteger.valueOf(9072));
Upon creation of the table, the layout is set to "auto" by default hence the width of the cell will always increase to follow the length of the string. As per OpenXML markup, it look's like
w:tblPr
w:tblLayout w:type="auto"
the solution is to set the layout to fixed and set the individual column length
w:tblPr
w:tblLayout w:type="fixed"
Here's the poi code for setting table layout:
XWPFTable table = document.createTable();
CTTblLayoutType type = table.getCTTbl().getTblPr().addNewTblLayout();
type.setType(STTblLayoutType.FIXED);
Here's how to set the individual width:
int[] cols = {
4896,
1872,
4032,
1728,
1440
};
for (int i = 0; i < table.getNumberOfRows(); i++) {
XWPFTableRow row = table.getRow(i);
int numCells = row.getTableCells().size();
for (int j = 0; j < numCells; j++) {
XWPFTableCell cell = row.getCell(j);
CTTblWidth cellWidth = cell.getCTTc().addNewTcPr().addNewTcW();
CTTcPr pr = cell.getCTTc().addNewTcPr();
pr.addNewNoWrap();
cellWidth.setW(BigInteger.valueOf(cols[j]));
}
}
column lengths are in twentieths of a point (dxa) or 1/1440 inch.
This is a major and very tricky element. I solved it using this own generic method of setting the widths of a table cell.
private static void setTableColumnWidths(XWPFTable table) {
table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(2000));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(3200));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1000));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1000));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1105));
table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1105));
}
Based on other answers...
public static void setTableColumnsWidth(XWPFTable table, long... widths) {
CTTblGrid grid = table.getCTTbl().addNewTblGrid();
for (long w : widths) {
grid.addNewGridCol().setW(BigInteger.valueOf(w));
}
}
Usage:
setTableColumnsWidth(table, 1440, 2700, 3000, 1440);

increasing the width of the column and not to have exponential value

I have a query is that, I have generated an excel sheet containing many columns with Data. Now there is a column named abc_ID and the value coming from back-end is of long type as shown below
//shown below how the value is passed for that column
private Long abc_Id;
abcdeed.abc_Id(13243534540L);
HSSFCellStyle[] cellStyles = new HSSFCellStyle[11];
HSSFCellStyle styleHeader = null;
HSSFCellStyle styleHeaderRBorder = null;
HSSFCellStyle cellStyleReportName = null;
HSSFCellStyle cellStyle00 = null;
HSSFCellStyle style_WhiteBg = null;
and I have set the following cell style of abc_ID column
if(columnHeaders[i].equals("abc_Id") && abcdeed.getabc_Id() != null){
cell.setCellValue(abcdeed.getabc_Id());
cell.setCellStyle(cellStyles[9]);
Now the issue is that finally when the excel sheet is generated and when I open that excel sheet first the value of column abc_Id looks compressed and the value in it initially is exponent type and it is because the column is of compressed type I want the column width should be expanded one and the value should not be of exponent type , I have tried to increase the cellStyles but it does not work. Please suggest the solution.
Use CELL_TYPE_STRING in all the rows for that particular Cell.
rows.getCell(abc_Id_Cell_No).setCellType(Cell.CELL_TYPE_STRING);
and at the end
Sheet.autoSizeColumn(abc_Id_Cell_No);
This will change all the cell values to String and autoSizeColumn will resize that column width.
The reason your cell is showing an exponent is nothing to do with your cell width it is to do with the type of value you are putting in it.
If your number was input as a string then the cell might hide the entire value from view but the full value would still exist in the cell.
Because your value is a number you need to edit the number format parameter for your cell so that it shows the number of digits you wish to display after the decimal point. You can check the valid number format codes as a reference.

Create FormLayout rows and columns dynamically (at runtime)

Hello guys and ladies,
as I let the Eclipse WindowBuilder create me a JPanel with a FormLayout, I wanted to make this creation to be dynamical, because the program I'm writing needs it that way in order to avoid 1000 row long from. I used the following code:
JPanel pData = new JPanel();
pData.setBounds(10, 232, 381, 163);
FormLayout fLayout= new FormLayout(new ColumnSpec[]{}, new RowSpec[]{});
int numCols = 5;
int numRows = 10;
for(int i=1;i<=numCols;i+=2)
{
fLayout.insertColumn(i, FormFactory.RELATED_GAP_COLSPEC);
fLayout.insertColumn(i+1, FormFactory.DEFAULT_COLSPEC);
}
for(int j=1;j<=numRows;j+=2)
{
fLayout.insertRow(j, FormFactory.RELATED_GAP_ROWSPEC);
fLayout.insertRow(j+1, FormFactory.DEFAULT_ROWSPEC);
}
pData.setLayout(fLayout);
getContentPane().add(pData);
But starting the program, I get a stack of errors starting with:
"The column index 1 must be in the range [1, 0]"
Changing the index in the for-loop(s) simply changes the number in the middle of this error text, but the rest stays the same.
What am I doing wrong? Is it even possible to create a FormLayout dynamically? I'd really appreciate your help!
Additional Information:
The reason I'm using a FormLayout is the fact, the columns have different sizes. I know GridBagLayout can do so as well, but it needs many more lines and numbers to have the same result concerning insets and position. But if it's the only sensible alternative, I'll accept it ... as long as it's dynamical ;-)
It has to do with how the "insertRow()/insertColumn()" work. To insert something you must already have row/columns to insert in between. You should instead use the ".appendRow()/.appendColumn()" which just add a new row or column at the bottom of any existing rows or to the right of any existing columns.
EX:
int numCols = 2;
int numRows = 10;
for(int i=1;i<=numCols;i++)
{
fLayout.appendColumn(FormFactory.RELATED_GAP_COLSPEC);
fLayout.appendColumn(FormFactory.DEFAULT_COLSPEC );
}
for(int j=1;j<=numRows;j++)
{
fLayout.appendRow(FormFactory.RELATED_GAP_ROWSPEC);
fLayout.appendRow(FormFactory.DEFAULT_ROWSPEC);;
}
this.setLayout(fLayout);
This would add 4 columns(2 default and 2 related gaps) and 4 rows(2 default and 2 related gaps) to whatever already exists.

Categories

Resources