?
Solved

Application's Interactive Tutorial

Posted on 2003-02-25
13
Medium Priority
?
171 Views
Last Modified: 2010-04-04
  I'm writing a tutorial for my application but Im having a problem when I simulate the mouse envents (with Mouse_Event and SetCursorPos). I'm doing the clicks ok but when I click over a Action Menu Bar the mouse continue moving but the menu is just expanded after the movement. I tried to use Application.ProcessMessages method after the fake click but it stops the mouse movement as waiting some answer and just continue the movement if I press ESC until the menu is completely collapsed. I tried to use the Refresh, Repaint, Invalidate Action Menu Bar methods but it doen't work! I don't know what to do.

                regards,

                     Anderson
0
Comment
Question by:assilva
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 3
13 Comments
 
LVL 34

Expert Comment

by:Slick812
ID: 8020909
hello assilva, maybe you could try a TTimer to call some of the mouse events, and or the SetCursorPos. The Timer might give you app time to do painting and menu display and other display updates. If you are not allowing any messages to be processed, then no menu display or painting will occure until the messages are processed. It seems that when you do call  Application.ProcessMessages, there is some problem for you???? Maybe show some code for when you call  Application.ProcessMessages?
0
 
LVL 6

Expert Comment

by:swift99
ID: 8022350
Check the PAQ's since October.

There was a recent question where the windows API for this purpose was explored and explained in some depth.  You don't need to get fancy with timers and such, merely learn the correct Windows API.
0
 

Author Comment

by:assilva
ID: 8028359
 I've tried to find the PAQ about menus and I didn't find it. (I've looked in a lot of PAQs, believe me). Anyway, I think a timer will help me in implementation of my tutorial, but, in fact, I really don't know how to get my "next step" event and get correct step in timer, but it's just implementation and not technical question, if anyone have any idea I'll appreciate. Meanwhile, I'll leave this question open for anyone who knows the more "correct" answer could post about the menus. But, sorry swift, the slick have the better answer that I have 'til now :)

             thanks
 
                    Anderson
                 
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:assilva
ID: 8028370
 I've tried to find the PAQ about menus and I didn't find it. (I've looked in a lot of PAQs, believe me). Anyway, I think a timer will help me in implementation of my tutorial, but, in fact, I really don't know how to get my "next step" event and get correct step in timer, but it's just implementation and not technical question, if anyone have any idea I'll appreciate. Meanwhile, I'll leave this question open for anyone who knows the more "correct" answer could post about the menus. But, sorry swift, the slick have the better answer that I have 'til now :)

             thanks
 
                    Anderson
                 
0
 

Author Comment

by:assilva
ID: 8028373
 I've tried to find the PAQ about menus and I didn't find it. (I've looked in a lot of PAQs, believe me). Anyway, I think a timer will help me in implementation of my tutorial, but, in fact, I really don't know how to get my "next step" event and get correct step in timer, but it's just implementation and not technical question, if anyone have any idea I'll appreciate. Meanwhile, I'll leave this question open for anyone who knows the more "correct" answer could post about the menus. But, sorry swift, the slick have the better answer that I have 'til now :)

             thanks
 
                    Anderson
                 
0
 

Author Comment

by:assilva
ID: 8028381
sorry for the repeated answers, i had problems with my browser...
0
 
LVL 34

Expert Comment

by:Slick812
ID: 8028545
I never knew Timers were fancy :-)  ??
 assilva,  you did not give much information about what you want to do and how you are trying to do it with the mouse event and SetCursorPos. . . I just sugested the TTimer because it was very general and might cover many situations, but there is nothing wrong with using a timer correctly. . .  anyway you say

" in fact, I really don't know how to get my "next step" event and get correct step in timer"

I have no Idea what your next step is or anything about the correct step. .

in your code you must have a sequence of "Events" and SetCursorPos, in a Timer event you might use a case statement and increase a Counter integer to advance the event      ; ; ;

  private
    Count: Integer;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
case Count of
0: FirstEvent;
1: SesondEvent;
2: begin
   if aStop Then Timer1.Enabled = False;
   ThirdEvent;
   end;
3: begin
   Timer1.Interval := 100;
   FourthEvent;
   end;
4: begin
   Timer1.Enabled = False;
   FifthEvent;
   end;
end;

Inc(Count);
end;


you will need to set Count to Zero when you start the timer
0
 

Author Comment

by:assilva
ID: 8032661
  What I need to do is an tutorial, I mean, a form with the text about the application (ex: "This is the main menu. The first item is..." while I move the mouse cursor through the items that i'm explaning.) and my application forms. Almost like the MS Office's help. I don't know what fancy exactly means but, I don't think you're wrong or anything with the timer, but the only fact is that neither you nor me knows how to "wait" the menu paint message and the timer "wait" for us. It's an alternative, just it. There other way to do it. The only one weird fact is that I thought it's more commom than it is. I mean, I didn't find anything about anybody who did the same thing as I'm doing, but it's an obvious thing to do with an application which we don't want to spend time with training.

          thanks for your help

                    Anderson
0
 

Author Comment

by:assilva
ID: 8032758
  Ow, and answering your question up there, this is the code that I use with Application.ProcessMessages

procedure SetStep;
begin
  case Step of
    0:begin   //go to File Menu
    SetFocus;
        MoveToAndClip(Mouse.CursorPos.X,Mouse.CursorPos.X);
        while (Mouse.CursorPos.X > 40) or (Mouse.CursorPos.Y > 40) do
        begin
          MoveToAndClip(Mouse.CursorPos.X-3,Mouse.CursorPos.Y-3);
          Sleep(8);
          Screen.Cursor := crArrow;
        end;
        Screen.Cursor := crArrow;
        MoveToAndClip(35,35);
      end;
    1:begin //ir até o menu produto/servico
        MoveToAndClip(35,35);
        Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
        WaitMessage;
        MoveToAndClip(35,60);

        Mouse_Event(MOUSEEVENTF_MOVE,60,0,0,0);
//        SetFocus;
      end;
    2:begin //ir até o grupo
        //SetFocus;
        Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
        //frmTutor.SetFocus;
      end;
  end;
0
 

Author Comment

by:assilva
ID: 8032759
  Ow, and answering your question up there, this is the code that I use with Application.ProcessMessages

procedure SetStep;
begin
  case Step of
    0:begin   //go to File Menu
    SetFocus;
        MoveToAndClip(Mouse.CursorPos.X,Mouse.CursorPos.X);
        while (Mouse.CursorPos.X > 40) or (Mouse.CursorPos.Y > 40) do
        begin
          MoveToAndClip(Mouse.CursorPos.X-3,Mouse.CursorPos.Y-3);
          Sleep(8);
          Screen.Cursor := crArrow;
        end;
        Screen.Cursor := crArrow;
        MoveToAndClip(35,35);
      end;
    1:begin //ir até o menu produto/servico
        MoveToAndClip(35,35);
        Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
        WaitMessage;
        MoveToAndClip(35,60);

        Mouse_Event(MOUSEEVENTF_MOVE,60,0,0,0);
//        SetFocus;
      end;
    2:begin //ir até o grupo
        //SetFocus;
        Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
        Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
        //frmTutor.SetFocus;
      end;
  end;
0
 

Author Comment

by:assilva
ID: 8032839
d*mn it, my keyboard have a problem with [Enter] then it posted when I was editing, here, there is the final code with english comments


procedure TAppForm.SetStep;
begin
 case Step of
  0:begin   //go to File Menu
     SetFocus;
     MoveToAndClip(Mouse.CursorPos.X,Mouse.CursorPos.X);
                        //procedure that I write
                        //just clip the cursor in the
                        //point to user don't move
    while (Mouse.CursorPos.X > 40) or (Mouse.CursorPos.Y > 
                                                    40) do
     begin
       MoveToAndClip(Mouse.CursorPos.X-3,Mouse.CursorPos.Y-
                                                       3);
       Sleep(8); //give time to go slower
       Screen.Cursor := crArrow;  //garantee that cursor  
                      //don't change if pass over an edit
                      // or something
     end;
      MoveToAndClip(35,35); //final point of menu
    end;
    1:begin //go to Products/Services menu
       MoveToAndClip(35,35);
       Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);  
                                   //set the focus...
       Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);    
           //...on the menu (setfocus method don't work)
       Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);  
                               //click down...
       Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);    
                       //...click up on the menu item
        Application.ProcessMessages;
                  //if I run, the application stop here
                  //and don't process down here until the
                  // menu is completely collapsed with
                  //ESC key.      
        //WaitMessage;  I tried this procedure but it
                     //doesn't work too

        MoveToAndClip(35,60); //go to the first item on  
                              //submenu

        //  Mouse_Event(MOUSEEVENTF_MOVE,60,0,0,0);  
            //tried this one to, but doesn't work anyway
      end;
      (*
        rest of process but just for mouse movement
       *)
  end;
0
 
LVL 34

Accepted Solution

by:
Slick812 earned 200 total points
ID: 8038703
Here's some code that will do a very simple "Teaching" type of program. The Main Form (Form1) has nothing special, you can make it as you need. There is a second Form (Form2), which is the "Information" text show form. It has a border style of bsNone, and a white color. It is sized each time it it used ti the size need for displaying all of the text. you can adjust the width in the ShowInfo(X, Y, nWidth: Integer; Text: String) procedure.
There are two TTimers, the first Timer1, does all of the cursor movement and mouse events and the Information window display. The Timer2, just does cursor movement. In this example, I do not use any user input, except the space bar, which will cancel the "Show", but you could add a timer stop and a user key press to continue, for extended text reads. There is a Main Menu, which I move to and click on, be WARNED, if you put any Application.ProcessMessages; after the first mouseevent on a menu item WIERD MIGHT WILL HAPPEN.
 There are 2 buttons, one to strat the "Show" and the other to "Show" info for.

Form1 code is -


unit Instruct1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, StdCtrls, ExtCtrls, Info1;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Edit1: TMenuItem;
    Stuff1: TMenuItem;
    New11: TMenuItem;
    Open1: TMenuItem;
    N1: TMenuItem;
    Close1: TMenuItem;
    Copy1: TMenuItem;
    Paste1: TMenuItem;
    Choise1: TMenuItem;
    Num11: TMenuItem;
    Num21: TMenuItem;
    Num31: TMenuItem;
    First1: TMenuItem;
    Second1: TMenuItem;
    Third1: TMenuItem;
    Edit2: TEdit;
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    Timer1: TTimer;
    Timer2: TTimer;
    Label2: TLabel;
    Label3: TLabel;
    procedure Close1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Num11Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure New11Click(Sender: TObject);
    procedure Open1Click(Sender: TObject);
  private
    { Private declarations }
    EventNum: Integer;
    EndPos, StartPos, Mover: TPoint;
    Radian1: Extended;
    PixelMov: Integer;
    procedure ShowInfo(X, Y, nWidth: Integer; Text: String);
    procedure MoveCursor(X, Y: Integer);
    //procedure HopOut(var Msg: TMessage); message WM_TIMER{WM_USER + 324};
  public
    { Public declarations }
    ShowGo: Boolean;
    procedure StopShow;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses Math;

{procedure TForm1.HopOut(var Msg: TMessage);
begin
Timer1.Enabled := False;
Application.ProcessMessages;
EventNum := 9;
Timer1.Enabled := True;
Label3.Caption := 'After';
end;}

procedure TForm1.MoveCursor(X, Y: Integer);
begin
GetCursorPos(StartPos);
EndPos.x := X;
EndPos.y := Y;
PixelMov := 15;
Mover.x := 0;
Mover.y := Round(Sqrt(SumOfSquares([abs(EndPos.y-StartPos.y),abs(EndPos.x-StartPos.x)]))) div PixelMov;
Radian1 := DegToRad(180 * (1 + ArcTan2(EndPos.y-StartPos.y, EndPos.x-StartPos.x) / Pi));
Timer2.Enabled := True;
end;

procedure TForm1.StopShow;
begin
EventNum := 1000;
Timer1.Enabled := False;
Timer2.Enabled := False;
Application.ProcessMessages;
ShowMessage('Instruction Has Been Canceled');
ShowGo := False;
end;

procedure TForm1.Close1Click(Sender: TObject);
begin
Close;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption := 'First One';
end;

procedure TForm1.Num11Click(Sender: TObject);
begin
Label1.Caption := 'Choise1';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
if ShowGo then Exit;
ShowGo := True;
EventNum := 0;
Timer1.Interval := 55;
Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
nRect: TRect;
begin
case EventNum of
  0: begin
     Timer1.Interval := 6000;
     ShowInfo(Left+ (Width div 2)-80, Top + (Height div 2)-20, 160,
     'This will show you how to use this program by moving the cursor and clicking on'+
     ' controls and showing you what will happen and what to do next'#10'If you need to cancel'+
     ' press the "Space" key on your keyboard');
     EventNum := 1;
     end;
  1: begin
     Timer1.Enabled := False;
     Timer1.Interval := 500;
     //Form2.Hide;
     ShowWindow(Form2.Handle, SW_HIDE);
     GetWindowRect(Button1.Handle, nRect);
     MoveCursor(nRect.Left+15, nRect.Top+10);
     EventNum := 2;
     end;
  2: begin
     Timer1.Interval := 4000;
     GetWindowRect(Button1.Handle, nRect);
     ShowInfo(nRect.Right+8, nRect.Top, 100,
     'This Button will do something when you press it.'#10'Show new text or whatever');
     EventNum := 3;
     end;
  3: begin
     Timer1.Interval := 1000;
     Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
     Application.ProcessMessages;
     Sleep(220);
     Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
     //Button1.Click;
     EventNum := 4;
     end;
  4: begin
     Timer1.Enabled := False;
     //Form2.Hide;
     ShowWindow(Form2.Handle, SW_HIDE);
     Timer1.Interval := 500;
     GetMenuItemRect(Handle,MainMenu1.Handle, 0, nRect);
     MoveCursor(nRect.Left+15, nRect.Top+10);
     EventNum := 5;
     end;
  5: begin
     //Timer1.Enabled := False;
     Timer1.Interval := 4000;
     GetMenuItemRect(Handle,MainMenu1.Handle, 0, nRect);
     ShowInfo(nRect.Left-128, nRect.Top-4, 120,
     'This File Menu lets you pick an Item to click'#10'There are 5 items on this one. The first item will be clicked next');
     EventNum := 6;
     end;
  6: begin
     Timer1.Interval := 1000;
     Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
     {Application.ProcessMessages;
     WARNING - DO NOT PUT ANY Application.ProcessesMessages
     after the first mouse event on a menu Item. . . .
     Wierd stuff happens}
     Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
     EventNum := 7;
     end;
  7: begin
     Timer1.Enabled := False;
     Timer1.Interval := 1000;
     GetMenuItemRect(Handle,MainMenu1.Items[0].Handle, 0, nRect);
     MoveCursor(nRect.Left+15, nRect.Top+10);
     EventNum := 8;
     end;
  8: begin
     Form2.Hide;
     ShowWindow(Form2.Handle, SW_HIDE);
     ShowInfo(Form2.Left, Form2.Top, 100,
     'This First menu item "New" will change a labels text if you click it');
     Timer1.Interval := 3000;
     EventNum := 9;
     end;
  9: begin
     Timer1.Enabled := False;
     Timer1.Interval := 1000;
     GetMenuItemRect(Handle,MainMenu1.Items[0].Handle, 1, nRect);
     MoveCursor(nRect.Left+15, nRect.Top+10);
     EventNum := 10;
     end;
  10: begin
     Form2.Hide;
     ShowWindow(Form2.Handle, SW_HIDE);
     ShowInfo(Form2.Left, Form2.Top, 100,
     'This Second menu item "Open" will change a labels text if you click it, So Let''s Click it!');
     Timer1.Interval := 3000;
     EventNum := 11;
     end;
  11: begin
      Timer1.Interval := 1000;
      EventNum := 12;
      Mouse_Event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
      Mouse_Event(MOUSEEVENTF_LEFTUP,0,0,0,0);
      EventNum := 12;
      end;
  12: begin
     Timer1.Enabled := False;
     //Form2.Hide;
     ShowWindow(Form2.Handle, SW_HIDE);
     ShowGo := False;
     Label1.Caption := 'The End';
     ShowMessage('Show is Over');
     end;
  13: begin
     Timer1.Enabled := False;
     end;
  else Timer1.Enabled := False;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
EventNum := 0;
ShowGo := False;
end;

procedure TForm1.ShowInfo(X, Y, nWidth: Integer; Text: String);
var
SRect: TRect;
begin
Form2.Text1 := Text;
SRect := Rect(0, 0, nWidth, 100);
InflateRect(SRect,-8,-8);
DrawText(Form2.Canvas.Handle, PChar(Text), Length(Text), SRect,
         DT_EDITCONTROL or DT_WORDBREAK or DT_CALCRECT);
{WARNING, using SetWindowPos on a Form will cause the VCL to lose track of the
Show and Hide state of that form}
SetWindowPos(Form2.Handle, HWND_TOP, X, Y, nWidth, SRect.Bottom+8,
             SWP_NOACTIVATE or SWP_SHOWWINDOW);
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
{Timer2 only does Cursor movement}
SetCursorPos(Round(StartPos.x-Cos(Radian1)*(PixelMov*Mover.x)),
             Round(StartPos.y-Sin(Radian1)*(PixelMov*Mover.x)));
Inc(Mover.x);
if (Mover.x > Mover.y) or (Mover.x > 3000) then
  begin
  Timer2.Enabled := False;;
  SetCursorPos(EndPos.x, EndPos.y);
  Timer1.Enabled := True;
  end;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #32 then
StopShow;
end;

procedure TForm1.New11Click(Sender: TObject);
begin
Label2.Caption := 'New1 Click';
end;

procedure TForm1.Open1Click(Sender: TObject);
begin
Label2.Caption := 'Open1 Click';
end;

end.

 - - - - - - -  - - -  - -  - - - - - - -  --  - - - - - - - - - - - - - -


Form2 code is -


unit Info1;

interface

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

type
  TForm2 = class(TForm)
    procedure FormClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
  public
    { Public declarations }
    Text1: String;
  end;

var
  Form2: TForm2;

implementation

{$R *.DFM}
uses Instruct1;

procedure TForm2.FormClick(Sender: TObject);
begin
ShowWindow(Form2.Handle, SW_HIDE);
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
BorderStyle := bsNone;
Color := clWhite;
Canvas.Pen.Color := clBlue;
Canvas.Pen.Width := 2;
end;

procedure TForm2.FormPaint(Sender: TObject);
var
CRect: TRect;
begin
windows.GetClientRect(Form2.Handle, CRect);
InflateRect(CRect,-8,-8);
Canvas.Rectangle(1,1, Width, Height);
DrawText(Canvas.Handle, PChar(Text1), Length(Text1), CRect,
         DT_EDITCONTROL      or DT_EXPANDTABS or DT_WORDBREAK);
end;

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = #32 then
Form1.StopShow;
end;

end.
0
 

Author Comment

by:assilva
ID: 8041568
  I'm really grateful for your help! You made more than I needed, thanks a lot!

             regards

                  Anderson
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question