So I wrote this to simulate a program that would have a start and stop feature, and has a tab design. Right now there is a tab that has a RichEdit object intended to be a running log.
As you can see, after we "start" the program I put just some milliseconds of sleep to simulate running instructions. I created a function to check for requests that would be called on a larger scale randomly throughout code to ping the GUI per say.
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
Global Const $h_numOfTabs = 2
Global Enum $H_TAB_1, $H_TAB_2, $H_TAB_END
Global $hGui, $h_logRichEdit, $iMsg, $h_tabs, $h_startButton, $h_stopButton
Example()
Func Example()
$hGui = GUICreate("Example (" & StringTrimRight(#ScriptName, StringLen(".exe")) & ")", 400, 550, -1, -1)
; ADD START AND STOP BUTTONS
$h_startButton = GUICtrlCreateButton( "Start", 50, 450 )
$h_stopButton = GUICtrlCreateButton( "Stop", 150, 450 )
$h_tabs = GUICtrlCreateTab( 5, 5, 390,375 )
; LOG TAB
GUICtrlCreateTabItem( "Log" )
$h_logRichEdit = _GUICtrlRichEdit_Create ( $hGui, "", 8, 30, 384, 347, BitOR( $ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY ) )
; STATS TAB
GUICtrlCreateTabItem( "Stats" )
; Close TABS
GUICtrlCreateTabItem( "" )
GUISetState( #SW_SHOW ) ; initialize the gui
While True
CheckRequests()
WEnd
EndFunc ;==>Example
Func Start()
while true
Sleep(100)
CheckRequests()
WEnd
EndFunc
Func Stop()
EndFunc
Func CheckRequests()
$iMsg = GUIGetMsg()
while $iMsg <> 0
Select
Case $iMsg = $GUI_EVENT_CLOSE
_GUICtrlRichEdit_Destroy($h_logRichEdit) ; needed unless script crashes
; GUIDelete() ; is OK too
Exit
Case $iMsg = $h_tabs
Switch GUICtrlRead( $h_tabs )
Case $H_TAB_1
ControlShow( $hGui, "", $h_logRichEdit )
Case Else
ControlHide( $hGui, "", $h_logRichEdit )
EndSwitch
Case $iMsg = $h_startButton
Start()
Case $iMsg = $h_stopButton
Stop()
EndSelect
$iMsg = GUIGetMsg()
WEnd
EndFunc
At about 500ms sleep, the lag when switching tabs is visible.
My question: On a larger scale, is this how we would handle/update things that are specific to a tab while running a larger program? If not, what would be a more efficient way of updating tab specific properties while running a larger overall program.
I have also seen a design recently where all the tabs and related components were their own GUI's but I am not sure the relevance of everything being its own GUI and if it pertains to this question.
Any help or clarification is greatly appreciated, I am new to AutoIT and trying to figure out some do's and dont's as well as efficiency.
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
Global Const $h_numOfTabs = 2
Global Enum $H_TAB_1, $H_TAB_2, $H_TAB_END
Global $hGui, $h_logRichEdit, $iMsg, $h_tabs, $h_startButton, $h_stopButton
Example()
Func Example()
$hGui = GUICreate("Example (" & StringTrimRight(#ScriptName, StringLen(".exe")) & ")", 400, 550, -1, -1)
; ADD START AND STOP BUTTONS
$h_startButton = GUICtrlCreateButton( "Start", 50, 450 )
$h_stopButton = GUICtrlCreateButton( "Stop", 150, 450 )
$h_tabs = GUICtrlCreateTab( 5, 5, 390,375 )
; LOG TAB
GUICtrlCreateTabItem( "Log" )
$h_logRichEdit = _GUICtrlRichEdit_Create ( $hGui, "", 8, 30, 384, 347, BitOR( $ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY ) )
_GUICtrlRichEdit_AppendText($h_logRichEdit, "{\rtf {Showing \b1 Rich Text \b0}")
; STATS TAB
GUICtrlCreateTabItem( "Stats" )
; Close TABS
GUICtrlCreateTabItem( "" )
; Register Windows message.
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState( #SW_SHOW ) ; initialize the gui
GuiMessageLoop()
EndFunc
Func GuiMessageLoop()
While 1
$iMsg = GUIGetMsg()
Switch $iMsg
Case $GUI_EVENT_CLOSE
_GUICtrlRichEdit_Destroy($h_logRichEdit) ; needed unless script crashes
; GUIDelete() ; is OK too
Exit
Case $h_startButton
Start()
Case $h_stopButton
Stop()
EndSwitch
WEnd
EndFunc
Func Start()
ConsoleWrite('# Sleep' & #CRLF)
Sleep(5000)
ConsoleWrite('# Awake' & #CRLF)
EndFunc
Func Stop()
EndFunc
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
Local $iLoWord = _WinAPI_LoWord($lParam)
Local $iHiWord = _WinAPI_HiWord($lParam)
ConsoleWrite('- WM_NOTIFY' & ' ' & $iLoWord & ' ' & $iHiWord & #CRLF)
Switch GUICtrlRead( $h_tabs )
Case $H_TAB_1
ControlShow( $hGui, "", $h_logRichEdit )
Case Else
ControlHide( $hGui, "", $h_logRichEdit )
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Try this example. It uses GuiRegisterMessage to capture
WM_NOTIFY Windows messages. WM_NOTIFY is not an ideal
message code for this, though have not found something
more suitable for only changing Tabs.
The code to hide and show the Rich Edit control has been
moved into the WM_NOTIFY function so that each time a
message is received, the Tab hide and show code executes.
ConsoleWrite is used to show what the events of interest
are doing during testing. If your editor has a output
console pane, then you may be able to view the writes to
the console pane.
If an event such as function Start takes a long time,
then multi-processing may help to allow the Gui to
remain responsive with the message loop.
Want a do don't, avoid (cyclic) recursive function
calls and avoid getting trapped in loops.
Additional References:
Windows Message Codes
AutoIt Wiki about Tabs
Related
How can i get the Aero Glass effect for my Autoit GUI?
I am playing a bit with AutoIt to increase my knowledge about GUI stuff. Usually i just create scripts without the usage of a GUI, but i would like to have a nice looking areo glass GUI when i just start to work with.
I already experiment with WinSetTrans but this is not exactly what i want. It should look more like the image below.
My current code is:
#include <GUIConstants.au3>
$iWidthGui = 450
$iHeightGui = 300
$hGui = GUICreate("Glass GUI", $iWidthGui, $iHeightGui, -1, -1, -1, $WS_EX_TOPMOST)
$cExit = GUICtrlCreateButton("Exit", $iWidthGui / 2 - 50, $iHeightGui / 2 - 15, 100, 30)
GUISetState( #SW_SHOW )
WinSetTrans($hGui, "", 180)
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $cExit
GUIDelete($hGui)
ExitLoop
EndSwitch
WEnd
Is it possible with Autoit? How can i do that?
Yes it is possible. This should work at least for Windows 7. I couldn't test the script on a Windows 10 machine.
Improved code:
#include-once
#include <GUIConstants.au3>
Global $iWidthGui = 450
Global $iHeightGui = 300
Global $hGui = GUICreate("Glass GUI", $iWidthGui, $iHeightGui, -1, -1, -1, $WS_EX_TOPMOST)
Global $cExit = GUICtrlCreateButton("Exit", $iWidthGui / 2 - 50, $iHeightGui / 2 - 15, 100, 30)
GUISetState( #SW_SHOW, $hGui )
Func _aeroGlassEffect( $hWnd, $iLeft = #DesktopWidth, $iRight = #DesktopWidth, $iTop = #DesktopWidth, $iBottom = #DesktopWidth )
$hStruct = DllStructCreate( 'int left; int right; int height; int bottom;' )
DllStructSetData( $hStruct, 'left', $iLeft )
DllStructSetData( $hStruct, 'right', $iRight )
DllStructSetData( $hStruct, 'height', $iTop )
DllStructSetData( $hStruct, 'bottom', $iBottom )
GUISetBkColor( '0x000000' )
Return DllCall( 'dwmapi.dll', 'int', 'DwmExtendFrameIntoClientArea', 'hWnd', $hWnd, 'ptr', DllStructGetPtr( $hStruct ) )
EndFunc
_aeroGlassEffect( $hGui )
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $cExit
GUIDelete($hGui)
ExitLoop
EndSwitch
WEnd
I switched WinSetTrans() for _aeroGlassEffect(). You can change the function parameters $iLeft, $iRight, $iTop, $iBottom.
How can I detect when a system is shutting down or logging off with AutoIt?
I need to run a function if the computer is shutdown or logged off while my script is still running.
You need to handle the Message WM_QUERYENDSESSION
Sample Code:
; Define Windows Message Codes
$WM_QUERYENDSESSION = 0x11
; Define Callback Parameter Codes
$ENDSESSION_CLOSEAPP = 0x00000001
$ENDSESSION_CRITICAL = 0x40000000
$ENDSESSION_LOGOFF = 0x80000000
; Register a Callback on the Message to the Function "onShutDown"
GUIRegisterMsg($WM_QUERYENDSESSION, "onShutDown")
; #FUNCTION# ========================================================
; Name...........: onShutDown Example Function
; Description ...: Application receives the WM_QUERYENDSESSION message
;
; Parameters ....:
; $hWndGUI - A handle to the window
; $MsgID - The WM_QUERYENDSESSION identifier
; $wParam - This parameter is reserved for future use
; $lParam - This parameter can be one or more of the following values.
; |0 - The system is shutting down or restarting
; (it is not possible to determine which event is occurring)
; |$ENDSESSION_CLOSEAPP - Application is using a ressource or file that needs to be freed
; |$ENDSESSION_CRITICAL - Application is forced to shut down
; |$ENDSESSION_LOGOFF - The user is logging off
;
; Return values .:
; |True - Allow to Shutdown
; |False - Prevent Shutdown
; Remarks .......: Applications should respect the user's intentions and return TRUE. By default any application returns **TRUE** for this message.
; If shutting down would corrupt the system or media that is being burned, the application can return **FALSE**.
; However, it is good practice to respect the user's actions.
;
Func onShutDown($hWndGUI, $MsgID, $wParam, $lParam)
Return True ; allow Shutdown ( or return "False" to prevent Shutdown )
EndFunc
Also See : List of Windows Message Codes
You can implement OnAutoItExitRegister() in such a way that you can assume the PC is shutting down.
OnAutoItExitRegister("DetectShutdown")
GUICreate("My GUI") ; will create a dialog box that when displayed is centered
GUISetState(#SW_SHOW) ; will display an empty dialog box
; Run the GUI until the dialog is closed
While True
$msg = GUIGetMsg()
If $msg = $GUI_EVENT_CLOSE Then
OnAutoItExitUnRegister("DetectShutdown")
Exit
EndIf
WEnd
Func DetectShutdown()
MsgBox(0, "", "Shutdown Detected!")
EndFunc
How can I detect when a system is shutting down or logging off with AutoIt?
As per Documentation - Function Reference - OnAutoItExitRegister() :
The mode of exit can be retrieved with #exitMethod.
Also detects user logoff and Windows shutdown.
I need to run a function if the computer is shutdown or logged off while my script is still running.
Example (determination of-, and reaction to exit methods):
#include <AutoItConstants.au3>; #exitMethod constants.
Global Enum $EXIT_OK, _
$EXIT_ONAUTOITEXITREGISTER, _
$EXIT_HOTKEYSET
Global Const $g_iDelayMain = 250
Global Const $g_iDelayExit = 1000 * 5
Global Const $g_sKeyExit = '{ESC}'
Global Const $g_sConsole = '%s-%s-%s %s:%s:%s.%s - #exitCode = %i (%s) #exitMethod = %i (%s)\n'
Global Const $g_aExit = [ _
'OK', _
'OnAutoItExitRegister() failed', _
'HotKeySet() failed' _
]
Global Const $g_aMethod = [ _
'end of script reached', _
'Exit function executed', _
'systray exit function activated', _
'Windows logoff', _
'Windows shutdown' _
]
Global $g_bStateExit = False
Main()
Func Main()
If Not OnAutoItExitRegister('_ReportExit') Then Exit $EXIT_ONAUTOITEXITREGISTER
If Not HotKeySet($g_sKeyExit, 'SetStateExit') Then Exit $EXIT_HOTKEYSET
While Not $g_bStateExit
Sleep($g_iDelayMain)
WEnd
Exit $EXIT_OK
EndFunc
Func _ReportExit()
Local Const $sLine = StringFormat($g_sConsole, _
#YEAR, #MON, #MDAY, #HOUR, #MIN, #SEC, #MSEC, _
#exitCode, $g_aExit[#exitCode], _
#exitMethod, $g_aMethod[#exitMethod] _
)
ConsoleWrite($sLine)
Sleep($g_iDelayExit)
Switch #exitMethod
; Case $EXITCLOSE_NORMAL
; Your code here.
; Case $EXITCLOSE_BYEXIT
; Your code here.
; Case $EXITCLOSE_BYCLICK
; Your code here.
Case $EXITCLOSE_BYLOGOFF
; Your code here.
Case $EXITCLOSE_BYSHUTDOWN
; Your code here.
EndSwitch
EndFunc
Func SetStateExit()
$g_bStateExit = True
EndFunc
Windows 7 and Vista both have a feature very usefull: Taskbar Thumbnail Preview, that allows you to see what's happening on other (minimized windows).
I am very inexperient using windows functions and DLLs but i wanted to know if it is possible to get minimized windows previews. The goal is to make an application that would loop between all processes that have minimized windows.
Not exactly what you need but is a good place to start. HERE
#include <ITaskBarList.au3>
#include <ButtonConstants.au3>
$GUI = GUICreate("Thumbnail Button", 250, 100)
GUICtrlCreateButton('ThumbNailClip', 1, 1)
GUISetState(#SW_SHOW)
$oTaskbar = _ITaskBar_CreateTaskBarObj()
$but1 = _ITaskBar_CreateTBButton('Down ToolTip', #ScriptDir & '\Icons\Down.ico', -1, '_Down_Button')
$but2 = _ITaskBar_CreateTBButton('Left ToolTip', #ScriptDir & '\Icons\Left.ico', -1, '_Left_Button')
$but3 = _ITaskBar_CreateTBButton('', #ScriptDir & '\Icons\Left.ico', -1, '_Right_Button');no tooltip
$but4 = _ITaskBar_CreateTBButton('Internet Explorer',#ProgramFilesDir & '\Internet Explorer\iexplore.exe', -1, '_IE_Button');
$but5 = _ITaskBar_CreateTBButton('AutoIt', #AutoItExe, -1, '_AutoIt_Button');
_ITaskBar_AddTBButtons($GUI)
_ITaskBar_SetThumbNailToolTip($GUI, 'ITaskBarList UDF ToolTip Example')
; Set progressbar to normal state (green)
_ITaskBar_SetProgressState($GUI, 2)
For $i = 1 to 100
_ITaskBar_SetProgressValue($GUI, $i)
Sleep(75)
; Set progressbar to Paused state (yellow). Notice that even thought the progressbar is in "paused" state, you can
; still can change the value. Its just an indicator. It doesnt actually pause anything.
If $i = 25 Then _ITaskBar_SetProgressState($GUI, 8);
;Set progressbar to Error state (red). This works the same way as paused state. Its just an indicator.
If $i = 50 Then _ITaskBar_SetProgressState($GUI, 4)
;Set progressbar back to normal state (green)
If $i = 75 Then _ITaskBar_SetProgressState($GUI, 2)
Next
;set progressbar Indeterminate
_ITaskBar_SetProgressState($GUI, 1)
Sleep(3000)
;clear progressbar
_ITaskBar_SetProgressState($GUI)
;Set ThumbNail Preview to only show the button from the GUI
MsgBox(0,'SetThumbNailClip','Notice that the ThumbNail preview shows the whole GUI.', 30, $Gui)
_ITaskBar_SetThumbNailClip($GUI, 0, 0, 80, 30)
MsgBox(0,'SetThumbNailClip','Now look again. You should only see the ThumbNailClip Button', 30, $Gui)
; clear thumbnail clip
_ITaskBar_SetThumbNailClip($GUI)
;Add Icon Overlay
_ITaskBar_SetOverlayIcon($GUI, #ProgramFilesDir & '\Internet Explorer\iexplore.exe')
MsgBox(0,'SetOverlayIcon','Taskbar tab should have and Internet Explorer icon overlay. ', 30, $Gui)
; clear icon overlay
_ITaskBar_SetOverlayIcon($GUI)
Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
Func _Down_Button()
MsgBox(0, 'Button Pressed', 'Down Button has been Pressed.')
EndFunc ;==>_Down_Button
Func _Left_Button()
MsgBox(0, 'Button Pressed', 'Left Button has been Pressed.')
EndFunc ;==>_Left_Button
Func _Right_Button()
MsgBox(0, 'Button Pressed', 'Right Button has been Pressed.')
EndFunc ;==>_Right_Button
Func _IE_Button()
MsgBox(0, 'Button Pressed', 'IE Button has been Pressed.')
EndFunc
Func _AutoIt_Button()
MsgBox(0, 'Button Pressed', 'AutoIT Button has been Pressed.')
EndFunc
My clipboard controller could have several items copied to the clipboard when using a hotkey (CTRL + SHIFT + Q), instead of only one item, and pastes all at once (CTRL + SHIFT + W), or paste any of the first 10 items directly (CTRL + SHIFT + 1 … 9). Another option is to clear the clipboard (CTRL + SHIFT + -).
It works just for several copy and pastes, but then trying to make a copy operation nothing is added to the buffer. I couldn't find a reason for this.
Code (problem should be in the addToClipboard() or getAll()) :
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <array.au3>
Global $clipBoard[50]=[""]
Global $counter = 0
HotKeySet("^+q","addToClipboard")
HotKeySet("^+-","emptyAll")
HotKeySet("^+w","getAll")
HotKeySet("^+1","get1")
HotKeySet("^+2","get2")
HotKeySet("^+3","get3")
HotKeySet("^+4","get4")
HotKeySet("^+5","get5")
HotKeySet("^+6","get6")
HotKeySet("^+7","get7")
HotKeySet("^+8","get8")
HotKeySet("^+9","get9")
$hGUI = GuiCreate("Clipboard Controller", 100, 100,Default,Default,$WS_SIZEBOX)
GUISetState()
Func addToClipboard()
Send ("^c")
$copied = ClipGet()
$clipBoard[Mod($counter,50)] = $copied
$counter +=1
EndFunc
Func getByIndex($i)
$statement = $clipBoard[$i]
ClipPut($statement)
Send("^v")
EndFunc
Func getAll()
$statement =""
For $i In $clipBoard
If $i <> "" Then
$statement &= $i & #CRLF
EndIf
Next
ClipPut($statement)
Send("^v")
EndFunc
Func emptyAll()
For $i=0 To 49
$clipBoard[$i]=""
Next
ClipPut("")
EndFunc
Func get1()
getByIndex(0)
EndFunc
Func get2()
getByIndex(1)
EndFunc
Func get3()
getByIndex(2)
EndFunc
Func get4()
getByIndex(3)
EndFunc
Func get5()
getByIndex(4)
EndFunc
Func get6()
getByIndex(5)
EndFunc
Func get7()
getByIndex(6)
EndFunc
Func get8()
getByIndex(7)
EndFunc
Func get9()
getByIndex(8)
EndFunc
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Problem is an old trap...
It takes a small amount of time to copy to the clip board
especially large items..try a sleep after the Send
Func addToClipboard()
Send ("^c")
sleep(1000) ; try different values
$copied = ClipGet()
$clipBoard[Mod($counter,50)] = $copied
$counter +=1
EndFunc
anyway like your script..idea
The problem is the code for addToClipboard is running while the user still has the keys pressed down. As a result, the Send command designed to send just Ctrl+C is in effect sending Ctrl+Shift+C, so the text is never copied.
The solution is to wait for the user to raise those keys, using the _IsPressed function, then once all keys are released, execute the code. It may also be wise to disable the hotkey when you enter the function (and re-enable when you leave) so that holding the hotkey down for a long time doesn't keep triggering the function.
An alternative would be to send the WM_COPY message directly to the control with focus. This is not guaranteed to work for every control (though I'd be very surprised if it didn't). This would be a far more reliable method.
hope this is the end of the problem , I found another way to set/get data from clipboard , functions : _ClipBoard_SetData () & _ClipBoard_GetData() from library <Clipboard.au3> , after trying them it worked well , after all it seems like the problem was in setting and getting data from the clipboard..
will come later isA to assure whether its finally correct or not
I have made a button in AutoIT for this program we are making for work we will call it $okmystery and I want $okmystery to like to my company website. Here is a snippet of the code I have so far:
Dim $msg
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $okbutton
; Minimize Current Window
WinSetState( $WINTITLE, "", #SW_MINIMIZE)
While Not BitAND(WinGetState($WINTITLE, ""), 16)
sleep( 250 )
WEnd
; Take Screen Shots and Logs
ScreenShotAndLogs()
; Compress Artifacts
If FileExists( $ZIPFILEPATH ) Then FileDelete( $ZIPFILEPATH )
_Zip_Create( $ZIPFILEPATH )
_Zip_AddFolderContents( $ZIPFILEPATH, $OUTPUTROOT )
DeleteOriginals()
; Restore main window
WinSetState( $WINTITLE, "", #SW_RESTORE)
;------------ Screen Shot
Case $msg = $okshot
; Minimize Current Window
WinSetState( $WINTITLE, "", #SW_MINIMIZE)
While Not BitAND(WinGetState($WINTITLE, ""), 16)
sleep( 250 )
WEnd
ScreenShot()
; Restore main window
WinSetState( $WINTITLE, "", #SW_RESTORE)
;----------------------------------
$okmystery = ShellExecute ("basic")
Run("Http://www.IT-Networks.org")
Case Default
; Do Nothing
EndSelect
WEnd
Exit( 0 )
It looks like you need to change the "$okmystery" case statement to match the other case statements (if those are all working like they're supposed to).
You can then try to ShellExecute() the url.
Case $msg = $okmystery
ShellExecute("Http://www.IT-Networks.org")
Here's a working example of a GUI with a button that opens your company website in your default web browser:
#include <GUIConstantsEx.au3>
Global $Button_1, $msg
GUICreate("Test GUI Button")
$okmystery = GUICtrlCreateButton("okmystery Button", 10, 30, 100)
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $okmystery
ShellExecute("Http://www.IT-Networks.org")
EndSelect
WEnd