Jump to content

Multiple "owner drawn" buttons--how?


packrat
 Share

Recommended Posts

How does the example code for "owner drawn" buttons under GuiRegisterMessage() have to be modified for two or more such customized buttons (rather than just one customized button)?

In an attempt to experiment with (that is, learn how to handle) multiple customized buttons, I added another custom button and duplicated the MY_WM_COMMAND and MY_WM_DRAWITEM functions (adding the digits 1 and 2 to their names to represent the custom buttons 1 and 2), but all that seems to happen is that the Button2 data is duplicated for Button1's display (same colors, same displayed button names, etc.). This leads me to believe that somehow they're still sharing the same data somewhere, even though the MY_WM_DRAWITEM1/2 values of $sText, $nTextColor, and $nBackColor are different for the two custom buttons.

I don't see or understand how to specify different button texts and colors unless there are multiple MY_WM_DRAWITEM functions. (However, I also have a hunch that having two sets of GUIRegisterMsg commands may be part of the problem.)

Here's just the beginning portion of my modified code, showing the initial GUI setup:

$hGUI       = GUICreate("My Ownerdrawn Created Button", 300, 200)

$nButton1   = GUICtrlCreateButton("", 90, 50, 120, 30)
GUICtrlSetStyle($nButton1, BitOr($WS_TABSTOP, $BS_NOTIFY, $BS_OWNERDRAW)); Set the ownerdrawn flag

$nButton2   = GUICtrlCreateButton("", 90, 95, 120, 30)
GUICtrlSetStyle($nButton2, BitOr($WS_TABSTOP, $BS_NOTIFY, $BS_OWNERDRAW)); Set the ownerdrawn flag

$nButton3   = GUICtrlCreateButton("Normal Button", 90, 140, 120, 30)

GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND1")
; WM_DRAWITEM has to registered before showing GUI otherwise the initial drawing isn't done
GUIRegisterMsg($WM_DRAWITEM, "MY_WM_DRAWITEM1")

GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND2")
; WM_DRAWITEM has to registered before showing GUI otherwise the initial drawing isn't done
GUIRegisterMsg($WM_DRAWITEM, "MY_WM_DRAWITEM2")

GUISetState()

MY_WM_COMMAND2 is a direct copy of MY_WM_COMMAND1, and MY_WM_DRAWITEM2 is a direct copy of MY_WM_DRAWITEM1 with the three variables I mentioned above having different values. The problem may be something very easy and obvious, but, without a lot of comments in the code, it's a bit challenging sometimes to figure out what's important to change and what should be left alone. Due to AutoIt's inability to change button backgrounds, etc., knowing how to handle multiple customized buttons in this manner is essential.

Thanks in advance for any help and suggestions!

Harvey

Link to comment
Share on other sites

THANK YOU!! THANK YOU!! THANK YOU!!

That works beautifully as far as I've been able to make it work so far. However, I can't seem to be able to make such a colored button work like a "normal" button with respect to activating it as a control having the focus via the Enter key or activating it via an Alt-keystroke combination. (I'm emulating a software vendor's dialog box as closely as I can--that's why all the "normality" of button activation is required.) Here's the code I've been working with, adapted as best I could with your _GuiCtrlCreateButton UDF:

Func GetAuthorization()
    Dim $WinHandle
    Dim $img ; control ID
    Dim $a
    Dim $Rtn
;
; set up the dialog box:
    $WinHandle = GUICreate ( "Please Enter Initials and Password" , 350, 200, 280, 250  ) 
;
    GUISetBkColor( 0xFFFFFF ) ; white background for dialog box
;
    GUICtrlCreateLabel( "&Initials:", 100, 70, 65, 15 )
    $txtbox1 = GUICtrlCreateInput( "", 168, 65, 108, 19, $WS_TABSTOP )
;
    GUICtrlCreateLabel( "&Password:", 100, 94, 65, 15 )
    $txtbox2 = GUICtrlCreateInput( "", 168, 89, 108, 19, BitOR( $WS_TABSTOP, $ES_PASSWORD ) )
;
    $OkButton = _GuiCtrlCreateButton( "&OK", 111, 130, 49, 24, 0x000000, 0xFFFFFF )
;
    $CancelButton = _GuiCtrlCreateButton("&Cancel", 168, 130, 71, 24, 0x000000, 0xFFFFFF )
;
    GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
; WM_DRAWITEM has to registered before showing GUI otherwise the initial drawing isn't done
    GUIRegisterMsg($WM_DRAWITEM, "MY_WM_DRAWITEM")
;
    GUICtrlSetState( $txtbox1, $GUI_FOCUS ) ; give focus to the first textbox
;
    GUISetState() ; display the dialog box
;
    $a = 0
    While 1
        $a = GUIGetMsg()
        Select
            Case $a = $GUI_EVENT_CLOSE ; Esc key or [X] exit button
                $authi = ""
                $authp = ""
                $Rtn = 0
                ExitLoop
            ;
            Case $a = $CancelButton
            ;$authi = ""
            ;$authp = ""
            ;$Rtn = 0
            ;ExitLoop
                Send("!c") ; force a mouseclick on "&Cancel" button
            ;
            Case $a = $txtbox1
                GUICtrlSetState( $txtbox2, $GUI_FOCUS ) ; give focus to the password textbox
            ;
            Case $a = $txtbox2
                GUICtrlSetState( $OkButton, $GUI_FOCUS ) ; give focus to the OK button
            ;GUICtrlSetBkColor( $OkButton, 0x669999 ) ; blue-green background for buttondown
            ;
            Case $a = $OkButton
            ;$authi = GUICtrlRead($txtbox1)
            ;$authp = GUICtrlRead($txtbox2)
            ;$Rtn = 1
            ;ExitLoop
                Send("!o") ; force a mouseclick on "&OK" button
        EndSelect
    Wend
;
    GUIDelete( $WinHandle ) ; close the dialog box
;
    Return $Rtn ; value 1 = OK button chosen; value 0 = Esc/Exit/Cancel button chosen
EndFunc  ;==>GetAuthorization()


Func Button_Click(ByRef $ctrl_id)
    Switch $ctrl_id
        Case $CancelButton
            $authi = ""
            $authp = ""
            $Rtn = 0
            MsgBox(0,"",$Rtn & "'" & $authi & "'" & $authp & "'")
        ;
        Case $OkButton
            $authi = GUICtrlRead($txtbox1)
            $authp = GUICtrlRead($txtbox2)
            $Rtn = 1
            MsgBox(0,"",$Rtn & "'" & $authi & "'" & $authp & "'")
    EndSwitch
    Return $Rtn ; value 1 = OK button chosen; value 0 = Esc/Exit/Cancel button chosen
EndFunc  ;==>Button_Click

I left the code as it was, following my last experiment which attempted to "fake" a button click when either the Enter key was pressed (when the button had the focus) or else the combination Alt-o was pressed. I copied the button processing code in the "normal" control processing part of the GetAuthorization() function to the Button_Click function, but it didn't seem to make any difference. The MsgBoxes display when the buttons are clicked with the mouse, but in no other way (such as pressing Enter or Alt-o). Even more importantly, the values in each Button_Click case ($authi, $authp, $Rtn) don't seem to get set, passed, or anything. These values are absolutely essential to the ultimate use of the larger function. (The $authi and $authp variables are global; because of the Button_Click function, so are $OkButton, $CancelButton, $txtbox1, and $txtbox2.)

Any further suggestions or help would be much appreciated! Thanks in advance!

Harvey

Link to comment
Share on other sites

I think the code posted by Larry in the subject thread "Capturing the Enter-key of an Input-control" and the explanations and code given in the help file "GUI Reference - OnEvent Mode" may give the key to resolving my problem (that is, using an OnEvent approach rather than a MessageLoop approach). I'm going to attempt that, and, if it doesn't work, then I may be back with further questions. Thanks!

Harvey

Link to comment
Share on other sites

Well, closer... but no cigar!

Here's my attempt at using the OnEvent approach to accomplish my dialog box with custom buttons:

Global $OkButton, $CancelButton, $txtbox1, $txtbox2, $WinHandle, $Rtn
Global Const $DebugIt = 1

Func GetAuthorization() ; [15 Nov 2005; modified 8-9,13-14 Sep 2006]
;
; NOTE:  $authi and $authp MUST be declared as global variables
;
    Opt("GUIOnEventMode", 1) ; replace default MessageLoop control processing with OnEvent control processing
;
;Dim $WinHandle
    Dim $img ; control ID
;Dim $txtbox1 ; control ID
;Dim $txtbox2 ; control ID
;Dim $OkButton ; control ID
;Dim $CancelButton ; control ID
    Dim $a
    Dim $Rtn
;
; set up the dialog box:
    $WinHandle = GUICreate ( "Please Enter Initials and Password" , 350, 200, 280, 250  )
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Terminate")
;
    GUISetBkColor( 0xFFFFFF ) ; white background for dialog box
;
    $img = GUICtrlCreatePic( "C:\QuestionMark.bmp", 16, 33, 28, 32 ) ; left, top, width, height -- these coordinates are relative to the dialog box, not the whole window
;
    GUICtrlCreateLabel( "&Initials:", 100, 70, 65, 15 )
    $txtbox1 = GUICtrlCreateInput( "", 168, 65, 108, 19, $WS_TABSTOP )
    GUICtrlSetOnEvent($txtbox1, "_MyInput")
;
    GUICtrlCreateLabel( "&Password:", 100, 94, 65, 15 )
    $txtbox2 = GUICtrlCreateInput( "", 168, 89, 108, 19, BitOR( $WS_TABSTOP, $ES_PASSWORD ) )
    GUICtrlSetOnEvent($txtbox2, "_MyInput")
;
    $OkButton = _GuiCtrlCreateButton( "&OK", 111, 130, 49, 24, 0x000000, 0xFFFFFF )
    GUICtrlSetOnEvent($OkButton, "OKPressed")
;
    $CancelButton = _GuiCtrlCreateButton("&Cancel", 168, 130, 71, 24, 0x000000, 0xFFFFFF )
    GUICtrlSetOnEvent($CancelButton, "CancelPressed")
;
    GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
; WM_DRAWITEM has to registered before showing GUI otherwise the initial drawing isn't done
    GUIRegisterMsg($WM_DRAWITEM, "MY_WM_DRAWITEM")
;
    GUICtrlSetState( $txtbox1, $GUI_FOCUS ) ; give focus to the first textbox
;
    GUISetState() ; display the dialog box
    
    GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND2")
    
; Just idle around
    While 1
        Sleep(10)
    WEnd
    
    
; END
    
EndFunc  ;==>GetAuthorization()

Func _MyInput()
   ;----------------------------------------------------------------------------------------------
    If $DebugIt Then _DebugPrint("_MyInput")
   ;----------------------------------------------------------------------------------------------
EndFunc  ;==>_MyInput

Func _Input_Changed($input)
   ;----------------------------------------------------------------------------------------------
    If $DebugIt Then _DebugPrint("Input Changed:" & GUICtrlRead($input))
   ;----------------------------------------------------------------------------------------------
EndFunc  ;==>_Input_Changed

Func _Input_LostFocus()
   ;----------------------------------------------------------------------------------------------
    If $DebugIt Then _DebugPrint("_Input_LostFocus")
   ;----------------------------------------------------------------------------------------------
EndFunc  ;==>_Input_LostFocus

Func _Input_GotFocus()
   ;----------------------------------------------------------------------------------------------
    If $DebugIt Then _DebugPrint("_Input_GotFocus")
   ;----------------------------------------------------------------------------------------------
EndFunc  ;==>_Input_GotFocus

Func OKPressed()
   ;----------------------------------------------------------------------------------------------
    If $DebugIt Then _DebugPrint("OK Pressed" & @LF & "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle)
   ;----------------------------------------------------------------------------------------------
    $authi = GUICtrlRead($txtbox1)
    $authp = GUICtrlRead($txtbox2)
    $Rtn = 1
;MsgBox(0,"",$Rtn & "'" & $authi & "'" & $authp & "'")
    _Terminate()
EndFunc  ;==>OKPressed

Func CancelPressed()
   ;----------------------------------------------------------------------------------------------
    If $DebugIt Then _DebugPrint("Cancel Pressed" & @LF & "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle)
   ;----------------------------------------------------------------------------------------------
    $authi = ""
    $authp = ""
    $Rtn = 0
;MsgBox(0,"",$Rtn & "'" & $authi & "'" & $authp & "'")
    _Terminate()
EndFunc  ;==>OKPressed

Func _Terminate() ; Esc key or [X] exit button
   ;Exit
    $authi = ""
    $authp = ""
    $Rtn = 0
;
;MsgBox(0,"",$Rtn & "'" & $authi & "'" & $authp & "'")
    GUIDelete( $WinHandle ) ; close the dialog box
;
    Return $Rtn ; value 1 = OK button chosen; value 0 = Esc/Exit/Cancel button chosen
;
    Opt("GUIOnEventMode", 0) ; make MessageLoop control processing the default again
EndFunc  ;==>_Terminate


Func Button_Click(ByRef $ctrl_id)
    Dim $Rtn
;
    Switch $ctrl_id
        Case $CancelButton
            $authi = ""
            $authp = ""
            $Rtn = 0
        ;MsgBox(0,"",$Rtn & "xxx'" & $authi & "'" & $authp & "'")
        ;
        Case $OkButton
            $authi = GUICtrlRead($txtbox1)
            $authp = GUICtrlRead($txtbox2)
            $Rtn = 1
        ;MsgBox(0,"",$Rtn & "xxx'" & $authi & "'" & $authp & "'")
    EndSwitch
    Return $Rtn ; value 1 = OK button chosen; value 0 = Esc/Exit/Cancel button chosen
EndFunc  ;==>Button_Click


Func MY_WM_COMMAND2($hWnd, $msg, $wParam, $lParam)
    Local $nNotifyCode = _HiWord($wParam)
    Local $nID = _LoWord($wParam)
    Local $hCtrl = $lParam
    Local Const $EN_CHANGE = 0x300
    Local Const $EN_KILLFOCUS = 0x200
    Local Const $EN_SETFOCUS = 0x100

    Switch $nID
        Case $txtbox1
            Switch $nNotifyCode
                Case $EN_CHANGE
                    _Input_Changed($txtbox1)
                Case $EN_SETFOCUS
                    _Input_GotFocus()
                Case $EN_KILLFOCUS
                    _Input_LostFocus()
                    GUICtrlSetState( $txtbox2, $GUI_FOCUS ) ; give focus to the password textbox
            EndSwitch
                   
        Case $txtbox2
            Switch $nNotifyCode
                Case $EN_CHANGE
                    _Input_Changed($txtbox2)
                Case $EN_SETFOCUS
                    _Input_GotFocus()
                Case $EN_KILLFOCUS
                    _Input_LostFocus()
                    GUICtrlSetState( $OkButton, $GUI_FOCUS ) ; give focus to the OK button
                ;GUICtrlSetBkColor( $OkButton, 0x669999 ) ; blue-green background for button
            EndSwitch
    EndSwitch
   ; Proceed the default Autoit3 internal message commands.
   ; You also can complete let the line out.
   ; !!! But only 'Return' (without any value) will not proceed
   ; the default Autoit3-message in the future !!!
    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_WM_COMMAND2

#cs ;already exists in GuiButton.au3 code
Func _DebugPrint($s_text)
    $s_text = StringReplace($s_text, @LF, @LF & "-->")
    ConsoleWrite("!===========================================================" & @LF & _
            "+===========================================================" & @LF & _
            "-->" & $s_text & @LF & _
            "+===========================================================" & @LF)
EndFunc  ;==>_DebugPrint
#ce

Func _HiWord($x)
    Return BitShift($x, 16)
EndFunc  ;==>_HiWord

Func _LoWord($x)
    Return BitAND($x, 0xFFFF)
EndFunc  ;==>_LoWord

Unfortunately, it doesn't work right--at least in terms of keystrokes (mouseclicks seem to work fine). Here's my original version that DOES work right. (The only problem is that the dialog box I'm trying to emulate is all white rather than all gray.)

Func GetAuthorization() ; [15 Nov 2005; modified 8-9 Sep 2006]
    Dim $WinHandle
    Dim $txtbox1 ;control ID
    Dim $txtbox2 ;control ID
    Dim $OkButton ;control ID
    Dim $CancelButton ;control ID
    Dim $a
    Dim $Rtn
;
;set up the dialog box:
    $WinHandle = GUICreate ( "Please Enter Initials and Password" , 350, 200, 280, 250  )
    GUICtrlCreateLabel( "&Initials:", 100, 70, 65, 15 ) ;left, top, width, height -- these coordinates are relative to the dialog box, not the whole window
    $txtbox1 = GUICtrlCreateInput ( "", 168, 65, 108, 19 )
    GUICtrlCreateLabel( "&Password:", 100, 94, 65, 15 )
    $txtbox2 = GUICtrlCreateInput ( "", 168, 89, 108, 19, $ES_PASSWORD )
    $OkButton = GUICtrlCreateButton ("&OK", 111, 130, 49, 24 )
    $CancelButton = GUICtrlCreateButton ("&Cancel", 168, 130, 71, 24 )
;
;GUICtrlSetState( $OKButton, $GUI_DEFBUTTON ) ;OK button is the default button -- COMMENT OUT!
    GUICtrlSetState( $txtbox1, $GUI_FOCUS ) ;give focus to the first textbox
;
    GUISetState() ;display the dialog box
;
    $a = 0
    While 1
        $a = GUIGetMsg()
        Select
            Case $a = $GUI_EVENT_CLOSE ; Esc key or [X] exit button
                $authi = ""
                $authp = ""
                $Rtn = 0
                ExitLoop
                
            Case $a = $CancelButton
                $authi = ""
                $authp = ""
                $Rtn = 0
                ExitLoop
                
            Case $a = $txtbox1
                GUICtrlSetState( $txtbox2, $GUI_FOCUS ) ; give focus to the password textbox
                
            Case $a = $txtbox2
                GUICtrlSetState( $OkButton, $GUI_FOCUS ) ; give focus to the OK button
            ;GUICtrlSetBkColor( $OkButton, 0x669999 ) ; blue-green background for button
                
            Case $a = $OkButton
                $authi = GUICtrlRead($txtbox1)
                $authp = GUICtrlRead($txtbox2)
                $Rtn = 1
                ExitLoop
        EndSelect
    Wend
;
    GUIDelete( $WinHandle )
;
    Return $Rtn
EndFunc

Here are the specifications I wrote up for myself for how it had to work:

; NOTE: in this code, pressing the Enter key means different things, depending upon

; which control (field or button) has the focus:

; (1) Alt-O always submits data; Alt-C always cancels the dialog

; (2) Alt-I always goes to the "Initials" field; Alt-P always goes to the "Password" field

; (3) cursor in "Initials" field: Tab and Enter go to "Password" field; Shift-Tab goes to "Cancel"

; (4) cursor in "Password" field: Tab and Enter go to "OK" button; Shift-Tab goes to "Initials"

; (5) focus on "OK" button: Enter submits data; Tab goes to "Cancel" button; Shift-Tab goes to "Password"

; (6) focus on "Cancel" button: Enter cancels the dialog; Tab goes to "Initials"; Shift-Tab goes to "OK"

[The only quirk which I hadn't fixed before moving on to customized buttons was that the Enter key didn't move from a textbox to the next control if the current textbox had no data entered in it.]

The second version (MessageLoop approach) above works according to these specs, but the first version (OnEvent approach) does not--and I can't figure out why. Any and all help would be appreciated! Thanks!

Harvey

Link to comment
Share on other sites

Addenda to my previous message:

(1) I forgot to note that you have to include gafrost's UDF:

#include "GuiButton.au3"

(2) For testing, of course, you probably should add something to call the function:

$a = GetAuthorization()

(3) In the first version (OnEvent approach), the code responds to clicking. However, rather than exiting the function to the calling function (see addendum #2 above), it leaves the script in a "Script Paused" halted state, requiring manual intervention to exit--without any data/information being returned to the calling function. Basically, what I'm saying is that the clicking aspect only partially works--and the script as a whole does not work at all.

Hope this extra info helps a bit!

Harvey

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...