第一个问题:
如何调用stringgrid中不可见的部分?你需要滚动查看它。
例如:
stringgrid中有20行,但一次只能看到10行。你需要滚动查看其他10.如何调用“隐藏”的?
第二个问题:
我知道这可能不是正确的方法,所以一些指针会受到赞赏 我有一个带有1个固定行的字符串网格。我在运行时添加ColorButtons。所以我用按钮填充1列。 我用这个按钮来“插入/删除”行。只要所有网格都处于“可见”部分,就可以正常工作。 当我“插入”新行并将按钮移动到“隐藏”部分时出现问题。最后一个按钮然后被绘制到Cell [0,0]。 “隐藏”部分中的其他按钮被正确绘制。知道为什么会这样吗?我应该找到一种在OnDraw方法中管理此问题的方法,还是有更好(正确)的方法来执行此操作?
代码:
procedure Tform1.addButton(Grid : TStringGrid; ACol : Integer; ARow : Integer);
var
bt : TColorButton;
Rect : TRect;
index : Integer;
begin
Rect := Grid.CellRect(ACol,ARow);
bt := TColorButton.Create(Grid);
bt.Parent := Grid;
bt.BackColor := clCream;
bt.Font.Size := 14;
bt.Width := 50;
bt.Top := Rect.Top;
bt.Left := Rect.Left;
bt.Caption := '+';
bt.Name := 'bt'+IntToStr(ARow);
index := Grid.ComponentCount-1;
bt :=(Grid.Components[index] as TColorButton);
Grid.Objects[ACol,ARow] := Grid.Components[index];
bt.OnMouseUp := Grid.OnMouseUp;
bt.OnMouseMove := Grid.OnMouseMove;
bt.Visible := true;
end;
procedure MoveRowPlus(Grid : TStringGrid; Arow : Integer; stRow : Integer);
var
r, index : Integer;
bt : TColorButton;
Rect : TRect;
begin
Grid.RowCount := Grid.RowCount+stRow;
for r := Grid.RowCount - 1 downto ARow+stRow do
begin
Grid.Rows[r] := Grid.Rows[r-StRow];
end;
index := Grid.ComponentCount-1;
for r := Grid.RowCount - 1 downto ARow+stRow do
begin
bt :=(Grid.Components[index] as TColorButton);
Rect := Grid.CellRect(10,r);
bt.Top := Rect.Top;
bt.Left := Rect.Left;
Grid.Objects[10,r] := Grid.Components[index];
dec(index);
end;
for r := ARow to (ARow +stRow-1) do
begin
Grid.Rows[r].Clear;
end;
end;
procedure MoveRowMinus(Grid : TStringGrid; Arow : Integer; stRow : Integer);
var
r, index : Integer;
bt : TColorButton;
Rect : TRect;
begin
for r := ARow to Grid.RowCount-stRow-1 do
begin
Grid.Rows[r] := Grid.Rows[r+StRow];
end;
index := ARow-1;
for r := ARow to Grid.RowCount-stRow-1 do
begin
Rect := Grid.CellRect(10,r);
bt :=(Grid.Components[index] as TColorButton);
bt.Top := Rect.Top;
bt.Left := Rect.Left;
Grid.Objects[10,r] := Grid.Components[index];
bt.Visible := true;
inc(index);
end;
for r := Grid.RowCount-stRow to Grid.RowCount-1 do
begin
Grid.Rows[r].Clear;
end;
Grid.RowCount := Grid.RowCount-stRow;
end;
答案 0 :(得分:5)
对于可见部分,存在VisibleRowCount
和VisibleColCount
属性。 TGridAxisDrawInfo
记录类型将可见部分 Boundary 和所有部分命名为 Extent (反之亦然,我永远不会记住)。所以没有具体的VCL声明名称为字符串网格的不可见部分。它只是不可见的部分。
我认为你出现了一个逻辑错误:滚动网格时按钮不移动。虽然看起来它们可能会移动,但这只是因为内部调用ScrollWindow
而移动设备上下文内容的结果。字符串网格组件中的滚动条是自定义添加的,并且不像例如TScrollBox
。
要始终在所有位置显示所有按钮,请在OnTopLeftChanged
事件中重新绘制字符串网格:
procedure TForm1.StringGrid1TopLeftChanged(Sender: TObject);
begin
StringGrid1.Repaint;
end;
当所有行的行高和字符串网格的高度永远不会改变时,只需创建一次所有按钮就足够了,让它们保持原样。这意味着每个按钮不再“附加”到一行,并且将它们存储在Objects
属性中不再具有任何意义。按下按钮时,只需从按钮的位置计算预期的行索引,并结合字符串网格的TopRow
属性,该属性指定网格中第一个可见的可滚动行的索引。
如果网格可以调整大小,例如通过锚点,然后更新父级OnResize事件中的按钮计数。如果字符串网格的行数可能会小于最大可见行数,则还会更新(可见)按钮计数。
如果您想要更多答案,请更新您的问题,并解释由于与网格和/或按钮的互动而如何调用MoveRowPlus
和MoveRowMinus
例程,因为现在我没有完全明白你想要的是什么。
关于CellRect
给出错误的坐标:这是因为CellRect
仅适用于完整(或部分)可见单元格。引用documentation:
如果指示的单元格不可见,
CellRect
将返回一个空矩形。
由于OP的评论而增加
我认为以下代码可以满足您的需求。每个按钮的原始行索引存储在Tag
属性中。
unit Unit1;
interface
uses
Windows, Classes, Controls, Forms, StdCtrls, Grids;
type
TForm1 = class(TForm)
Grid: TStringGrid;
procedure GridTopLeftChanged(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FPrevTopRow: Integer;
procedure CreateGridButtons(ACol: Integer);
procedure GridButtonClick(Sender: TObject);
procedure RearrangeGridButtons;
function GetInsertRowCount(ARow: Integer): Integer;
function GridButtonToRow(AButton: TButton): Integer;
procedure MoveGridButtons(ButtonIndex, ARowCount: Integer);
end;
implementation
{$R *.dfm}
type
TStringGridAccess = class(TStringGrid);
procedure TForm1.FormCreate(Sender: TObject);
begin
FPrevTopRow := Grid.TopRow;
CreateGridButtons(2);
end;
procedure TForm1.CreateGridButtons(ACol: Integer);
var
R: TRect;
I: Integer;
Button: TButton;
begin
R := Grid.CellRect(ACol, Grid.FixedRows);
Inc(R.Right, Grid.GridLineWidth);
Inc(R.Bottom, Grid.GridLineWidth);
for I := Grid.FixedRows to Grid.RowCount - 1 do
begin
Button := TButton.Create(Grid);
Button.BoundsRect := R;
Button.Caption := '+';
Button.Tag := I;
Button.ControlStyle := [csClickEvents];
Button.OnClick := GridButtonClick;
Button.Parent := Grid;
Grid.Objects[0, I] := Button;
OffsetRect(R, 0, Grid.DefaultRowHeight + Grid.GridLineWidth);
end;
end;
procedure TForm1.GridButtonClick(Sender: TObject);
var
Button: TButton absolute Sender;
N: Integer;
I: Integer;
begin
N := GetInsertRowCount(Button.Tag);
if Button.Caption = '+' then
begin
Button.Caption := '-';
Grid.RowCount := Grid.RowCount + N;
for I := 1 to N do
TStringGridAccess(Grid).MoveRow(Grid.RowCount - 1,
GridButtonToRow(Button) + 1);
MoveGridButtons(Button.Tag, N);
end
else
begin
Button.Caption := '+';
for I := 1 to N do
TStringGridAccess(Grid).MoveRow(GridButtonToRow(Button) + 1,
Grid.RowCount - 1);
Grid.RowCount := Grid.RowCount - N;
MoveGridButtons(Button.Tag, -N);
end;
end;
procedure TForm1.GridTopLeftChanged(Sender: TObject);
begin
RearrangeGridButtons;
FPrevTopRow := Grid.TopRow;
end;
procedure TForm1.RearrangeGridButtons;
var
I: Integer;
Shift: Integer;
begin
Shift := (Grid.TopRow - FPrevTopRow) *
(Grid.DefaultRowHeight + Grid.GridLineWidth);
for I := 0 to Grid.ControlCount - 1 do
begin
Grid.Controls[I].Top := Grid.Controls[I].Top - Shift;
Grid.Controls[I].Visible := Grid.Controls[I].Top > 0;
end;
end;
function TForm1.GetInsertRowCount(ARow: Integer): Integer;
begin
//This function should return the number of rows which is to be inserted
//below ARow. Note that ARow refers to the original row index, that is:
//without account for already inserted rows. For now, assume three rows:
Result := 3;
end;
function TForm1.GridButtonToRow(AButton: TButton): Integer;
begin
for Result := 0 to Grid.RowCount - 1 do
if Grid.Objects[0, Result] = AButton then
Exit;
Result := -1;
end;
procedure TForm1.MoveGridButtons(ButtonIndex, ARowCount: Integer);
var
I: Integer;
begin
for I := 0 to Grid.ControlCount - 1 do
if Grid.Controls[I].Tag > ButtonIndex then
Grid.Controls[I].Top := Grid.Controls[I].Top +
ARowCount * (Grid.DefaultRowHeight + Grid.GridLineWidth);
end;
end.
但是我可以说如果不使用按钮控件也可以这样做:我建议在字符串网格的OnDrawCell事件中绘制虚假按钮控件。