Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Mouse burrowing 1

Status
Not open for further replies.

enonod

Programmer
Jan 7, 2005
22
GB
I apologise for the lengthy explanation but I hope it is clear.
All objects must be produced on the fly, not ready made components.

In generic terms, I want a large board on top of which are say 4 smaller boards side by side all touching and covering the lower board.
On each of the 4 top boards I want say 50 square objects, all of which touch side by side, and completely cover the boards below.

I want the first board to be a TobjectList containing the 4
TObjectLists for the upper boards which in turn each
contain the list of 50 square objects.

I want to click (the position of) any square and have it react, and also have it's board react because the board knows one of it's squares was clicked.

I tried to use TGraphicControls for the final squares and picked up the mouse event.
However they do not know which lists they belong to and so I cannot call a method in one of the four boards.
OOP wise I seem to be working backwards.

I tried to pick up the mouse event for the bottom board (a TScrollBox) but I cannot get below the squares on top.

I feel that I should be able to click on the first board, pick up the coords, pass coords (modified in relative terms) to the appropriate one of the 4 boards, have the board react, then pass coords on to the square that resides at that position and have it react.

My problems are:
If I use graphic controls as above, I cannot click on the underlying boards.
I don't know how to draw the squares without them being controls. (Say, have a board draw them.)

If I used a bitmap in some way as the bottom board and paint everything on it I presume the repaint would always repaint the whole surface instead of as at present only the square clicked on.

If I did know how to draw them and achieved it, could I click the underlying boards through the images assuming they would not be controls?

Any clues would be gratefully received as I am totally lost. Please keep any explanation fairly simple.

Regards
 
Simply use Form1 as the "large board" with 4 panels as the four "smaller boards." Then you can put TImage components on each of the panels. Use the Owner property to keep track of who owns whom.

Not sure why you need to do all this "on the fly," but here is working code that does what you ask. (Change the icon name to suit your needs.)
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, contnrs;

type
  TBoard = class(TPanel);

  TSquare = class(TImage);

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    Boards:TObjectList;
    Squares:TObjectList;
    procedure MakeABoard(X,Y:integer);
    procedure MakeASquare(ABoard:TBoard;X,Y:integer);
    procedure ImageXMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  x,y:integer;
begin
  Boards := TObjectList.Create(False);
  Squares := TObjectList.Create(False);
  for x := 0 to 1 do
    for y := 0 to 1 do
      MakeABoard(X,Y);
end;

procedure TForm1.MakeABoard(X,Y:integer);
var
  oBoard:TBoard;
  i,j:integer;
begin
  oBoard := TBoard.Create(Self);
  oBoard.Parent := Self;
  Boards.Add(oBoard);
  with oBoard do
    begin
      Name := 'B' + IntToStr(X) + '_' + IntToStr(Y);
      Height := 280;
      Width := 280;
      Top := X * Height;
      Left := Y * Width;
    end;
  for i := 0 to 7 do
    for j := 0 to 7 do
      MakeASquare(oBoard,i,j);
end;

procedure TForm1.MakeASquare(ABoard:TBoard;X,Y:integer);
var
  oSquare:TSquare;
begin
  oSquare := TSquare.Create(Self);
  oSquare.Parent := ABoard;
  Squares.Add(oSquare);
    with oSquare do
      begin
        Name := ABoard.Name + '_S' + IntToStr(X) + '_' + IntToStr(Y);
        Height := 33;
        Width := 33;
        Top := X * Height;
        Left := Y * Width;
        Picture.LoadFromFile('c:\windows\winupd.ico');
        OnMouseDown := ImageXMouseDown;
      end;
end;

procedure TForm1.ImageXMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ShowMessage( 'Name: ' + TSquare(Sender).Name
           + '  Panel: ' + TBoard(TSquare(Sender).Parent).Name )
end;

end.
Note that the components created are set up with Form1 as the owner. That is why the object lists are created with the OwnsObjects property set to False.

I would be inclined to create the 4 panels at design time, but I can understand not wanting to take the effort to put hundreds of images on the form that way.

 
Thank you Zathras for coming to my rescue.
I guessed that if I explained at length I would not make something quite clear.

The description is generic for simplicity.
It didn't occur to me to say that the only items visible are the 200 (say) squares. The sets of boards are not visible and thus cannot be placed at design time (they only exist in the mind of the other objects so to speak).

The startup creates a bottom board, which in turn creates the next layer of boards (a user selectable number). Those boards each create their squares. 'Ownership' (collectivisation of the squares) down the chain as it were, is by this action, established.

Incidentally squares can be resized, created and destroyed by the sequence of clicks and so the quantity is not fixed after initialization, but they all have the same methods and properties available.

The bottom board is solely to permit later addition of a complete new set (as a second bottom board plus etc. as described) and collectivises the 4 boards it contains.
The 4 boards are in a sense simply to collectivise their own 50 (say) squares and differentiate them from the adjacent sets of squares.

When a sequence of squares are clicked (and maybe dragged) tests are carried out to see whether a square is in the same or a different set (board) as another square clicked afterwards (or dragged over) etc. and finally was that set on the same bottom board.

This was why I chose TObjectLists for the boards and not components or controls; I assume there will be a massive overhead if all the squares are left as TGraphicControls.

It must surely be wrong to have the squares query the containers to see which one contains them in order to test rules, they should already know, by the way they were created.
So I cannot use normal ownership of components.

I wanted to have the form or scrollbox or the TObjectLists paint (or draw) the squares but to avoid repainting the whole lot every time one square changed.
At present a square if it changes repaints only itself and so is presumably faster etc.

I hoped you could help me click a square position and pass coords down the line as explained previously ( I seem to have the clickable control at the wrong end of the chain, but the repaint at the correct end. Or something!

I hope this makes it clearer.

Thanks again
 
I don't think I can help you.

I don't understand why you can't use the Owner property of the square to keep track of which board it is on. It is trivial to call a method on the board (or on the board's parent) whenever you need, passing a pointer to the square that you want it to work on.

Without a clearer image of the user interface that you are trying to provide, I don't understand why you can't use simple TStringGrid components. I can only guess that your squares are allowed to move to anyplace the user wants, and not snapped into place (e.g. like a chessboard)?

TObjectList is a very primitive object. Placing pointers to your squares in an object list doesn't accomplish much. In fact, in my example above, they are not even really used.

I just don't understand what you mean by
It must surely be wrong to have the squares query the containers to see which one contains them in order to test rules, they should already know, by the way they were created.
So I cannot use normal ownership of components.
What "query"?
What "rules"?
Who "should already know" what?
 
Thanks Zathras for trying under duress.
I would still like your help, because you provide very useful examples from which I can learn.
I think the best way forward is for me to drop the 'simplified' model and explain the actual job, which I thought might get us entangled in something too big while the example might have been easier.

It will take a few hours for me to put this together so this is a holding reply until I do later today.
I have got the software working but before progressing to the next stage I realised I was partly programming in the old procedural way which meant I was locating objects because I knew where they were in an array structure, the objects did not.
It started to get messy using these array indexes when I realised I had strayed and it was much better to call a method of 'the current object' without me the programmer having to know which one it was.

I presume that I can re-reply to my own reply so that you get it.

Thanks in presumption
 
The project consists of simulating strips of veroboard. If you are not familiar this is used for electronic prototyping and consists of a piece of board covered with copper strips. The strips are drilled along their length at 0.1 inch intervals. The boards therefore consists of a variable number of strips and a variable number of holes,
forming a grid. There may be several such boards but usually one.

Strips may be cut anywhere along their length. If cut but once the original single becomes three items, the original now shorter, plus a single hole with no copper, then the remainder of the original. These are now called Tracks. There could be many cuts.
The Strips have to be invisible containers of Tracks (copper). Initially only one track per Strip.

The need for an invisible Strip which appears to do nothing, is because the Tracks it contains are a set and obey different rules with regard to each other compared to the rules between themselves and Tracks on other Strips. As follows.

Wires may be placed in the Track holes and connected to other Track holes usually on another Strip (i.e. not part of the same set).

Voltages may be connected to a Track and the Track will change colour. If a wire is connected from there to a Track on another strip it will mimic the colour and pass on the voltage.

If another type of component (not wire) is so connected this will not pass the voltage.
If an attempt is made to place a wire across a Cut (i.e. rejoining the original Tracks in a single Strip) a message must warn that removing the cut would achieve the same,
therefore this has to be tested.

It must also be tested that when a Cut is removed as above that Tracks either side do not already contain different voltages.
If a wire is already between two Tracks on different Strips, the placing of a duplicate must be detected and a warning given.

If a voltage is present on a Track and a wire from another Track with a Different voltage is attempted it must be refused. This results in keeping track of chains of wires that may eventually arrive back at a forbidden place and must be detected.
This is but a small sample of properties and tests. Connecting wires is done by Drag n drop.
I had everything working as far as wires and some components were concerned.

When I came to add more I began to realise that I had programmed from the 'outside' using arrays to hold the strips, Tracks and holes (3D) and everything I did in the tests was me looking up the indexes and programming them into procedures. I don't know how to explain this but it got very complicated keeping track. I would for example use an array index to call a certain Track method etc.
The Tracks were TGraphicControl and repainted themselves when invalidated etc. They picked up the mouse clicks.

I realised I had strayed from OOP which ought to have made matters simpler and I rejigged everything.

I produced a TObjectList as a board which contains (creates) a list of Strip Objects.
Each Strip object is again a TObjectList which contains (creates) Track objects.
The Track objects contain an integer array for holes containing codes for various hole contents etc. I thought that it would use less resources than hundreds of hole objects that have few attributes.

I did not draw the Tracks at first, simply tested the mouse click on the underlying board and passed the coords down the line so they selected first a strip and then a
track and then a hole etc.
This meant I could click the mouse and the method for a particular track would respond without me knowing anything about the coords that got me there or even which Track.
Calling Cut Track for any particular Track results in the extra two Tracks being passed back to the Strip for storage in the Set.
This I thought, is the answer!!

Then I had to draw the Tracks and came unstuck. At first I used the Paint method for the underlying TScrollBox Canvas but had to have loops to draw all the Tracks. It flickered
badly, unlike my original which would draw one Track if need be. The loops also drew all the Tracks every time because it was in a loop.
I decided this was no good and made the Tracks TGraphicControls again but when they drew they blocked the underlying TScrollBox and so the mouse would not work. I was back to clicking on the Tracks direct. I do not want that, the new method of clicking the TScrollBox and passing coords was infinitely better.

My problem then is how to draw the tracks on the TScrollBox Canvas (especially individually?) (they have their own coords) but not obscure the canvas. I guess, in other words, how do I get the Tracks to draw themselves on that canvas but use the TScrollBox repaint to control it all.

If you can help I would be grateful and I apologise to everyone else for the unusual length of this.

Regards
 
No apology necessary. It's nice to know where we are headed. I'm at work now and so won't be able to give this my full consideration until later.

One thing I don't understand is the use of TScrollBox. I admit I haven't used it before, so perhaps it is the best way to go, but I can't quite see. Is one TScrollBox used for one strip (track?).

Also, the terminology will take me a while to get in sync.
Calling Cut Track for any particular Track results in the extra two Tracks being passed back to the Strip for storage in the Set.
The difference between a strip and a track is that a track is a strip with a cut? Or is a track a collection of strips?
What is a set? Same as board?

Seems that you need to do some object-oriented analysis here. Sounds like a strip is one object that would have properties such as what board it is on, a list of holes, a list of cuts (initially empty). Another object would be a wire with properties such as which holes it connects. I would guess that a hole is an object with properties such as which strip it is on (and where) and which wire object is connected (or nil).

I still am seeing in my mind a TStringGrid, where each column is a strip and each cell in a column represents a 0.1 inch portion of the strip and is either a hole, a cut or copper. You would use the OnDrawCell event to paint the appropriate graphic corresponding to the value in the cell. Painting would be done only when necessary and would be under the control of Delphi.

Drawing the wires would be something else, however. I have no experience with the drawing objects, but the methods of TCanvas should suffice. You may have to draw the segments of the wires separately as they traverse multiple objects. A property of the wire objects might be a list of line segments and the canvases to paint them on. (But there should be a better way - I just haven't found it yet.)

Clicking and dragging from one hole to another would create a line, update the two holes and re-calculate the entire configuration.

To keep from going insane, you should carefully keep the graphics separate from the computations. The objects need to have the properties to satisfy both requirements independently (calculating the voltages and painting the screen). For example, voltage would be a simple property with simple read/write to a private variable, while color would be a derived property with a getter that looks at the voltage and an internal table of voltages and colors. That way when the user says change the color of -3 from blue to red, all you have to do is revise the table.

 
Thanks for sticking with me Zathras
Starting at the interface, a window (form).
The window contains a status bar various menus and buttons for selection etc.
Because the user chooses the number of Tracks and Holes the window size is unknown and scroll bars are often needed.
To avoid scrolling the status bar and buttons a TScrollBox is used in the window and outside it is a set of axes with numbers and letters matching the strips and holes to know where we are.
These I scroll mathematically to match any scroll bar movement in the ScrollBox, this avoids the up scroll from scrolling the top axis off and the left scroll from scrolling the left axis off. They are therefore always visible and scroll independently.

The TScrollBox contains the image of Tracks. If the Tracks are too numerous or too long then scroll bars appear not on the window but on the scrollbox and are thus shorter than windows scrollbars.
When I scroll, the Tracks move in the TScrollBox (which is of course smaller than the window and whose edges are not visible.
This is all done and works perfectly.

When I click the mouse over the scrollbox it appears as though I am clicking on a hole in a track.
The coords relative to the scrollbox are sent forward by calculating the Y coord divided by the height of a strip, which gives a strip number. I send the X coord to that strip and it is divided by the distance between holes gives a hole number. The strip uses that hole number to calculate which track within that strip is referred to. The strips as yet are not drawn because of my problem, but via the TObjectLists I can tell that I arrive at the right place.
This is all done and works perfectly.

To reiterate the Strip/Track makeup.
A board is the same size as the Tscrollbox and cannot be seen, it is a virtual container and contains one set of Strips.
Strips are horizontal across the board, are also virtual containers and so not visible.
Their purpose is to keep all tracks that are in that one horizontal row together as a set that are distinct from the tracks in the other strips. Strips (and therefore Tracks) lay horizontally one below the other down the board.
Initially a strip contains one track that fills it, let us say 50 holes. The holes go horizontally along the track.
If this track is cut say at hole 20 then the strip now contains one track with 19 holes, one track with one hole (the cut) and on track 30 holes, still (and always) making up the original 50.
If I now cut the track of 30 holes at it's hole 11 I now have five tracks, the three mentioned above except that the last is now 10 holes not 30 plus a new track of 1 hole (the new cut) plus the remainder of 19 holes.
Each of these tracks have the same methods and properties. They all belong to the original strip that contained the original single track. I can rejoin those holes also, under correct conditions.

So a strip receives the X coord for a cut and calls the cut-method of the appropriate track. The track splits itself creating the two new parts and sends them back to the strip on which they reside, the TObjectList. This all works without me using any coords in the program.
This is all done and works perfectly.

Wires are indeed six segmented lines because they are stretchable to allow for laying them in other than straight lines. Once laid they can be pulled around much like a marquee.
These all work perfectly.
The voltages are changeable by colour option selections and work perfectly.

I now want to draw the tracks on the scrollbox so that when I click the mouse it doesn't click a track object it clicks the underlying scrollbox to get a coord.
If I use TGraphicControls for Tracks as I did before, when I click on the track to cut it, it doesnt know where to send the two new ones to. I the programmer have to tell it and I don't want to or I must use a tag on the track to show its strip number, this is bad practice and I am again programming outside the OOP environment. My new way solves this.

To give a better understanding I can e-mail you an exe of the original one working so you could play with it.
I am actually quite pleased with it so far.
I hope this clears up my previous descriptions of strips/tracks and sets. Set doesn't exist its a descriptive word.

If you want a copy I will not use your e-mail address for anything else.
Regards
 
Still not sure why you insist on using a TScrollBar, but here is a way to override it so as to be able to get mouse position on a button down event:
Code:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls, contnrs;

type
  { Special version of TScrollBar to trap mouse down event.}
  TMyScrollBar = class(TScrollBar)
  public
  private
    procedure DefaultHandler( var Message ); override;
  end;

type
  { Main form.}
  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    ScrollBars:TObjectList;
    procedure MakeABar( ABox:TScrollBox; X,Y,H,W:integer );
    procedure ReportMouseDown( AMyScrollBar:TMyScrollBar; X,Y:integer );
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{ TForm1 }

{ Put a TMyScrollBar on ScrollBox1 for demo.  Make it wider than the box.}
procedure TForm1.FormCreate(Sender: TObject);
begin
  ScrollBars := TObjectList.Create( True );
  MakeABar( ScrollBox1, 32, 42, 12, ScrollBox1.Width + 100 );
end;

{ ScrollBars are created without an owner.  This will free them all at once.}
procedure TForm1.FormDestroy(Sender: TObject);
begin
  ScrollBars.Free;
end;

{ Make a MyScrollBar as indicated inside a TScrollBox }
procedure TForm1.MakeABar(ABox: TScrollBox; X, Y, H, W: integer);
var
  oMyScrollBar:TMyScrollBar;
begin
  oMyScrollBar :=TMyScrollBar.Create( nil );
  with oMyScrollBar do
    begin
      Left := X;
      Height := H;
      Top := Y;
      Width := W;
      Parent := ABox;
    end;
  ScrollBars.Add( oMyScrollBar );
end;

{ User clicked on a TMYScrollBar --  Update window title with info.}
procedure TForm1.ReportMouseDown(AMyScrollBar: TMyScrollBar; X,Y:integer);
begin
  Caption := 'WM_LBUTTONDOWN: ' + IntToStr(X) + ',' + IntToStr(Y)
           + '   (Box=' + AMyScrollBar.Parent.Name + ')';
end;

{ TMyScrollBar }

{ Preview WM_LBUTTONDOWN event to do something...}
procedure TMyScrollBar.DefaultHandler(var Message);
begin
  if TMessage(Message).Msg = WM_LBUTTONDOWN then
    with TWMMouse(Message) do
      TForm1(Self.Parent.Parent).ReportMouseDown( Self, XPos, YPos );
  inherited;
end;

end.
Notice that the X,Y mouse coordinates are relative to the TMyScrollBar so it doesn't matter how the TScrollBox is scrolled.

Notice also that I am calling a method on the form to process the event, passing the scrollbar and the X,Y mouse coordinates. I could just as easily stopped at the TScrollBox and had the event there, but since there could be multiple TScrollBox components, it seems to make sense to have the code in just one place.
 
I am confused about the TScrollBar. I think you may have misread my post, I am using a TScrollBox which has auto scrollbars built in. As explained the purpose of this is to avoid scrolling the whole window, lest I lose my status bar and buttons etc.
I have no other scrollbars.

The TScrollbox is a modified version (LMDTools) which has a canvas attached and can detect scroll events unlike the Borland one. I must draw on that and get my mouse coords from that.

Thank you for your example which I will study carefully despite the scrollbar. Your comment about the coords relative to the scrollbox seems to suggest it may hold the key I am looking for.
 
Ok, thanks. I was really wondering about that.

There are other problems with using TScrollBar. (Such as the way it looks, and also I could squeeze out a mouse down event, but so far haven't been able to get the mouse up or click events also when dragging is enabled, I don't even get the mouse down event any more.)

But it seems to me that you want to put a TImage in the scroll box and use that Canvas for your drawing. That way you can get the mouse down/up events for the TImage which remain constant regardless of how the box is scrolled. If you are trying to use the Canvas of the scroll box, you are having a world of problems.

If you anchor the scroll box to top/bottom/left/right of the form, the user can have more control over the work space, meanwhile by using the TImage as your canvas you don't have to be concerned about any of the scrolling.

 
I am a little confused by your comment about the mouse up/down event remaining constant regardless of scroll with Timage.
If a hole in a track is off screen, then when I scroll it into view and click on it the coords must be the physical position in the scrollbox plus the amount of scrollbar movement to give me the true coords for the position that was off screen (the true position on the board). The coords must relate to the size of the board even if not all is visible.

Also if I anchor the Tscrollbox to the four sides of the form as you suggest it will totally cover the form and defeat the purpose of using a Tscrollbox, which is to be able to scroll a portion of the form and leave a portion (on two edges) that do not scroll.

If you could see the running program all would be clear, is there somewhere I can send it?
 
Thanks Zathras
I have tried the code now and believe you have used the scrollbar to simulate one of my tracks.
It certainly appears to work but seems a bit of a cheat??
It could almost be the same as clicking any of my tracks, mutiply the position by track height etc to get the coords relative to the underlying board and then sending them back to select the correct track.
I may be mistaken in my understanding of what you have done, but it is the scrollbar that is picking up the click.

Regards
 
Ok, I'll give this one more try.

It seems to me that you need a coordinate space that allows the user to click within a region and you need to find the node closest to where he clicked in order to do your processing.

What I would do is use a transparent TImage overlay on a TStringGrid (all inside a TScrollBox). That allows the user to click anywhere over a cell and Delphi will calculate the grid coordinates (row/column) corresponding to that cell. You have both the contents of the cell that can contain a value as to what exists there, and if you wish, you can even attach an object with the same coordinates to contain whatever else you may need. (In other words, you can use the object property of the grid instead of handling your own object lists.) You can use the OnDrawCell event of the string grid to paint whatever is appropriate at that coordinate (copper, hole, break, etc.) and use the Canvas of the TImage to draw your connections. This allows the user to click anywhere over a cell and you will know which coordinate is being addressed in terms of rows and columns of the underlying string grid. The contents of the cell can be interpreted by the OnDrawCell handler to paint whatever is appropriate there.

The trick is to set the parent property of the TImage to the string grid so that the TImage will receive the clicks.

Here is a working model to experiment with:

test.pas:
Code:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls, contnrs, ExtCtrls, dialogs, Grids;


type
  { Main form.}
  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    StringGrid1: TStringGrid;
    Image1: TImage;
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
    procedure ShowData(Ident:string; X,Y:integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Parent := StringGrid1;
  Image1.Top := 0;
  Image1.Left := 0;
  Image1.Height := StringGrid1.Height;
  Image1.Width := StringGrid1.Width;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ShowData('MouseDown',X,Y);
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ShowData('MouseUp',X,Y);
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if ssLeft in Shift then
    ShowData('MouseMove',X,Y);
end;

procedure TForm1.ShowData(Ident:string; X, Y: integer);
var
  C,R:integer;
begin
  StringGrid1.MouseToCell(X,Y,C,R);
  Caption := Format('%s at %d,%d (Grid col=%d, row=%d)',[Ident,X,Y,C,R]);
end;

end.

test.dfm:
Code:
object Form1: TForm1
  Left = 329
  Top = 118
  Width = 486
  Height = 291
  BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  KeyPreview = True
  OldCreateOrder = False
  OnCreate = FormCreate
  DesignSize = (
    478
    264)
  PixelsPerInch = 96
  TextHeight = 13
  object ScrollBox1: TScrollBox
    Left = 8
    Top = 6
    Width = 454
    Height = 249
    Anchors = [akLeft, akTop, akRight, akBottom]
    TabOrder = 0
    object Image1: TImage
      Left = 0
      Top = 0
      Width = 553
      Height = 271
      Transparent = True
      OnMouseDown = Image1MouseDown
      OnMouseMove = Image1MouseMove
      OnMouseUp = Image1MouseUp
    end
    object StringGrid1: TStringGrid
      Left = 0
      Top = 0
      Width = 569
      Height = 277
      ColCount = 55
      DefaultColWidth = 10
      FixedCols = 0
      RowCount = 11
      FixedRows = 0
      Options = []
      TabOrder = 0
    end
  end
end
 
Thank you Zathras for your example.
The concept sounds good and I will experiment to death with it and the previous one with the scrollbar which is also very interesting. I am particularly interested in the direct WM useage, I am not familiar with that and will need to study it and play, it seems powerful.
I have the feeling I am on the right path now.

I am going away for a week tomorrow pm and will be taking the laptop (can't leave it alone) so that I can experiment in peace.

Thank you for your time and effort, I will let you know in a week if it worked.
Regards
Don
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top