Delphi:StringGrid、位置和上下文菜单

发布于 2024-09-14 22:18:17 字数 284 浏览 3 评论 0 原文

我在使用 TStringGrid 和弹出菜单时遇到问题,

我想知道从弹出菜单中选择项目时最后活动的单元格的行/列。但是,当我单击弹出菜单时,StringGrid.Row 返回为 -1。

我尝试使用 MouseToCell 作为 OnClick 的一部分,但即使在设置 SG.Row 之后,它仍然在弹出菜单例程中返回为 -1...我怀疑问题是网格失去焦点。

有没有不需要 OnClick 设置全局变量的解决方案?

我使用链接到弹出菜单上的项目的操作列表来确保工具栏和弹出菜单之间的操作保持一致

I'm having a problem with using a TStringGrid and Popup menu

I want to know the Row / Column of the cell that was last active when select an item from my Popup menu. However when I click on the popup menu, the StringGrid.Row is returned as -1.

I've tried using MouseToCell as part of OnClick, but even after setting SG.Row it still returns as -1 in the PopUp menus routines... I suspect that the problem is the Grid losing the focus.

Are there any solutions to this that don't require OnClick setting a global variable?

I'm using an Action List linked to the items on the Popup Menu to make sure that the actions are consistent between the toolbar and the Popup Menu

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

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

发布评论

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

评论(5

半岛未凉 2024-09-21 22:18:17

恐怕我不完全明白你的意思。当我左键单击字符串网格中的单元格时,它会被选中,但当我右键单击它时则不会。当我右键单击它时,会显示弹出菜单(如果已分配),并且在 MenuItemClick 上我可以轻松读取当前的 rowcol已选择。请参阅示例视频

我猜您确实想要这样:您想要右键单击来更改活动单元格以及左键单击。这很容易做到:

procedure TForm1.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
    StringGrid1.Perform(WM_LBUTTONDOWN, 0, MakeLParam(Word(X), Word(Y)));
end;

I am afraid that I do not fully understand what you mean. When I left-click a cell in a string grid, it gets selected, but not when I right-click it. When I right-click it, the popup menu is shown (if assigned), and on MenuItemClick I can easily read the row and col currently selected. See example video.

I guess that you actually want this: you want right-clicks to change the active cell as well as left-clicks. This is easily done:

procedure TForm1.StringGrid1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
    StringGrid1.Perform(WM_LBUTTONDOWN, 0, MakeLParam(Word(X), Word(Y)));
end;
〆凄凉。 2024-09-21 22:18:17

另一种了解 TStringGrid 上所选行的方法(实际上是唯一的):

YourstringGrid.Selection.Top;
YourstringGrid.Selection.Bottom;

如果仅选择了一行,则它们必须匹配。

我从未见过 .Selection.… 失败,而我看到 YourstringGrid.Row 似乎无法获取选择行,很多时候当您认为它必须返回其他值时它会返回 -1 (请参阅最后的 4 点以了解为什么似乎失败,但当它返回 -1 时实际上并不是失败,...这是一个基本理解的概念)。

选择和带有焦点的单元格不是一回事... .Selection 用于选择,.Row.Col 用于带有焦点的单元格焦点与选择无关,它可以是具有焦点的单元格,而选择是完全不同的单元格范围(两者是不同的概念)。

另外,我发现 YourstringGrid.Row<>YourstringGrid.Selection.Top 可以为 True。当具有焦点的单元格不在所选内容的顶行时。

互联网上显示的一些技巧、技巧、代码等仅适用于当 goRowSelect=False 设置为 True 时,此类例程无法正常工作,请小心使用。

提示:在具有 goRowSelect=True 的 TStringGrid 上,通过代码选择多行是非常错误的,更改 .Selection 有时不会更新 .Row< /code> (它们不会更改具有焦点的实际单元格),因此如果有人只想选择一行,最好将行值直接分配给 .Row

请记住:在带有 goRowSelect=True 的 TStringGrid 上谈论哪个单元格具有焦点是没有意义的,因此在编码时他们根本没有考虑到这样的事情(.RowgoRowSelect=True 时,不得读取 > 和 .Col)。换句话说:如果你总是选择一整行,那么有什么意义必须检查具有焦点的单元格,不存在这样的单元格,它是整行,等等......这样想就不会因为BUG而生气在 goRowSelect=True TStringGrid 上混合焦点单元格时的内部实现。

同样最糟糕的是:通过 goRowSelect=True 和一些键盘组合(Shift+Cursors)和鼠标单击,您可以进行罕见的选择,例如一列中的两个或三个单元格,但不能选择整行;请记住它具有 goRowSelect=True 并且网格仅显示所选行中的某些单元格,如果您阅读 .Selection 它会告诉您并非该行上的所有单元格都被选中( True=(TheGrid.FixedCols+#) 其中 # 可以大于 1。再次强调,要小心这样的 BUG...我只能说...我总是陷阱选择更改并强制选择整行(我在 OnSelectCell 上放置代码以确保所有选择始终都是整行),请参阅一个简单的代码(注意我不关心正在选择哪个单元格,根据概念,选择必须转到完整的行或完整的行,而不是一个单元格;又是一个罕见的概念,内部实现不认为你想要在选定的单元格更改时执行某些操作,因此该事件应该没有代码,我将此代码放在修复的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 有太多错误,我发现它在同时 .Selection.Top=2 时告诉“.Row=13” .Selection.Bottom=5;活动行怎么可能是选择范围之外的行呢?这是因为'.Row'(还有.Col)不讲选定的行,讲哪个单元格有焦点,所以看.Row就知道选择哪一行在概念上是错误的...您将看到具有焦点的单元格的行,与实际选择的单元格无关。

我从来没有看到失败的事情:

  • .Selection.… 总是告诉你选定的区域(显示为选定的区域)
  • .Row 如果分配了一个值(并且网格有 goRowSelect=True),整个行被选中(我从未在没有 goRowSelect=True 的情况下尝试过),但只有一行。

更不用说如果您想对 TStringGrid 进行大量修改,使其成为同时具有多个连续选择的多行选择(如 ListBox 多选);由于 TStringGrid 在 .Row 和 .Selection 属性管理上存在所有错误,这使得事情变得非常混乱。

对于这样的多选网格,我建议始终使用非官方的 VCL 组件而不是 TStringGrid,如果我没记错的话,它被称为 TMultiSelectStringGrid,在它上面,每个单元格、行和列都有一个 .Selected 属性,即 Read/写得可以。当您想要按下 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;

注意:我确实在单元上的过程中拥有该代码,并调用该过程传递网格引用和 X、Y 坐标;说实话,我使用的单元是 TStringGrid 的完整破解,声明为 type TStringGrid=class(Grids.TStringGrid),因此我可以使用视觉设计并在所有单元上拥有额外的功能其中;只需确保 hack 能够在单元列表末尾的 interface uses 部分添加此类单元(或者至少在 Grids 之后,绝不是在 Grids 之前)。

控制弹出菜单是否显示以及显示什么弹出菜单的特殊提示:

  • OnMouseDown 事件上执行此操作,切勿在 OnMouseUp 上执行,也不要在 OnClick 上执行> 等;或弹出菜单将在选择更改之前显示...并且有时当选择更改时(通过代码)弹出菜单将立即隐藏。
  • 如果完成OnMouseDown,则不需要通过代码强制显示弹出菜单,它会正常执行;另外,您可以取消要显示的弹出窗口,例如,如果在单元格数据外部单击,或者也可以为固定列、固定行有不同的弹出窗口,而且对于每个单元格,您可以有不同的弹出窗口(我谈论的是设计时弹出窗口,您还可以在显示之前动态创建弹出条目,等等),在事件 OnMouseDown 上放置您想要执行的操作的代码,谈论在设计时创建的 opoup 菜单;如果弹出窗口是在运行时创建的,则认为相同:在 OnMouseDown 上显示或不显示,在自己的 OnPopup 菜单事件上构造菜单。

基本技巧是在事件 OnMouseDown 上进行选择更改,该事件在弹出菜单显示之前触发。

啊,在我的代码中,我不介意单击了哪个按钮,因为如果在选定的多行内单击左键,它也会正常运行(我的代码不会对选择进行任何更改,也不会对行等进行任何更改。它实际上什么也不做,请参阅 if ),但您会看到选择仅更改为一行。

请注意,选择也可以通过按住鼠标左键更改为多重选择,然后移动鼠标并抬起左键,这将选择多个单元格/行。用户必须做出选择的所有这些方式,使得标准组件的内部实现如此错误,在内部编码时并未考虑到所有操作组合。

尝试在按下鼠标左键的同时按 Ctrl 和/或 Shift,并且您在标准网格上移动鼠标,根本没有代码,在 OnMouseMove 上的 ecetp 代码显示 .Row.Col.Selection.···,将会看到您永远认为不可能的事情。我看到有一次告诉 .Col 值是几百万(这是一个不可能的值,因为网格只有几个列),对于 .Row 也是如此(与失败时的值不同) '.上校')。

因此,如果您考虑获取选择内容,请不要相信 .Row.Col 返回的值(错误的概念,它们表示哪个单元格具有焦点,与什么是选择);但您可以使用它们来选择一行或一列(仅当使用允许的黑客网格时才选择列,或者使用带有 goRowSelect=False 的网格并模拟您自己的列选择)。

请始终牢记这一点(请始终这样做):

  • 具有焦点的单元格(.Row.Col 可能会告诉您哪一个)可以是在实际选择之外,是的,它可能会被排除(其中很难强制失败,它会发生,不需要编写任何代码,只需使用鼠标移动单击并与 AltCtrlShift、光标和空格键 可能会发生)。因此,不要相信 .Row.Col 了解有关选择的任何信息(这在概念上是错误的),始终使用 .Selection。….

希望这有助于不要像我一样得到标题,直到我理解这一点:

  1. .Selection.… 只代表所选单元格的一个矩形区域(不介意 goRowSelect 是否为 True或假)。
  2. .Selection:=TGrigRect(Rect(Left,Top,Right,Bottom)); 是将实际选择更改为另一个选择的最佳方法(由您自己确保 Left<=Right< /code> 和 Top<=Bottom 否则事情可能会变得非常糟糕);把代码想象成这么大: .Selection:=TGrigRect(Rect(Min(Left,Right),Min(Top,Bottom),Max(Right,Left),Max(Bottom,Top)); (请参阅 MinMax,它们采用 Maths 单位)。
  3. .Row 给出行号。其上绘制有虚线矩形的特殊单元格,无论它是在选择范围内还是在选择范围之外,如果没有单元格具有焦点,则它也可以是 -1 与选择无关
  4. 。 code> 给出了其上绘制有虚线矩形的特殊单元格的列号,无论它是在选择范围内还是在选择范围之外,如果没有单元格具有焦点,则也可以为 -1 它与选择无关。

理解这四件事,我可以得到过去的东西。我花了太多时间来理解两个不同的概念:具有焦点的单元格(“.Row”和“.Col”)和选定的单元格(.选择...

。PD:请随意分享此信息!

Another way to know the row of a selection on a TStringGrid (it is really the only one):

YourstringGrid.Selection.Top;
YourstringGrid.Selection.Bottom;

If there is only one row selected they must match.

I never see .Selection.··· failing, while i saw YourstringGrid.Row seem to fail for getting the selection row, a lot of times it return -1 when you think it must return other values (see 4 points at the end to understand why seems to fail but it is really not a fail when it return -1, ... it is a concept bas understod).

Selection and cell with foucs are not the same thing... .Selection is for selection, .Row and .Col are for the cell with the focus and has nothing related to the selection, it can be a cell with focus while selection be a total different range of cells (both are different concepts).

Also more, i have detected that YourstringGrid.Row<>YourstringGrid.Selection.Top can be True. When the cell that has the focus is not on the top row of the selection.

Some hacks, tricks, code, etc. shown on Internet are only for when goRowSelect=False if it is set to True such routines do not work well, use them with care.

Hint: On a TStringGrid that has goRowSelect=True it is very buggy to select by code more than a row, changing .Selection sometimes do not update .Row (they do not change the actual cell that has the focus), so if anyone want to select just one row it is better to assign the row value directly to .Row.

Remember: On a TStringGrid with goRowSelect=True talking about what cell has the focus has no sence, so when coding it they do not have in mind such thing at all (.Row and .Col must not be readed when goRowSelect=True). In other words: if you allways have a full row selected what sence has to check the cell that has the focus, there is not such cell, it is the full row, etc... think as that to not get mad by BUGs on internal implementation when mixing focused cell on a goRowSelect=True TStringGrid.

Also worst: Whith goRowSelect=True and some keyboard combinations (Shift+Cursors) and mouse clicks, you can make rare selections, like two or three cells in a column, but not the full rows; remember it has goRowSelect=True and the grid shows only some cells of that rows selected, and if you read .Selection it tells you not all cells on the row are selected (True=(TheGrid.FixedCols+#<TheGrid.Selection.Left)) where # can be more than 1. Again, beware of such BUGs... i can only say... i allways trap selection changes and force full rows to be selectect (i put code on OnSelectCell to ensure all selection is allways full row/s), see a simple code (note i do not care what cell is being selected, by concept the selection must go to a full row or full rows, not a cell; again a rare concept, internal implementation do not think you want to do something when selected cell changes, so this event is supposed to not have code, i put this code to FIX the BUG of selection not being full row/s):

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;

Simplifing: The TStringGrid is too much buggy, i have catch it telling '.Row=13' while at same time .Selection.Top=2 and .Selection.Bottom=5; how can be the active row one outside the selection? etc. It is because '.Row' (and also .Col) do not talk about row selected, talk about what cell has the focus, so seeing .Row to know what row is selected is wrong in concept... you will be seen the row of the cell that has the focus, nothing related with acutal selection cells.

I never see failing this things:

  • .Selection.··· allways tells you the selected area (the area shown as selected)
  • .Row if assigned a value (and grid has goRowSelect=True), that whole row gets selected (i had never tried that without having goRowSelect=True), but only one row.

Not to mention if you want to hack TStringGrid it a lot and make it a multi-row select with more than one contiguos selection at the same time (like ListBox multi select); that makes things very chazy because of all bugs TStringGrid has on .Row and .Selection properties managment.

For such multi slections grids, i recomend allways using a non oficial VCL component instead of the TStringGrid, if i do not remember bad it is called TMultiSelectStringGrid, on it you have a .Selected property for each cell, row and column that is Read/Write able. It really works great when you want a multi-select with Ctrl key pressed, also works great with multi-row selection and multi-column selectiong... just do a loop over the rows, columns or cells to check witch ones are selected and witch ones not. It also has a property .RightMouseSelect (if i do not remember bad) that makes right click to select, and it does well.

Warning, not all code out there to select on right click is correct... a lot of them do not care if you have multi-selection or not... never set .Row if you want to mantain more than one row selected, just check if mouse is outside the selection prior to change the .Selection else right click can make selection to change... so how one could popup menu for more that one row (example of use: popup menu entry called delete for more than one entry at the same time).

In other words (code i really use for VCL standard 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;

Note: I really have that code on a procedure on a unit and call that procedure passing the Grid reference and X, Y coordinates; well to tell the really truth that unit i use is a full hack of TStringGrid with a declaration as type TStringGrid=class(Grids.TStringGrid), so i can use visual design and have sush extra funcions on all of them; just ensure for hack to work to add such unit on the interface uses section at end of the units list (or at least after Grids, never before Grids).

Special hints for controlling PopUp menu been or not been shown and what Popup menu to show:

  • Do it on event OnMouseDown, never on OnMouseUp, neither OnClick, etc.; or popup menu will be shown before selection changes... and sometines when the selection changes (by code) popup will hide inmediatly.
  • If done OnMouseDown there is no need to force the popup menu to be shown by code, it will do it normally; also more, you can cancel the popup to be shown, for example if clicked outside the cells data, or also can have different popups for FixedCols, FixedRows, also for each cell you can have a different popup (i talk about design time popups, you also can dinamically create popup entries prior to be shown, etc), put code for what you want to do allways on event OnMouseDown, talking about opoup menus created on design time; if popup is created on runtime, think the same: show or not show on OnMouseDown, construction of the menu on the own OnPopup menu event.

The basic trick is to do the selection chages on the event OnMouseDown, it is fired before popup menu is shown.

Ah, on my code i do not mind what button was clicked, since if left clicked inside mutiple rows selected, it will also act as normal (my code do not make any change to selection, nor to row, etc. it really does nothing, see the ifs), but you will see the selection changes to only one row.

Beware, selection also can be changed to a multi selection by a mouse left down, sustained, then move mouse and lift left button, that will select more than one cell/row. All this ways that the user has to make selections, makes internal implementation of standard component so buggy, not all combinations of actions had been taken in mind while it was internally coded.

Try to press Ctrl and or Shift while left mouse is pressed and you are moving the mouse on a standard grid with no code at all, ecetp code on OnMouseMove to show .Row, .Col and .Selection.···, will see thing you will not ever think would be possible. I see one time telling .Col value was some millons (an imposible value, since grid has only a few cols), same for .Row (different value than when fail on '.Col').

So do not believe values returned with .Row and .Col if you think on getting what is the selection (wrong concept, they express what cell has the focus, nothing related with what selection is); but you can use them to select one and only one Row or Column (column only if use hacked grid that allow it, or use a grid with goRowSelect=False and simulate a column selection by your own).

And please, allways have in mind this (please do it allways):

  • The cell that has the focus (.Row and .Col may tell you which one is) can be outside the actual selection, yes, it can be out (among it is very hard to force that fail, it occurs, no need to code anything, just using mouse move click and combinations with Alt, Ctrl, Shift, Cursors and Spacebar can happen). So do not trust .Row nor .Col to know anything about the selection (that is wrong on concept), allways use .Selection.···.

Hope this helps not getting headage as i was having till i understand this:

  1. .Selection.··· representes only one rectangular area of cells selected (no mind if goRowSelect is True or False).
  2. .Selection:=TGrigRect(Rect(Left,Top,Right,Bottom)); is the best way to change the actual selection to another one (ensure by your self Left<=Right and Top<=Bottom or else thing can go really bad); think on code as this huge: .Selection:=TGrigRect(Rect(Min(Left,Right),Min(Top,Bottom),Max(Right,Left),Max(Bottom,Top)); (see the Min and Max, they are in Maths unit).
  3. .Row gives the row number of that special cell that has a dotted rectangular drawn on it, no matter if it is inside the selection or outside the selection, also can be -1 if no cell has focus. It has nothing related with selection.
  4. .Col gives the col number of that special cell that has a dotted rectangular drawn on it, no matter if it is inside the selection or outside the selection, also can be -1 if no cell has focus. It has nothing related with selection.

Understanding that four things, i can get headages be something on the past. It took me too much to understand that two different concepts: Cell that has focus ('.Row' and '.Col') and cells selected (.Selection.···).

P.D.: Be free to share this info!

羞稚 2024-09-21 22:18:17

在我的基于 TStringGrid 的控件之一中,我使用 MouseDown/MouseUp 事件来处理该弹出菜单,因为我有两个不同的上下文菜单,具体取决于您单击的 TStringGrid 的哪个区域。就像魅力一样。只需确保在代码之前调用inherited即可。

--
请注意,弹出上下文菜单时调用事件的顺序有些奇怪。更准确地说,当您按下人民币并弹出弹出菜单时,不会立即调用 MouseUp 事件。下次按下鼠标按钮(任何按钮)时会调用它。

另请参阅:TStringGrid - OnMouseUp 未调用!

In one of my TStringGrid-based controls I am using MouseDown/MouseUp event to handle that pop-up menu because I have two different contextual menus, depending on which area of TStringGrid you've clicked. Works like a charm. Just make sure you call inherited BEFORE your code.

--
Please note that there is something strange about the order in which the events are called when you pop-up the contextual menu. More exactly, when you press the RMB and the pop-up menu pops the MouseUp event is not called immediately. It is called next time you press a mouse button (any button).

See this also: TStringGrid - OnMouseUp is not called!

慕烟庭风 2024-09-21 22:18:17

嗯...我无法在 D2010 中重现该问题。

一个快速的想法是,也许问题发生是因为您没有选择任何行?是否会在 Form 的 OnCreate 帮助中首先将 StringGrid 的 Row 预设为 0?

Hmm... I'm unable to duplicate the problem in my D2010.

A quick thought is that perhaps the problem occurs because you did not have any rows selected? Would presetting the StringGrid's Row to, say, 0 first in your Form's OnCreate help?

几味少女 2024-09-21 22:18:17

如果您想要/需要右键单击一个单元格将焦点移动到它(通常用左键单击完成),您可以使用我使用的代码:

type TStringGridHacked=class(Grids.TStringGrid); // This is to have access to hidden (and very usefull) methods, like MoveCol, MoveRow, FocusCell, etc
procedure TMyForm.TheStringGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
   ACol,ARow:Integer;
begin
     if mbRight=Button
     then begin // Right mouse button clicked
               TheStringGrid.MouseToCell(X,Y,ACol,ARow); // Convert X,Y coordinates of mouse to cell Col & Row
               if (FixedCols<=ACol)and(FixedRows<=ARow)
               then begin // Cell is not a header one
                         TStringGridHacked(TheStringGrid).FocusCell(ACol,ARow,True); // Send focus to such cell doing only one move, so triggering SelectCell only once
                    end;
          end;
end;

我一直在使用该 Hack type TStringGridHacked=class(Grids.TStringGrid)< /code> 很久很久了,因为我在互联网上找到了它。

我将这样的 hack(类型声明)放在实现使用之后(如果我在同一单元上多次需要它),或者就像在程序之前的代码中一样(如果我只需要它一次);两种方法都可以正常工作并使代码更加清晰。

If you want / need Right clicking a cell move focus to it (as normally done with left click) you can use the code i use for that:

type TStringGridHacked=class(Grids.TStringGrid); // This is to have access to hidden (and very usefull) methods, like MoveCol, MoveRow, FocusCell, etc
procedure TMyForm.TheStringGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
   ACol,ARow:Integer;
begin
     if mbRight=Button
     then begin // Right mouse button clicked
               TheStringGrid.MouseToCell(X,Y,ACol,ARow); // Convert X,Y coordinates of mouse to cell Col & Row
               if (FixedCols<=ACol)and(FixedRows<=ARow)
               then begin // Cell is not a header one
                         TStringGridHacked(TheStringGrid).FocusCell(ACol,ARow,True); // Send focus to such cell doing only one move, so triggering SelectCell only once
                    end;
          end;
end;

I have been using that Hack type TStringGridHacked=class(Grids.TStringGrid) for a long, long time, since i found it on Internet.

I put such hack (type declaration) just after the implementation uses (if i need it more than once on same unit), or as is in code just before the procedure (if i only need it once); both ways works fine and make code more clear.

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