在 Delphi TStringGrid 中检测单选与多选

发布于 2024-11-08 10:58:28 字数 549 浏览 6 评论 0原文

这是我上一个关于 Delphi 字符串网格的问题 Delphi TStringGrid 多重选择,确定选定行的后续问题。这是一个不同的问题。

我正在更仔细地研究 ONSelectCell 事件 TSelectCellEvent = 对象的过程 (Sender: TObject; ACol, ARow: Longint; var CanSelect: Boolean);

我注意到 TStringGrid.Selection.Top,Bottom 属性不一定准确(在事件本身内)。基本上,如果有人从选择多行变为仅选择一行,则 Selection.* 属性不会更新,而如果选择多行,则会更新。

无论是否选择一行或多行,ARow 参数都会更新,但只有当我可以确定选择了一行且仅选择了一行时,这才会对我有帮助。

例如,如果只选择了一行,则使用 Arow 参数,如果多于一行,则使用 Selection.* 属性来确定当前选择了哪些行。

一定有一个更简单的方法......

谢谢!

This is a follow up to my previous question Delphi TStringGrid multi select, determining selected rows regarding Delphi String Grids. It's a different question.

I was looking more closely at the ONSelectCell Event
TSelectCellEvent = procedure (Sender: TObject; ACol, ARow: Longint; var CanSelect: Boolean) of object;

I noticed that the TStringGrid.Selection.Top,Bottom properties are not necessarily accurate (within the event itself). Basically, if someone goes from selecting multiple rows to just one row, the selection.* properties do not get updated, whereas if one selects multiple rows, they do.

The ARow parameter does get updated regardless of whether one or more rows are selected, but this will only help me if I can determine that one and only one row was selected.

Eg, If it's just one row that was selected, then use Arow parameter, if more than one row then use Selection.* properties to determine which row(s) are currently selected.

There must be an easier way....

Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千と千尋 2024-11-15 10:58:28

我认为,部分问题在于所使用的术语。在您完全理解正在发生的事情之前,您一定会很困惑'select'如何同时表示'highlight''focus' >。在这种特殊情况下,两者之间应该有所区别。

在继续之前,我希望您记住,聚焦单元格也可以(并且实际上)突出显示,但是突出显示的单元格不一定是聚焦的一。

现在,OnSelectCell 事件与聚焦有关。当单击单元格或尝试使用导航键在其上导航时,将触发该处理程序。简而言之,当尝试聚焦单元格时,就会调用处理程序。您可以通过重置CanSelect参数来禁止聚焦单元格(这又意味着本质上CanFocus,因为单元格可以被选择,即突出显示,而没有集中注意力,并且您无法使用 OnSelectCell 来控制它)。

另一方面,goRangeSelect 选项和 TDrawGrid.Selection 属性与选择突出显示有关。前者允许您(用户)突出显示多个单元格,而后者则指向突出显示这些单元格的范围。

现在说说我的要点。在调用有问题的处理程序时,Selection从不准确,即它与ACol & 不相关。传递给处理程序的 ARow 参数。 Selection 包含在调用处理程序之前突出显示的单元格范围,并且它在处理程序内永远不会自行更改。无论是一个单元格还是多个单元格,Selection都会保持不变,直到处理程序退出。当这种情况发生时(处理程序退出),Selection 就会发生变化(顺便说一句,结果取决于您是否重置 CanSelect)。

因此,总而言之,您不能使用 OnSelectCell 来确定实际的选择作为用户最近操作的结果。相反,我建议遵循 @Sam'的建议并使用 OnMouseUp* 事件。它还允许您控制选择:如果您认为用户选择“太多”,您可以更正最终范围。不过,在后一种情况下,我可能会考虑使用 OnMouseMove,因为它允许您通过“即时”修正范围来更平滑地响应。

只要您只需要确定选择,OnDrawCell 似乎也很好。


*根据您的评论,我必须补充一点,您还必须使用 OnKeyUp 来处理使用键盘进行的选择。

I think, part of the problem is in terminology used. Until you completely understand what is happening, it must be confusing to find how ‘select’ is used to mean both ‘highlight’ and ‘focus’. In this particular case there should be distinction between the two.

Before I proceed, I'd like you to keep in mind that the focused cell can also be (and actually is) highlighted, but a highlighted cell is not necessarily the focused one.

Now, the OnSelectCell event has to do with focusing. The handler is fired when the cell is clicked or when you are trying to navigate over it with navigation keys. In short, the handler is invoked when there's an attempt to focus a cell. You can prohibit focusing the cell by resetting the CanSelect parameter (which, again, means essentially CanFocus, because the cell can be selected, i.e. highlighted, without being focused, and you can't control that with OnSelectCell).

The goRangeSelect option and TDrawGrid.Selection property, on the other hand, have to do with selecting as highlighting. The former allows you (the user) to highlight more than one cell, while the latter points to the range of those cells highlighted.

Now to my main point. Upon invoking the handler in question, Selection is never accurate, i.e. it is not correlated with the ACol & ARow parameters that are passed to the handler. Selection contains the range of cells that were highlighted just before calling the handler, and it never changes by itself within the handler. Whether one cell or more than one, Selection stays the same until the handler exits. And it is when that happens (the handler exits) that Selection changes (and the result depends on whether you reset CanSelect or not, by the way).

So, in conclusion, you cannot use OnSelectCell to determine the actual Selection as the result of the user's most recent action. Instead I would suggest following @Sam's advice and use the OnMouseUp* event. It also allows you to have control over selection: you can correct the final range if you think the user has selected ‘too much’. In the latter case I would probably consider using OnMouseMove instead, though, as it allows you to respond more smoothly by correcting the range ‘on the fly’.

OnDrawCell seems fine too as long as you need just to determine the selection.


*Following your comment, I must add, that you'd also have to employ OnKeyUp as well, to handle selections made with the keyboard.

我最亲爱的 2024-11-15 10:58:28

我能够自己解决这个问题,最后我将 OnDrawCell 事件与 onSelectCell 事件结合使用——我认为这会很混乱,但结果并没有那么糟糕。

这里总结一下我的解决方案,供遇到同样问题的其他人参考。以下是两个关键事实:

  1. OnDrawCell 中的 TStringGrid.Selection 属性始终准确。
  2. TStringGrid.Selection 属性仅在 OnSelectCell IFF 已选择多行时准确。

public
  previousHighlightCount : integer; //flag to ensure that the necessary code within the onDraw only gets called once per row selection(s).  Initialize to '1' in onFormCreate.


procedure Grid.OnDrawCell(...)
begin
...
SelectionCount := Grid.Bottom - Grid.Top;**
if ((SelectionCount = 1) AND (previousHighlightCount  1)) then  
begin                                                                               
   GridUpdateEdits;  //your routine to update the grid properly for one row.*    
   previousHighlightCount := 1;
end
else
  previousHighlightCount := PrtEdtGrid.SelectionCount;   //the routine for multiply selected rows is in the onSelectCell Event and onSeelctCell works for multiple selections.
....
end;


谢谢回复的人!!

I was able to solve this on my own, I wound up using the OnDrawCell Event in conjunction with onSelectCell Event -- which I thought was going to be a mess, but turned out not so bad.

Here's a summary of my solution for others who encounter the same problem. Here are two key facts:

  1. The TStringGrid.Selection Property is ALWAYS accurate in the OnDrawCell.
  2. The TStringGrid.Selection Property is ONLY accurate in OnSelectCell IFF multiple rows have been selected.

public
  previousHighlightCount : integer; //flag to ensure that the necessary code within the onDraw only gets called once per row selection(s).  Initialize to '1' in onFormCreate.


procedure Grid.OnDrawCell(...)
begin
...
SelectionCount := Grid.Bottom - Grid.Top;**
if ((SelectionCount = 1) AND (previousHighlightCount  1)) then  
begin                                                                               
   GridUpdateEdits;  //your routine to update the grid properly for one row.*    
   previousHighlightCount := 1;
end
else
  previousHighlightCount := PrtEdtGrid.SelectionCount;   //the routine for multiply selected rows is in the onSelectCell Event and onSeelctCell works for multiple selections.
....
end;


Thanks to those who responded!!

命比纸薄 2024-11-15 10:58:28
for RowIndex := StringGrid1.Selection.Top to StringGrid1.Selection.Bottom do
begin
  DoSomethingWithRow(RowIndex);
end;

是的,我明白你的意思。似乎 Selection 属性在 OnSelectCell 事件之后更新,因此在事件内部只有旧值(即在 select 事件之前)。答案是将上面的代码移至 stringgrid 的 OnMouseUp 事件。看起来效果很好。

for RowIndex := StringGrid1.Selection.Top to StringGrid1.Selection.Bottom do
begin
  DoSomethingWithRow(RowIndex);
end;

Yes, I see your point. It seems the Selection property is updated after the OnSelectCell event so inside the event you only have the old values (ie. before the select event). The answer to that is to move the code above to the stringgrid's OnMouseUp event. It seems to work fine.

静赏你的温柔 2024-11-15 10:58:28

StringGrid1.Selection.Top 到 StringGrid1.Selection.Bottom
这对我来说非常有效,因为我使用 onkeypress 事件来选择/取消选择内容。

StringGrid1.Selection.Top to StringGrid1.Selection.Bottom
is what worked perfectly for me since I'm using the onkeypress event to select/deselect stuff.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文