How do I get screen coordinates of the DBGrid cell
Asked Answered
P

1

6

I want to show popup button or fancy message (with coloured background, etc) just under right-bottom corner of particular cell of the current row.

For now I only figured how to get grid coordinates:
x = DBGrid.DataSource.DataSet.RecNo
y = DBGrid.Columns[index]

There is also TCustomGrid.CellRect, which would do what I want, but it's protected and I don't want to inherit and create another component class.

One crazy workaround I can think of is to save TRect-s in onDrawColumnCell event to some array.

So, what do you think ?

EDIT
How do I get screen coordinates of, say, second cell in the current row ?

Pinkard answered 20/2, 2012 at 2:38 Comment(3)
@downvoter: is question not constructive or too open ended or not a real question ? Could you elaborate, so I could improve it ?Pinkard
I'm not the downvoter, but I'd suspect it's because your question isn't clear. Do you want the currently selected cell, the cell under the mouse, the cell being clicked, or something else?Rung
It's a little better. None of your solutions will work, BTW. RecNo doesn't necessarily mean anything; index order can affect row ordering, Columns[Index] gives you column but not row, and saving coordinates in OnDrawColumnCell won't help, as it has no relationship to the current row in the grid except during the time the cell is being drawn. (I don't have a solution to offer (yet), but I can see the flaws in what you're thinking about doing.)Rung
R
11

You can get the current cell coordinates, using a little deception. :)

Descendants of a component are allowed to access the protected fields of the ancestor class. Since we don't need to do anything except gain access to the protected CellRect method of TDBGrid, we'll create an interposer (do-nothing descendant) that simply allows us access to that protected method. We can then typecast the TDBGrid to that new descendant class and use it to reach the protected method. I name the descendant using THack as a prefix to make it clear that the only purpose of the descendant is to gain access ("hack") the ancestor class.

// implementation
type
  THackDBGrid=class(TDBGrid);

// Where you need the coordinates
var
  CurrRow: Integer;
  Rect: TRect;
begin
  CurrRow := THackDBGrid(DBGrid1).Row;
  Rect := THackDBGrid(DBGrid1).CellRect(ColIndexYouWant, CurrRow);
  // Rect now contains the screen coordinates you need, or an empty
  // rectangle if there is no cell at the col and row specified.
end;

As the OP has indicated in a comment, there's a more detailed description of how this works at delphi.about.com.

Rung answered 20/2, 2012 at 6:55 Comment(8)
works! Thanks a lot. Btw, I've seen this solution once or twice while googling, but somehow thought that's not itPinkard
for those interested why this works, it's called "Protected Hack". The technique exploits the fact that protected members of the class are visible to all methods defined in the same unit as the class. Short example here on SO, more elaborate on by Zarko GajicPinkard
If this answers your question, may I ask why you're not accepting it as correct?Rung
actually I've accepted it :), but then decided to wait a little to let others to answer (and upvote your answer, btw), maybe someone will come up with solution without a hack. The truth is virtually no one willing to answer will look at closed question.Pinkard
actually this is the best solution. you could change THackDBGrid to TDBGridAccess if it makes you less stressed :) casting TDrawGrid(DBGrid1).CellRect will also work, but I like this solution less because TDrawGrid.CellRect implementation might change (for now it's Result := inherited CellRect(ACol, ARow)).Mediant
@kobik: if it makes you less stressed - I'll consider this ))Pinkard
@KenWhite: typo - "CellRect(ColIndexYouWant, Row)" --> "CellRect(ColIndexYouWant, CurrRow)"Pinkard
Good catch. I'll fix it for future reference. Thanks. :)Rung

© 2022 - 2024 — McMap. All rights reserved.