Image navegation mini window

Im trying to make an application in Delphi 7 that can display large images on screen.
I want to know how to use a mini window to navigate across the large image.
Something like the minimap in games like StarCraft where the huge map is on the main screen (can't see it all),
but in the right corner is a mini stretched version of the huge image, and over this a selection tool (a rectangle), then when you move this rectangle over the mini image, the main screen go to this image portion on the huge image at the backgroud.
Sorry for my poor english skills.
Thanks a lot.
LVL 3
big_one01Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

developmentguruPresidentCommented:
Here is a working example using a TPaintBox.  Place a TPaintBox in the upper right side of a form on a new application, attach the 4 events and run it.  Let me know if you need more.
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;
 
type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    procedure PaintBox1Paint(Sender: TObject);
    procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    fDragging : boolean;
    procedure SetPosition(x, y : integer);
  public
    X, Y : integer;
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
const
  MaxMapSize = 1000;
 
{$R *.dfm}
 
procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  fDragging := true;
  SetPosition(X * 10, Y * 10);
end;
 
procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if fDragging then
    SetPosition(X * 10, Y * 10);
end;
 
procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  fDragging := false;
end;
 
procedure TForm1.PaintBox1Paint(Sender: TObject);
var
  aX, aY : integer;
  R : TRect;
 
begin
  with PaintBox1, Canvas do
    begin
      aX := X;
      if X < 50 then
        aX := 50;
      if X > MaxMapSize - 50 then
        ax := MaxMapSize - 50;
 
      aY := Y;
      if Y < 50 then
        aY := 50;
      if Y > MaxMapSize - 50 then
        aY := MaxMapSize - 50;
 
      //change map coord into mini map coord
      aX := aX div 10;
      aY := aY div 10;
 
      R := Rect(aX - 5, aY - 5, ax + 5, ay + 5);
      Rectangle(R);
    end;
end;
 
procedure TForm1.SetPosition(x, y : integer);
begin
  Self.X := X;
  Self.Y := Y;
  PaintBox1.Invalidate;
end;
 
end.

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
big_one01Author Commented:
Thanks.
I try you code but does not work.
I have a TImage over a form, the TImage is loaded with a huge image.
I can navegate the huge image using the form scrollbars.
Im trying to use a "minimap" box (another TImage)  in the form loaded with a stretched version of the huge image. I use your code to create a navegation rectangle in the "minimap", but has no efect of scroll or pan in the huge image at the main form.
What Im doing wrong with your code?
0
developmentguruPresidentCommented:
The code sets coordinates as X, Y in the main form.  I would change these to properties and use a set method with the properties.  Then, whenever a change happens to X or Y, the associated set method will be called.  Inside the set method you need to adjust the scroll bars based on the X, Y from the mini map.  All I did was show you how the mini map portion would work.  You should see a small box on the mini map portion that you are able to move with the mouse.  Did that much work for you?  If not then you just need to assign the methods.  Let me know if you need a more thorough example.
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

big_one01Author Commented:
Thaks.
I solve the issue using a ScrollBox with the huge TImage inside and
a frame over the minimap, then when I pan this frame, I change the scrollbars position to move across the huge image.
But now I need the inverse process, I need an event of the scrollbox where I can check if the scroll bar position has been changed by the user, in order to update the frame position over the minimap, but I cant find something like OnScroll, do you know about maybe some Windows Message that can be checked to know if the scroll bars has been "scrolled".
0
developmentguruPresidentCommented:
You will need to create a descendant class of the TScrollBox and override the message handlers like this:

  TNotifyScrollBox = class(TScrollBox)
  protected
    procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  end;

  Make your TScrollBox a TNotifyScrollBox instead, then you can respond to the messages by changing the location on your mini map.  You can change your scroll box either by registering the control, or you can create it dynamically when your form is created.  You will want to use the message responses to activate new events.

  be very careful.  This could set up a loop that will hang your front end.  If A is changed and tells B to update then B (having changed) tells A to Update, etc, etc...You will likely need to set up 2 variables to indicate if one control or the other is currently updating the other, then in each, check and only do the noptification of change if it is not currently in the middle of another update.

  I do not have time to do the whole componet for you, and the points do not justify that work anyway.

Good Luck.
0
big_one01Author Commented:
Thanks.
I already solve the problem using a third party TScrollBox component.
This have the OnHScrooll and the ONVscroll events, justs as I needed.

0
developmentguruPresidentCommented:
I gave you code that did the "mini map" portion of it for you, I even described what would be needed for the "inverse process" if you wanted to do it yourself.  Now you want to claim you solved it yourself because you found a third party control that does just the last part of it?!?  I think I deserve the points on this one.
0
big_one01Author Commented:
I try the code that you give to me, but this code dont help me with the problem.
In the first part as you cant see I solve the issue using a ScrollBox with the huge TImage inside, because in your words " All I did was show you how the mini map portion would work. You should see a small box on the mini map portion that you are able to move with the mouse.  Did that much work for you?" As any that try the code can see, you just draw a rectangle with a TPaintBox, thats not a solution!
And in the second part, you say that I have to create my own component because in you words "I do not have time to do the whole componet for you, and the points do not justify that work anyway." That is not a solution either
Thanks anyway.
0
developmentguruPresidentCommented:
There are two parts to your problem, the mini map and the scrolling of the main image.  I gave you working code for the mini map and told you everything that would be needed in order to tie it to the scrolling part of it.

The paint box drawing a square is the solution to the mini map portion.  You are able to move the box with your mouse.  Moving it with your mouse generates changes to an X and Y coordinate that can be used to change the scroll box position.  The code I gave you works, evidently you did not try it out.

I was trying to help you solve a problem, not necessarily do all the work for you.  I did part of the work and told you how the rest could be done by you.  That is all that should be required to be considered an answer.
0
Vee_ModCommented:
OK - PAQ'd the solutions to developmentguru, then re-added the 125 points to big_one01's account.


Vee_Mod
Experts Exchange Moderator
0
kretzschmarCommented:
well, thank Vee_Mod to make it possible

At the Meantime i tried myself a solution

instead of using a scrollbox i used a panel as container (-> so no scrollbars)
it can be navigated through the MiniMap or by dragging with the mouse

the dfm


object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 447
  ClientWidth = 535
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object PanMiniMap: TPanel
    Left = 0
    Top = 0
    Width = 101
    Height = 447
    Align = alLeft
    TabOrder = 0
    object MiniMap: TImage
      Left = 0
      Top = 0
      Width = 100
      Height = 100
      Proportional = True
      OnMouseDown = MiniMapMouseDown
      OnMouseMove = MiniMapMouseMove
      OnMouseUp = MiniMapMouseUp
    end
    object MiniMapNavigator: TShape
      Left = 0
      Top = 0
      Width = 41
      Height = 41
      Margins.Left = 0
      Margins.Top = 0
      Margins.Right = 0
      Margins.Bottom = 0
      Brush.Style = bsClear
      Pen.Mode = pmNotXor
      OnMouseDown = MiniMapNavigatorMouseDown
      OnMouseMove = MiniMapNavigatorMouseMove
      OnMouseUp = MiniMapNavigatorMouseUp
    end
    object BtnLoad: TButton
      Left = 15
      Top = 106
      Width = 75
      Height = 25
      Caption = '&Load'
      TabOrder = 0
      OnClick = BtnLoadClick
    end
  end
  object PanBigPic: TPanel
    Left = 101
    Top = 0
    Width = 434
    Height = 447
    Align = alClient
    TabOrder = 1
    OnResize = PanBigPicResize
    ExplicitLeft = 111
    ExplicitTop = 161
    ExplicitWidth = 535
    ExplicitHeight = 342
    object BigPic: TImage
      Left = 0
      Top = 0
      Width = 105
      Height = 105
      AutoSize = True
      OnMouseDown = BigPicMouseDown
      OnMouseMove = BigPicMouseMove
      OnMouseUp = BigPicMouseUp
    end
  end
  object OpenPictureDialog1: TOpenPictureDialog
    Left = 192
    Top = 8
  end
end

Open in new window

0
kretzschmarCommented:
the unit

unit BigPicWithMiniMap_u;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ExtDlgs;
 
type
  TForm1 = class(TForm)
    PanMiniMap: TPanel;
    PanBigPic: TPanel;
    OpenPictureDialog1: TOpenPictureDialog;
    BigPic: TImage;
    MiniMap: TImage;
    BtnLoad: TButton;
    MiniMapNavigator: TShape;
    procedure BtnLoadClick(Sender: TObject);
    procedure PanBigPicResize(Sender: TObject);
    procedure BigPicMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure BigPicMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure BigPicMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure MiniMapMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MiniMapMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure MiniMapMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MiniMapNavigatorMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MiniMapNavigatorMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure MiniMapNavigatorMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private-Deklarationen }
    PicLoaded : Boolean;   //Act only if there is one Picture loaded
    BigPicDragX : Integer;
    BigPicDragY : Integer;
    BigPicInMove : Boolean;
    MiniMapNavigatorInMove : Boolean;
    MiniMapDisplayWidth : Integer;
    MiniMapDisplayHeight : Integer;
    procedure CalcMiniMapBounds;
    procedure CalcMiniMapNavigatorBounds;
    procedure CalcMiniMapNavigatorPosition(ATop,ALeft : Integer);
    procedure CalcBigPicBounds(ATop,ALeft : Integer);
  public
    { Public-Deklarationen }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
uses jpeg;  //add JPeg-Support
 
//Init
procedure TForm1.FormCreate(Sender: TObject);
begin
  //Avoid Dragging Flicker
  PanBigPic.DoubleBuffered := true;
  PanMiniMap.DoubleBuffered := true;
  //No Picture loaded yet
  PicLoaded := False;
end;
 
 
//Handle BigPic Mouse-Events
procedure TForm1.BigPicMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if PicLoaded then
  begin
    BigPicInMove := True;
    BigPicDragX := X;
    BigPicDragY := Y;
  end;
end;
 
procedure TForm1.BigPicMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var l,t : Integer;
begin
  if BigPicInMove then
  begin
    if BigPicDragY - y <> 0 then
      t := BigPic.Top - (BigPicDragY - y)
    else
      t := BigPic.Top;
    if BigPicDragX - x <> 0 then
      l := BigPic.Left - (BigPicDragX - x)
    else
      l := BigPic.Left;
    CalcBigPicBounds(t,l);
  end;
end;
 
procedure TForm1.BigPicMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  BigPicInMove := False;
end;
 
 
//Handle MiniMap Mouse-Events
procedure TForm1.MiniMapMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if PicLoaded then
  begin
    MiniMapNavigatorInMove := True;
    CalcMiniMapNavigatorPosition(y,x);
  end;
end;
 
procedure TForm1.MiniMapMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if MiniMapNavigatorInMove then
    CalcMiniMapNavigatorPosition(y,x);
end;
 
procedure TForm1.MiniMapMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  MiniMapNavigatorInMove := False;
end;
 
//Handle MiniMapNavigator Mouse-Events
procedure TForm1.MiniMapNavigatorMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var P : TPoint;
begin
  if PicLoaded then
  begin
    MiniMapNavigatorInMove := True;
    P := MiniMap.ScreenToClient(MiniMapNavigator.ClientToScreen(Point(x,y)));
    CalcMiniMapNavigatorPosition(p.y,P.x);
  end;
end;
 
procedure TForm1.MiniMapNavigatorMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var P : TPoint;
begin
  if MiniMapNavigatorInMove then
  begin
    P := MiniMap.ScreenToClient(MiniMapNavigator.ClientToScreen(Point(x,y)));
    CalcMiniMapNavigatorPosition(p.y,P.x);
  end;
end;
 
procedure TForm1.MiniMapNavigatorMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  MiniMapNavigatorInMove := False;
end;
 
//Handle FormResize
procedure TForm1.PanBigPicResize(Sender: TObject);
begin
  if PicLoaded then
    CalcBigPicBounds(BigPic.Top,BigPic.Left);
end;
 
procedure TForm1.BtnLoadClick(Sender: TObject);
begin
  if OpenPictureDialog1.execute then
  begin
    MiniMap.Picture.LoadFromFile(OpenPictureDialog1.filename);
    BigPic.Picture.LoadFromFile(OpenPictureDialog1.filename);
    PicLoaded := True;
    BigPic.Top := 0;
    BigPic.Left := 0;
    CalcMiniMapBounds;
    CalcBigPicBounds(BigPic.Top,BigPic.Left);
  end;
end;
 
//Depending Calculations
 
procedure TForm1.CalcMiniMapBounds;
begin
  //Get the real Height and Width, because the MinMap is proportianal stretched
  //Init, As we have a Square as MiniMap
  MiniMapDisplayHeight := MiniMap.Height;
  MiniMapDisplayWidth := MiniMap.Width;
  //But is the Loded not a Square, correct it dependent
  if MiniMap.Picture.Height > MiniMap.Picture.Width then
    MiniMapDisplayWidth := round(MiniMap.Width * (MiniMap.Picture.Width/MiniMap.Picture.Height))
  else
    if MiniMap.Picture.Height < MiniMap.Picture.Width then
      MiniMapDisplayHeight := round(MiniMap.Height * (MiniMap.Picture.Height/MiniMap.Picture.Width));
 
end;
 
procedure TForm1.CalcBigPicBounds(ATop,ALeft : Integer);
begin
  //keep image in bounds
  //Calc Left
  If (BigPic.Width < PanBigPic.ClientWidth) or
      (ALeft > 0) then
    BigPic.Left := 0
  else
    if abs(ALeft) + PanBigPic.ClientWidth > BigPic.Width then
      BigPic.Left := PanBigPic.ClientWidth - BigPic.Width
    else
      BigPic.Left := ALeft;
  //Calc Top
  If (BigPic.Height < PanBigPic.ClientHeight) or
      (ATop > 0) then
    BigPic.Top := 0
  else
    if abs(ATop) + PanBigPic.ClientHeight > BigPic.Height then
      BigPic.Top := PanBigPic.ClientHeight - BigPic.Height
    else
      BigPic.Top := ATop;
  //Adjust MiniMapNavigator
  CalcMiniMapNavigatorBounds;
end;
 
procedure TForm1.CalcMiniMapNavigatorBounds;
Var
  h,w : Integer;
begin
 
  MiniMapNavigator.Left := trunc(abs(BigPic.left)*(MiniMapDisplayWidth/BigPic.Width));
  MiniMapNavigator.Top := trunc(abs(BigPic.Top)*(MiniMapDisplayHeight/BigPic.Height));
  MiniMapNavigator.Width := trunc(PanBigPic.ClientWidth*(MiniMapDisplayWidth/BigPic.Width)) + 1;
  MiniMapNavigator.height := trunc(PanBigPic.ClientHeight*(MiniMapDisplayHeight/BigPic.Height)) + 1;
  //Keep the MiniMapNavigator UpToDate
  MiniMapNavigator.Repaint;
end;
 
procedure TForm1.CalcMiniMapNavigatorPosition(ATop,ALeft : Integer);
var t,l : Integer;
begin
  t := ATop - (MiniMapNavigator.Height div 2);
  l := ALeft - (MiniMapNavigator.Width div 2);
  t := -trunc(t/(MiniMapDisplayHeight/BigPic.Height));
  l := -trunc(l/(MiniMapDisplayWidth/BigPic.Width));
  CalcBigPicBounds(t,l);
end;
 
end.

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.