了解 TStringGrid 上选择的行的另一种方法(它实际上是唯一的):
YourstringGrid.Selection.Top;
YourstringGrid.Selection.Bottom;
如果只选择了一行,它们必须匹配。
我从来没有看到.Selection.···
失败,虽然我看到 YourstringGrid.Row 似乎无法获取选择行,但很多时候它返回 -1 当您认为它必须返回其他值时(请参阅最后的 4 点以了解为什么似乎失败但当它返回-1时,它真的不是失败,......这是一个理解的概念)。
选择和带有焦点的单元格不是一回事.......Selection
用于选择,.Row
并且.Col
用于具有焦点的单元格并且与选择无关,它可以是具有焦点的单元格,而选择是完全不同的单元格范围(两者是不同的概念)。
此外,我发现这YourstringGrid.Row<>YourstringGrid.Selection.Top
可能是真的。当具有焦点的单元格不在所选内容的第一行时。
Internet 上显示的一些 hack、技巧、代码等仅适用于goRowSelect=False
如果设置为 True 此类例程无法正常工作的情况,请谨慎使用。
提示:在 TStringGrid 上,goRowSelect=True
通过代码选择多行是非常错误的,.Selection
有时更改不会更新.Row
(它们不会更改具有焦点的实际单元格),所以如果有人只想选择一行,那就是最好将行值直接分配给.Row
.
请记住:在 TStringGrid 上goRowSelect=True
谈论什么单元格有焦点是没有意义的,所以在编码时他们根本没有想到这样的事情(.Row
并且.Col
不能在什么时候阅读goRowSelect=True
)。换句话说:如果你总是选择一整行,那么必须检查有焦点的单元格,没有这样的单元格,它是整行,等等......认为不要被 BUG 激怒在 TStringGrid 上混合焦点单元格时的内部实现goRowSelect=True
。
同样最糟糕的是:WhithgoRowSelect=True
和一些键盘组合(Shift+Cursors)和鼠标点击,你可以做出罕见的选择,比如一列中有两个或三个单元格,但不是整行;记住它有goRowSelect=True
并且网格只显示选择的行的一些单元格,如果你读.Selection
它告诉你行上的所有单元格都没有被选中(True=(TheGrid.FixedCols+#<TheGrid.Selection.Left)
) 其中# 可以大于 1。同样,请注意此类 BUG...我只能说...我总是捕获选择更改并强制选择完整的行(我在 OnSelectCell 上放置代码以确保所有选择都是完整的row/s),看一个简单的代码(注意我不关心正在选择什么单元格,从概念上讲,选择必须进入整行或整行,而不是单元格;又是一个罕见的概念,内部实现不认为你想要在选定的单元格更改时做一些事情,所以这个事件应该没有代码,我把这个代码用来修复选择不是全行的BUG):
procedure TYourForm.YourGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
begin
YourGrid.Selection:=TGridRect(Rect(YourGrid.FixedCols,YourGrid.Selection.Top,YourGrid.FixedCols,YourGrid.Selection.Bottom));
end;
简化:TStringGrid 有太多错误,我发现它同时告诉 '.Row=13'.Selection.Top=2
和.Selection.Bottom=5
; 选择之外的活动行怎么可能是第一行?等等。这是因为'.Row'(以及.Col
)不谈论选择的行,谈论什么单元格有焦点,所以看到.Row
知道选择了什么行在概念上是错误的......你会看到行具有焦点的单元格,与实际选择单元格无关。
我从来没有见过失败的事情:
- .Selection.···总是告诉你选中的区域(区域显示为选中)
- .Row 如果分配了一个值(并且网格有
goRowSelect=True
),则选择整行(我从来没有尝试过没有goRowSelect=True
),但只有一行。
更不用说您是否想大量破解 TStringGrid 并使其成为同时具有多个连续选择的多行选择(例如 ListBox 多选);由于 TStringGrid 在 .Row 和 .Selection 属性管理上的所有错误,这让事情变得非常混乱。
对于这样的多选择网格,我建议总是使用非官方的 VCL 组件而不是 TStringGrid,如果我不记得不好,它被称为 TMultiSelectStringGrid,在它上面你有一个 .Selected 属性,每个单元格、行和列是读取/能写。当您想要Ctrl按下键进行多选时,它真的很有效,也适用于多行选择和多列选择...只需在行、列或单元格上循环以检查女巫被选中和女巫那些不是。它还有一个属性.RightMouseSelect
(如果我不记得不好的话)可以右键单击选择,而且效果很好。
警告,并非所有右键单击时选择的代码都是正确的...其中很多都不关心您是否有多项选择...永远不要设置.Row
是否要选择多行,只需检查如果鼠标在更改之前位于选择之外,.Selection
否则右键单击可以更改选择...那么如何弹出菜单超过一行(使用示例:弹出菜单条目称为删除多个条目同时时间)。
换句话说(我真正用于 VCL 标准 TStringGrid 的代码):
procedure TYourForm.YourGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
ACol,ARow:Integer;
begin
YourGrid.MouseToCell(X,Y,ACol,ARow);
if goRowSelect in YourGrid.Options
then begin // TStingGrig with full row selected, no individual cell must be selected
if (ARow<YourGrid.Selection.Top)
or
(YourGrid.Selection.Bottom<ARow)
then begin // Where clicked is outside the actual rows that are selected
YourGrid.Row:=ARow;
end;
end
else begin // TStingGrig where individual cells can be selected
if (ARow<YourGrid.Selection.Top)
or
(YourGrid.Selection.Bottom<ARow)
or
(ACol<YourGrid.Selection.Left)
or
(YourGrid.Selection.Right<ACol)
then begin // Where clicked is outside the actual selection
YourGrid.Selection:=TGridRect(Rect(ACol,ARow,ACol,ARow)); // Select the clicked cell
end;
end;
end;
注意:我确实在单元上的程序上有该代码,并调用该程序传递 Grid 引用和 X、Y 坐标;说实话,我使用的单元是type TStringGrid=class(Grids.TStringGrid)
TStringGrid 的完整破解,声明为 as ,因此我可以使用视觉设计并在所有单元上拥有额外的功能;只需确保 hack 可以interface
uses
在单元列表末尾的部分添加此类单元(或至少在网格之后,从不在网格之前)。
控制弹出菜单的特殊提示已显示或未显示以及要显示的弹出菜单:
- 在 event 上做
OnMouseDown
,从不做OnMouseUp
,也不做OnClick
,等等;或弹出菜单将在选择更改之前显示......并且在选择更改时(通过代码)弹出菜单将立即隐藏。
- 如果完成了
OnMouseDown
不需要通过代码强制显示弹出菜单,它会正常执行;还有更多,您可以取消要显示的弹出窗口,例如,如果在单元格数据之外单击,或者也可以为 FixedCols、FixedRows 提供不同的弹出窗口,对于每个单元格,您也可以有不同的弹出窗口(我谈论设计时弹出窗口,您还可以在显示之前动态创建弹出条目等),将您想要做的代码放在 event 上OnMouseDown
,谈论在设计时创建的 opoup 菜单;如果 popup 是在运行时创建的,请考虑相同:显示或不显示 on ,在自己的菜单事件OnMouseDown
上构建菜单。OnPopup
基本技巧是对事件进行选择更改OnMouseDown
,它在弹出菜单显示之前被触发。
啊,在我的代码上,我不介意单击了哪个按钮,因为如果在选定的多行内单击左键,它也会正常工作(我的代码不会对选择进行任何更改,也不会对行等进行任何更改。它真的什么也没做,请参见if
s),但您会看到选择仅更改为一行。
请注意,选择也可以通过鼠标左下,持续,然后移动鼠标并抬起左键来更改为多选,这将选择多个单元格/行。用户必须进行选择的所有这些方式,使得标准组件的内部实现变得如此错误,在内部编码时并未考虑到所有操作组合。
尝试在按下鼠标左键时按下Ctrland 或在标准网格上移动鼠标,完全没有代码,在 OnMouseMove 上的 ecetp 代码显示,和, 会看到你认为不可能的事情。我看到有一次告诉价值是几百万(一个不可能的价值,因为网格只有几列),相同的(与'.Col'失败时不同的价值)。Shift.Row
.Col
.Selection.···
.Col
.Row
所以不要相信返回的值.Row
,.Col
如果你想得到什么是选择(错误的概念,它们表达了哪个单元格有焦点,与选择是什么无关);但是您可以使用它们来选择一个且仅一个行或列(仅当使用允许它的黑客网格时才选择列,或者使用带有goRowSelect=False
并自己模拟列选择的网格)。
并且请始终牢记这一点(请始终这样做):
- 具有焦点的单元格(
.Row
并且.Col
可能会告诉您哪个是)可以在实际选择之外,是的,它可以在外面(其中很难强制失败,它会发生,无需编写任何代码,只需使用鼠标移动单击和与Alt, Ctrl, Shift, 光标的组合并Spacebar可能发生)。所以不要相信.Row
也不.Col
知道关于选择的任何事情(这在概念上是错误的),总是使用.Selection.···
.
希望这有助于在我理解这一点之前不要让我头疼:
.Selection.···
仅代表选定的一个矩形单元格区域(不介意goRowSelect
是真还是假)。
.Selection:=TGrigRect(Rect(Left,Top,Right,Bottom));
是将实际选择更改为另一个的最佳方法(由您自己确保,Left<=Right
否则Top<=Bottom
事情可能会变得非常糟糕);把代码想象成这么大:(.Selection:=TGrigRect(Rect(Min(Left,Right),Min(Top,Bottom),Max(Right,Left),Max(Bottom,Top));
见Min
and Max
,它们是Maths
单位的)。
.Row
给出具有虚线矩形的特殊单元格的行号,无论它是在选择内还是在选择外,如果没有单元格有焦点,也可以是 -1。它与选择无关。
.Col
给出绘制了一个虚线矩形的特殊单元格的 col 编号,无论它是在选择内部还是在选择外部,如果没有单元格有焦点,也可以是 -1。它与选择无关。
了解这四件事,我可以得到一些过去的东西。我花了太多时间才理解这两个不同的概念:具有焦点的单元格('.Row' 和 '.Col')和选定的单元格(.Selection.···
)。
PD:请随意分享这些信息!