Apache POI Locking Header Rows - java

Is anyone out there familiar with a way to lock a row in a spreadsheet created with Apache POI 3.7? By locking I mean that I want the title row for the columns to remain visible when the user is scrolling through the rows. My created spreadsheet will have 500 rows and it would be beneficial if the column’s names were always visible.

In case you need to Freeze any particular row anywhere in the sheet you can use (Within org.apache.poi.ss.usermodel.Sheet) (Available in POI 3.7 as well)
Sheet.createFreezePane(int colSplit, int rowSplit, int leftmostColumn, int topRow)
In your case if you want to freeze just your first x rows then the int leftmostColumn, int topRow section will get removed and you can use just
Sheet.createFreezePane(int colSplit, int rowSplit)
for example
sheet1.createFreezePane(0, 5); // this will freeze first five rows

To do this, you can create a freeze pane as follows:
workbook.getSheetAt(workbook.getActiveSheetIndex()).createFreezePane(0, 1);
This will freeze the first row in place. There's another method with more options, so check out the API.
The only thing to note would be if you're using XSSF workbooks - there is a mention of a bugfix in version 3.8-beta3 that fixed the behavior of freeze panes using XSSF spreadsheets:
50884 - XSSF and HSSF freeze panes now behave the same(poi-developers)
I don't know the details of this, but it would be worth investigating if you're in that boat.

You can not freeze a middle row without getting the rows above it also freezed.
Say you have 100 rows and your header row is at line 50. You might expect that only row 50 gets locked so that when scrolling from line 1-49, everything is scrolled up and when it reaches line 50, the 50th row scrolls to the top and stays there when lines 51-100 is scrolled.
But, there is a workaround. What you can do is, group the rows and then freeze them.
First, group the rows from 1-49 and then freeze panes from 1-50. Now the user can minimize the group and then work with the table with the table header locked and at the top.
sheet.groupRow(0, 49);
sheet.createFreezePane(0, 50);
There is a small catch though. MS Excel won't let you expand/collapse a group if the sheet is protected. For this you need to write a Macro.

Related

POI Excel chart - set property to - 'Don't move or size with cells'

I have an excel template which has the table and charts already setup, just need to add data. There is a collapsible table (using group row) which has a variable number of rows. Beneath this table are two bar charts at the same vertical level.
After filling the table data the two charts are shifted down so when the table is expanded there is no overlapping between the table and charts.
To enable this the chart properties are set to 'Move but dont size with cells'. This works but when any columns or rows are resized the two charts start to move. This can be fixed by using the 'Dont move or size with cells' option.
I have tried the below code but am getting NPE with the following code. The getGraphicFrame() returns null.
dbSheet.getDrawingPatriarch().getCharts().get(0).getGraphicFrame().getAnchor().setAnchorType(AnchorType.DONT_MOVE_AND_RESIZE);
Can someone advise how this can be done? Thanks.

Prevent merge cell to split across pages

I have generated an Excel document with jxls and POI. Now POI has merged cell, half data is in page 1 & other half of merged cell in page 2. How can I prevent it?
Unfortunately you can't. That's a disadvantage of Excel. Excel does not provide a "keep merged cells on one page" feature. One need to set an explicit page break above of the row which shall the first on the new page.
Apache POI provides Sheet.setRowBreak to do so.
So you need to know what row is the first one having the merged cells split into two pages. Then set row break to the row above.
For example if first row index of the rows having the merged cells split into two pages is 25, then:
...
Sheet sheet ...
...
sheet.setRowBreak(24);
...
Of course this only can be used if the row positions on the page are static or if one knows how many rows fit to one page. I don't know any more dynamic solution.
Same is if merged columns split over two pages. Then manually set a column break is needed.
Apache POI provides Sheet.setColumnBreak to do so.
Of course this has same disadvantages as manually row break has.

Horizontal scrolling in selenium web driver till element is not visible

I have a website that has a long horizontal table. I have Xpath that extracts column headers of a table that stretches more than the screen width (3X of the screen width). Now I have to extract all column heads with their respective index as my table has show columns filters from where user can select or deselect the rows. So I need to dynamically fetch the columns with the index. Now I when I try to fetch the column heads for the first time then system fetch me the column heads till it is visible on the first screen without scroll but now when the system tries to get the column head which is not visible on chrome then code returns a null value.
I have tried to get the total number of columns and checked that scrolling right by 8 columns will do my job but then with this, I am not able to reuse this function on other web tables where there are lesser columns as the system does not find the i+8 column and shows the exception.
I tried to scroll right every time by one column when I get column head as blank. But with this, my code has to check one if condition each time when it does get blank and this is making my method very slow which I can't afford as I need to get at least 35 columns and that too more than 2-3 time in bigger methods.
Now, what I know here is I know which is the last column head was visible to me so I need to scroll right till column head which I had is not visible to me on a screen which other way means I have scrolled maximum to right without hiding the column which I haven't covered. How can I do it?
This is what I tried for this scrolling by 8 columns by seeing the general width of columns. This is working for me but restricting the reusability of function.
if (colHead.equalsIgnoreCase("")) {
WebElement elementToBeScrolled1 = driver.findElement(By.xpath("//th["+i+"+8]"));
By elementToBeScrolled = getByLocator(elementToBeScrolled1);
do {
keyPress(Keys.ARROW_RIGHT);
} while (waitForElement(elementToBeScrolled, 5, WaitType.invisibilityOfElementLocated));
colHead = driver.findElement(By.xpath("//th[" + i + "]"))
.getText();

Does NatTable need a manual refresh after repaintCell?

I have the following code snippet.
int index = getEventList().indexOf(myObj);
SelectionLayer selectionLayer = getGlazedListsGridLayer()
.getBodyLayerStack().getSelectionLayer();
getNatTable().repaintCell(0,selectionLayer.getRowIndexByPosition(index));
When I run the code shown above, the affected cells only get repainted after I click on the table displayed in the GUI. If I comment out that code and use getNatTable().refresh(); it repaints without me having to first click on the table.
Is there a way to have a cell repainted without having to click on the table displayed in the GUI? I would hate to have to call refresh() for a large table where this code may be executed many times.
No you don't need to perform some additional step in order to trigger the repainting. The issue in your code is the usage of wrong index values. You have a grid so column 0 is the row header from the NatTable perspective. I suppose you want to redraw the first column of the body, which is index 1 from the NatTable point of view. Also the row index is incorrect, as you calculate the index in the SelectionLayer but actually need the index in the table, which is at minimum +1 if you only have a column header row.
Actually your code should work by adding 1 on the index if you have one row header column and one column header row in the grid.
getNatTable().repaintCell(1, selectionLayer.getRowIndexByPosition(index) + 1);

Using NatTable for large data which is slow to retrieve

I got a question about the NatTable SWT datagrid widget which I want to use to display a huge log file.
As the log file can be several GB in size, I cannot load it in memory entirely. The application should use as little heap space as possible. Thus, my IDataProvider implements its getDataValue method to read a log file line on the fly, with the help of a little caching mechanism and a cache for raw line positions within the file. When opening a file, almost nothing is known about its contents - not even the amount of rows the table will eventually have to display.
This leads to several problems which currently freak me out:
1) I have to estimate the total row count (using average line length) until the file has been scanned entirely and a maximum line count is really known for sure. As soon this is the case my getRowCount method returns the actual, correct number of rows. This seems to freak out the NatTable widget, it loses its current position entirely and jumps to row # 1!
2) When doing something intuitive as double-clicking on the border of a column (to auto-size the column, just like in Excel), my application freezes completely as suddenly ALL rows cells contents is queried using my provider and the whole concept is abused! I did not want anything to trigger a full file read!
Does anybody have some hints for me? The documentation is so little and so bad...
Any hint is greatly appreciated! How can I prevent my application from freezing??
Thanks!
1) Sounds like the selection isn't preserved when you change the row count - a row count change implies a backing data change hence it's probably playing safe and setting the selection to the first row. You could query the selected row before changing the row count and then reset the selection after you change the row count.
2) In order to figure out what the max-width of the column is, the table has to query each value for that cell in every row... Either you have to implement a paging mechanism such that you return something resulting in zero width when the row isn't visible, or you'll probably want to raise a bug against NatTable to request a feature for an auto-resize mode based on only the visible columns!

Categories