【问题标题】:Detecting single vs multiple selections in Delphi TStringGrid在 Delphi TStringGrid 中检测单选与多选
【发布时间】:2011-08-26 20:48:49
【问题描述】:

这是我之前关于 Delphi String Grids 的问题 Delphi TStringGrid multi select, determining selected rows 的后续。这是一个不同的问题。

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

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

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

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

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

谢谢!

【问题讨论】:

  • 我不知道你在问什么。 “一定有更简单的方法”是个问题吗?
  • ...必须有一种更简单的方法来了解在 onSelectCell 事件中选择了哪些行。
  • @sse - 你是怎么解决这个问题的?

标签: delphi select selection tstringgrid


【解决方案1】:
for RowIndex := StringGrid1.Selection.Top to StringGrid1.Selection.Bottom do
begin
  DoSomethingWithRow(RowIndex);
end;

是的,我明白你的意思。似乎在 OnSelectCell 事件之后 更新了 Selection 属性,因此在事件中您只有旧值(即在 select 事件之前)。答案是将上面的代码移动到 stringgrid 的 OnMouseUp 事件。它似乎工作正常。

【讨论】:

  • 谢谢,这是个好主意,遗憾的是不能保证通过鼠标选择单元格。我的另一个想法是在 onDrawCell 事件中跟踪 selection.*,它总是准确的,但由于性能原因(而且因为它看起来很笨拙),我也不喜欢这个。其他想法?
  • ps,如果我能获得可能有帮助的受保护属性,我不介意降级另一个组件。接下来我将深入研究 TStringGrid 源代码。
【解决方案2】:

我能够自己解决这个问题,我最终将 OnDrawCell 事件与 onSelectCell 事件结合使用——我认为这会是一团糟,但结果并不是那么糟糕。

这是我为遇到相同问题的其他人提供的解决方案的摘要。以下是两个关键事实:

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

民众 previousHighlightCount : 整数; //标志以确保 onDraw 中的必要代码仅在每个行选择中被调用一次。在 onFormCreate 中初始化为“1”。 程序 Grid.OnDrawCell(...) 开始 ... SelectionCount := Grid.Bottom - Grid.Top;** if ((SelectionCount = 1) AND (previousHighlightCount 1)) 那么 开始 网格更新编辑; //您的例程为一行正确更新网格。* previousHighlightCount := 1; 结尾 别的 previousHighlightCount := PrtEdtGrid.SelectionCount; //多选行的例程在 onSelectCell 事件中,onSeelctCell 适用于多选。 …… 结尾;

感谢回复的人!!

【讨论】:

    【解决方案3】:

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

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

    现在,OnSelectCell 事件与聚焦有关。当单击单元格或尝试使用导航键在单元格上导航时,将触发处理程序。简而言之,当试图聚焦一个单元格时,会调用处理程序。您可以通过重置CanSelect 参数来禁止聚焦单元格(这同样意味着CanFocus,因为可以选择单元格,即突出显示,而无需聚焦,你不能用OnSelectCell来控制它。

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

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

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

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


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

    【讨论】:

    • 好帖子!感谢您的详尽回答。但实际上存在选择准确的情况。 TStringGrid.Selection 属性在 OnSelectCell IFF 中是准确的(就突出显示而言),多行已被突出显示。使用 onMouseUp 不是一个好的解决方案,因为可以在没有鼠标的情况下选择和/或突出显示内容。我同意 onDrawCell 是一个很好的方法,只要使用标志来避免不必要的重新计算。我希望有一个 onAfterHighlight 事件。关于如何将其添加到后代类中的任何想法?
    • 我同意,在某些情况下,传递给处理程序的坐标指向已选择的单元格。但这只是因为该单元格已被先前的用户操作选择,而不是用户现在正在执行的操作。在我的测试中,Selection 总是更新 after OnSelectCellafter 从处理程序返回)。另一方面,您所说的OnMouseUp 是非常正确的,到目前为止,除了OnMouseUp 之外,我不知道除了定义OnKeyUp 事件之外的其他解决方案(解决方法)。这使得整个方法更加不优雅,这是一种耻辱。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      • 2022-01-10
      • 1970-01-01
      • 2013-08-13
      相关资源
      最近更新 更多