Forum > LCL
[SOLVED] TStringGrid - making focused cell visible again
(1/1)
alpine:
It is probably a trivial one, but for the last couple of hours I just can't figure it out. In the TStringGrid, when the focused cell has gone out of sight (by scrolling with the scrollbars), how it can be made visible again?
There is IsCellVisible() but no MakeCellVisible().
Thanks in advance!
Blaazen:
You can use property TopRow, which is the first visible row. The same is for columns: property LeftCol.
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- if not StringGrid1.IsCellVisible(StringGrid1.Col, StringGrid1.Row) then begin StringGrid1.TopRow:=StringGrid1.Row; StringGrid1.LeftCol:=StringGrid1.Col; end;So the selected cell will become top-left cell.
alpine:
--- Quote from: Blaazen on February 06, 2023, 07:14:24 pm ---You can use property TopRow, which is the first visible row. The same is for columns: property LeftCol.
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- if not StringGrid1.IsCellVisible(StringGrid1.Col, StringGrid1.Row) then begin StringGrid1.TopRow:=StringGrid1.Row; StringGrid1.LeftCol:=StringGrid1.Col; end;So the selected cell will become top-left cell.
--- End quote ---
Thanks for the reply!
However, I would prefer not to scroll in unnecessary directions, making it top-left will be fine when the focused cell is currently towards NW direction. In all other (7) it will be inappropriate - consider the focused cell is the farthest bottom-right and it is out of sight.
Edit:
Actually, there is a goScrollKeepVisible option, but with that on, the grid changes its Row and/or Col when scrolling with the scrollbars. I don't want this to happen because it will trigger some internal updates, etc.
Blaazen:
OK, there are also properties VisibleRowCount and VisibleColCount.
So you can do:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---StringGrid1.TopRow:=StringGrid1.Row-(StringGrid1.VisibleRowCount div 2);and selected cell will be in the middle (vertically).
Also, instead of IsCellVisible() you can use:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---if (Row>=TopRow) and (Row<(TopRow+VisibleRowCount)) thenand you can manage vertical and horizontal shift separately.
alpine:
--- Quote from: Blaazen on February 06, 2023, 08:07:29 pm ---OK, there are also properties VisibleRowCount and VisibleColCount.
So you can do:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---StringGrid1.TopRow:=StringGrid1.Row-(StringGrid1.VisibleRowCount div 2);and selected cell will be in the middle (vertically).
--- End quote ---
Not quite. VisibleRowCount could change depending on the different row heights (same with VisibleColCount and col widths).
--- Quote from: Blaazen on February 06, 2023, 08:07:29 pm ---Also, instead of IsCellVisible() you can use:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---if (Row>=TopRow) and (Row<(TopRow+VisibleRowCount)) thenand you can manage vertical and horizontal shift separately.
--- End quote ---
Trying to cope with variable widths/heights, I've tried a "crawling" approach:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure MakeVisible(AGrid: TStringGrid; ACol, ARow: Integer);begin AGrid.BeginUpdate; // Comment it to work properly try if ARow < AGrid.TopRow then AGrid.TopRow := ARow else while AGrid.TopRow + AGrid.VisibleRowCount <= ARow do AGrid.TopRow := AGrid.TopRow + 1; if ACol < AGrid.LeftCol then AGrid.LeftCol := ACol else while AGrid.LeftCol + AGrid.VisibleColCount <= ACol do AGrid.LeftCol := AGrid.LeftCol + 1; finally AGrid.EndUpdate(True); // Comment it to work properly end;end;But it doesn't work well when enclosed in BeginUpdate/EndUpdate - seems that VisibleXXXCount doesn't update properly. Commenting them out makes it plausible, but then you can visually see how the grid gradually gets there.
I finally came to the following solution:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure MakeVisible(AGrid: TStringGrid; ACol, ARow: Integer);var L: Integer;begin AGrid.BeginUpdate; try if ARow < AGrid.TopRow then AGrid.TopRow := ARow // towards NW, N, NE else if AGrid.TopRow + AGrid.VisibleRowCount < ARow then begin if AGrid.FixedRows > 0 then L := AGrid.CellRect(0, Pred(AGrid.FixedRows)).Bottom else L := 0; Inc(L, AGrid.RowHeights[ARow]); while ARow > AGrid.FixedRows do begin Inc(L, AGrid.RowHeights[Pred(ARow)]); if L > AGrid.ClientHeight then Break else Dec(ARow) end; AGrid.TopRow := ARow; // towards SW, S, SE end; if ACol < AGrid.LeftCol then AGrid.LeftCol := ACol // towards NW, W, SW else if AGrid.LeftCol + AGrid.VisibleColCount < ACol then begin if AGrid.FixedCols > 0 then L := AGrid.CellRect(Pred(AGrid.FixedCols), 0).Right else L := 0; Inc(L, AGrid.ColWidths[ACol]); while ACol > AGrid.FixedCols do begin Inc(L, AGrid.ColWidths[Pred(ACol)]); if L > AGrid.ClientWidth then Break else Dec(ACol) end; AGrid.LeftCol := ACol; // towards NE, E, SE end; finally AGrid.EndUpdate(True); end;end; Which scans backward to find how many cols/rows can fit into the scrollable area. It works fairly well, though it is not ideal, since it cannot set the topleft origin of the scrollable area in the middle of a cell - something that can be observed when you have columns wider than the grid itself.
Navigation
[0] Message Index