Can a Dialog be made to "STAYONTOP"?

Technical support and scripting issues

Moderators: Dorian (MJT support), JRL

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Mon Feb 21, 2011 9:27 pm

Yes, thanks Rain... I did not know about this property of dialogs:

FormStyle = fsStayOnTop
JRL wrote:Do you need to set OnTaskbar to True for fsStayOnTop to work? I tried your sample without OnTaskbar set to True and it seemed to work.
I am also wondering this as I need to have OnTaskbar set to False so I am hoping that is not a requirement. My example macro below sets OnTaskBar to False and it still seems to work fine.

Rain, your method seemed to solve another problem for me. I have a stay-on-top dialog with an Edit field. With my old code, the cursor blinks in the Edit field whether or not the Dialog itself has keyboard focus. This is confusing to a user as a blinking cursor usually indicates that when you type, the chars will show up there... but without keyboard focus on the actual dialog, those chars are going to some other window.

Using your method, it automatically takes care of that blinking cursor in the Edit field... if the dialog does not have keyboard focus, no blinking cursor... when it has keyboard focus, the blinking cursor appears... this is exactly what I was looking for. All is fine... running uncompiled.

However when I compile it, the dialog will not stay on top. :( So I went back to using JRL's trick of continually getting the window's position and then moving it to where it already is... in the idle loop... and yes, it makes the dialog say on top... but it also brings the blinking cursor back in the Edit field... even when the dialog itself does not have keyboard focus:

Code: Select all

Dialog>Dialog1
object Dialog1: TForm
  Left = 251
  Top = 97
  HelpContext = 5000
  BorderIcons = [biSystemMenu]
  Caption = 'Dialog Stay On Top Example'
  ClientHeight = 77
  ClientWidth = 213
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  FormStyle = fsStayOnTop
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 172
    Height = 13
    Caption = '1. Set the FormStyle to fsStayOnTop'
  end
  object Edit1: TEdit
    Left = 46
    Top = 37
    Width = 121
    Height = 21
    TabOrder = 0
    Text = 'Edit1'
  end
end
EndDialog>Dialog1

AddDialogHandler>Dialog1,,OnClose,Exit
Show>Dialog1

Label>Loop
wait>.01

//If macro is compiled, the dialog will not Stay On Top
//unless we also add the following two lines (JRL's trick)
GetWindowPos>Dialog Stay On Top Example,X,Y
MoveWindow>Dialog Stay On Top Example,X,Y

Goto>Loop

SRT>Exit
  Exit>1
END>Exit
Does anyone have any thoughts as to how, running compiled, I can make that blinking cursor in the Edit field only show when the Dialog itself has keyboard focus... i.e. chars we type will actually go to the Edit field?
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
JRL
Automation Wizard
Posts: 3526
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Tue Feb 22, 2011 4:57 am

jpuziano wrote:Using your method, it automatically takes care of that blinking cursor in the Edit field... if the dialog does not have keyboard focus, no blinking cursor... when it has keyboard focus, the blinking cursor appears... this is exactly what I was looking for. All is fine... running uncompiled.
Hmmm. For me the cursor blinks when the dialog is unfocussed even uncompiled. Oh, wait... It blinks because of the move. If you take out the MoveWindow the cursor does not blink when uncompiled and the MoveWindow is only needed when compiled.

In any event this solved it for me both compiled and uncompiled. Unfortunately its exactly the kind of scripting shenanigans you dislike.

I added a button that has no size and no purpose except to be a dialog object to take focus when the dialog does not have focus. Added a Window_NewActive OnEvent>. Whenever the active window changes the "SetFocusE" subroutine is called. The subroutine examines the handle of the current window and compares it to the handle of the dialog. If they don't match, the invisible dialog button becomes the focused dialog object thus there is no blinking cursor.

Added a dialog handler that sets focus to the edit object whenever the dialog is clicked.

Also changed the Get window and move window in the loop to use the dialog handle. Its just more reliable that way.

Code: Select all

OnEvent>Window_NewActive,0,0,SetFocusE

Dialog>Dialog1
object Dialog1: TForm
  Left = 274
  Top = 150
  HelpContext = 5000
  BorderIcons = [biSystemMenu]
  Caption = 'Dialog Stay On Top Example'
  ClientHeight = 94
  ClientWidth = 243
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  FormStyle = fsStayOnTop
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = True
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 172
    Height = 26
    Caption = '1. Set the FormStyle to fsStayOnTop'#13#10'2. Set OnTaskbar to True'
  end
  object MSButton1: tMSButton
    Left = 0
    Top = 0
    Width = 0
    Height = 0
    DoubleBuffered = True
    ParentDoubleBuffered = False
    TabOrder = 1
    DoBrowse = False
    BrowseStyle = fbOpen
  end
  object Edit1: TEdit
    Left = 48
    Top = 53
    Width = 121
    Height = 21
    TabOrder = 3
    Text = 'Edit1'
  end
end
EndDialog>Dialog1

AddDialogHandler>Dialog1,,OnClose,Exit
AddDialogHandler>Dialog1,,OnClick,SetFocusE
Show>Dialog1

Label>Loop
wait>.01
Let>WIN_USEHANDLE=1
  GetWindowPos>Dialog1.Handle,X,Y
  MoveWindow>Dialog1.Handle,X,Y
Let>WIN_USEHANDLE=0
Goto>Loop

SRT>Exit
  Exit>1
END>Exit

SRT>SetFocusE
  Let>WIN_USEHANDLE=1
  GetActiveWindow>Title,winX,WinY
  Let>WIN_USEHANDLE=0
  If>%Title%=%Dialog1.handle%
    SetDialogObjectFocus>Dialog1,Edit1
  Else
    SetDialogObjectFocus>Dialog1,msButton1
  EndIf
END>SetFocusE

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Tue Feb 22, 2011 11:18 pm

Hi JRL,

Thanks for the speedy reply and solution, much appreciated.

Your code seemed to work but after testing it compiled with a few hops back and forth between Windows File Manager and the compiled dialog, I received the following error msg...
Error Msg wrote:---------------------------
Information
---------------------------
Error in : JRL - stay on top example using SetFocusE.exe
Line: 60 - Specified Window "FolderView" in GetWindowPos Not Present.
Any Subsequent Key Sends In Script May Cause Exceptions.
---------------------------
OK Abort
---------------------------
...so I made the following modifications to your code. The first thing I got rid of is the OnEvent> you added and the subroutine and the event handler that calls the subroutine. I suspect there is some speed issue there with OnEvent and eliminating it did get rid of the Error Msg. I then added the processing necessary right into the main idle loop... so far so good... try the code below:

Code: Select all

Dialog>Dialog1
object Dialog1: TForm
  Left = 274
  Top = 150
  HelpContext = 5000
  BorderIcons = [biSystemMenu]
  Caption = 'Dialog Stay On Top Example'
  ClientHeight = 94
  ClientWidth = 243
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  FormStyle = fsStayOnTop
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 172
    Height = 26
    Caption = '1. Set the FormStyle to fsStayOnTop'
  end
  object MSButton1: tMSButton
    Left = 0
    Top = 0
    Width = 0
    Height = 0
    DoubleBuffered = True
    ParentDoubleBuffered = False
    TabOrder = 1
    DoBrowse = False
    BrowseStyle = fbOpen
  end
  object Edit1: TEdit
    Left = 48
    Top = 53
    Width = 121
    Height = 21
    TabOrder = 3
    Text = 'Edit1'
  end
end
EndDialog>Dialog1

AddDialogHandler>Dialog1,,OnClose,Exit
Show>Dialog1

Label>Loop
wait>.01
Let>WIN_USEHANDLE=1
  GetWindowPos>Dialog1.Handle,X,Y
  MoveWindow>Dialog1.Handle,X,Y
  GetActiveWindow>Title,winX,WinY
Let>WIN_USEHANDLE=0
If>%Title%=%Dialog1.handle%
  SetDialogObjectFocus>Dialog1,Edit1
Else
  SetDialogObjectFocus>Dialog1,msButton1
EndIf
Goto>Loop

SRT>Exit
  Exit>1
END>Exit
So, it works... the only wrinkle is that with this method, if I have a few chars typed into the Edit1 field, every time my dialog gets keyboard focus again, yes Edit1 gets keyboard focus... but all the chars I've already typed in there are ALL HIGHLIGHTED so that if I were to type another char, it would REPLACE the ones already there.

So I click with the mouse at the end of the chars that are there, they "un-highlight"... and I can type a few more... but then I switch to another window, my dialog stays-on-top, that's good, and the blinking cursor in Edit1 goes away, also good... so now I switch back to my dialog and BOOM... all the existing chars in Edit1 are all highlighted again. I don't want that behavior... I just want the cursor to be blinking at the end of the chars that are there.

Or, to be more specific, whatever it looks like before I switch focus away (half the chars highlighted, none, all, cursor blinking at start, middle, end, whatever) I want it to look just exactly like that when focus gets switched back to my dialog and Edit1. And note that clicking on the dialog is only one way that keyboard focus might return to the dialog... really it should work no matter what caused it to regain keyboard focus.

Any further thoughts?
Last edited by jpuziano on Wed Feb 23, 2011 1:48 am, edited 1 time in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
JRL
Automation Wizard
Posts: 3526
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Tue Feb 22, 2011 11:23 pm

Press End

Code: Select all

---Prior code---

Label>Loop
wait>.01
Let>WIN_USEHANDLE=1
  GetWindowPos>Dialog1.Handle,X,Y
  MoveWindow>Dialog1.Handle,X,Y
  GetActiveWindow>Title,winX,WinY
Let>WIN_USEHANDLE=0
If>%Title%=%Dialog1.handle%
  SetDialogObjectFocus>Dialog1,Edit1
  Press End
Else
  SetDialogObjectFocus>Dialog1,msButton1
EndIf
Goto>Loop

---following code---

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Tue Feb 22, 2011 11:41 pm

Talk about a fast response. :D

Yes, I though about Pressing End... but what I am really looking for is...
jpuziano wrote:Or, to be more specific, whatever it looks like before I switch focus away (half the chars highlighted, none, all, cursor blinking at start, middle, end, whatever) I want it to look just exactly like that when focus gets switched back to my dialog and Edit1. And note that clicking on the dialog is only one way that keyboard focus might return to the dialog... really it should work no matter what caused it to regain keyboard focus.
Any thoughts?
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
JRL
Automation Wizard
Posts: 3526
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Wed Feb 23, 2011 5:16 am

Here's a concept for you. For some reason I've found inconsistency if I pick in the dialogs title bar. Anyway, I have no more time to mess with it tonight. Maybe you can make it work or maybe you have something better.

Get the caret position while focus is on the dialog then try to restore the position using a mouse click when you return to the dialog.

Have fun.

Code: Select all

Let>NotOnEditFlag=0

Label>Loop
wait>.01
Let>WIN_USEHANDLE=1
  GetWindowPos>Dialog1.Handle,X,Y
  MoveWindow>Dialog1.Handle,X,Y
  GetActiveWindow>Title,winX,WinY
Let>WIN_USEHANDLE=0
If>%Title%=%Dialog1.handle%
  If>NotOnEditFlag=1
    Let>NotOnEditFlag=0
    Let>WIN_USEHANDLE=1
    GetWindowPos>Dialog1.Edit1.Handle,ObjX,ObjY
    Add>ObjX,Saved_CarX
    Add>ObjY,Saved_CarY
    Add>objY,5
    GetCursorPos>CurX,CurY
    MouseMove>ObjX,ObjY
    Wait>0.2
    LClick
    MouseMove>CurX,CurY
    Let>WIN_USEHANDLE=0
  EndIf
  GetCaretPos>CarX,CarY,1
Else
  If>NotOnEditFlag=0
    SetDialogObjectFocus>Dialog1,msButton1
    Let>NotOnEditFlag=1
    Let>Saved_carX=CarX
    Let>SavedCarY=CarY
  EndIf
EndIf
Goto>Loop

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Fri Mar 04, 2011 12:20 am

Hi JRL,

Thanks for the concept. I fiddled around with a macro that worked that way... and did get something sort of working... but you could actually watch the mouse flashing and hopping around as it restored the saved caret position inside the text string typed into field Edit1 when the dialog regained focus so I gave up on that idea.

Then I found out via various links...

Mastering Delphi 7 - Customizing Windows Controls
http://flylib.com/books/en/2.37.1.96/1/

http://docwiki.embarcadero.com/RADStudi ... t_Controls

...about Delphi Edit field properties called SelText, SelStart and SelLength but these have not (yet) been exposed in MS v12 dialogs.

I was going to ask to have them exposed... however I found a much simpler solution. Try the code below:

Code: Select all

Dialog>Dialog1
object Dialog1: TForm
  Left = 354
  Top = 137
  HelpContext = 5000
  BorderIcons = [biSystemMenu]
  Caption = 'Dialog Stay On Top Example'
  ClientHeight = 94
  ClientWidth = 243
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  FormStyle = fsStayOnTop
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 172
    Height = 13
    Caption = '1. Set the FormStyle to fsStayOnTop'
  end
  object Edit1: TEdit
    Left = 48
    Top = 53
    Width = 121
    Height = 21
    AutoSelect = False
    TabOrder = 0
    Text = 'Edit1'
  end
end
EndDialog>Dialog1

AddDialogHandler>Dialog1,,OnClose,Exit
Show>Dialog1

Label>Loop
wait>.01
Let>WIN_USEHANDLE=1
GetWindowPos>Dialog1.Handle,sotX,sotY
MoveWindow>Dialog1.Handle,sotX,sotY
GetActiveWindow>Title,awX,awY
Let>WIN_USEHANDLE=0
If>%Title%=%Dialog1.handle%
  If>lost_focus_flag=True
    SetDialogProperty>Dialog1,Edit1,Enabled,True
    SetDialogObjectFocus>Dialog1,Edit1
    Let>lost_focus_flag=False
  EndIf
Else
  //our dialog no longer has focus
  SetDialogProperty>Dialog1,Edit1,Enabled,False
  Let>lost_focus_flag=True
EndIf
Goto>Loop

SRT>Exit
  Exit>1
END>Exit
The crucial difference from my earlier code is the value of the property in red below:
code out-take wrote: object Edit1: TEdit
Left = 48
Top = 53
Width = 121
Height = 21
AutoSelect = False
TabOrder = 0
Text = 'Edit1'
end
By default, AutoSelect=True for an Edit field. What that does is, when the field gets focus, if it contains any text, all that text is automatically selected. So when I set the Enabled property to False, that removed the blinking cursor... but when the Dialog regained focus and I set the Enabled property back to True, when AutoSelect was True, I lost whatever state the cursor and selected text was in previosly every time.

With AutoSelect=False for Edit1, this works perfectly, both compiled and non-compiled. Finally, a Stay-On-Top Dialog with an Edit field that behaves exactly as I want it to.

Thanks to everyone who contributed to this solution... I hope this is helpful to anyone else trying to achieve the same effect.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

Post Reply
Sign up to our newsletter for free automation tips, tricks & discounts