mBernin

Reference a ComboBox individually

15 posts in this topic

#1 ·  Posted

So I've hit a wall in working out the logic behind a problem I'm having. The scenario is this:

I have a loop iterating up to a certain amount of 'slots', creating rows of GUI elements in a program. Currently I'm modding it to include ComboBoxes within that loop. The elements all can be referenced by row in functions etc elsewhere simply being called via "$Elem1[$i]" "$Elem2[$i]" "$Elem3[$i]" etc. But when creating a variable for the combobox if I add [$i] to the variable the combobox suddenly doesn't get populated properly, I'm assuming because you can't place comboboxes into arrays? It sounds a little confusing, but the screenshot and code snippet should explain what I'm talking about :P

So this is the GUI, with the rows being produced (the comboboxes I added into the loop - showing the bug I'm facing when adding [$i] to the variable they're declared into):

https://imgur.com/a/RISPO

And this is the code producing those elements (I'll cut some out since it's mainly the comboboxes we're concerned with):

For $i = 0 To $g_iUpgradeSlots - 1
        $g_hPicUpgradeStatus[$i]= GUICtrlCreateIcon($g_sLibIconPath, $eIcnTroops, $x - 10, $y+1, 14, 14)
            _GUICtrlSetTip(-1, $sTxtStatus)
        $g_hChkUpgrade[$i] = GUICtrlCreateCheckbox($i+1 &":", $x + 5, $y+1, 34, 15)
            _GUICtrlSetTip(-1,  $sTxtCheckBox & " #" & $i+1 & " " & $sTxtAfterUsing)
;           GUICtrlSetFont(-1, 8)
            GUICtrlSetOnEvent(-1, "btnchkbxUpgrade")
        $g_hTxtUpgradeName[$i] = GUICtrlCreateInput("", $x+40, $y, 87, 17,BitOR($ES_CENTER, $GUI_SS_DEFAULT_INPUT, $ES_READONLY, $ES_NUMBER)) ;ORIGINAL $g_hTxtUpgradeName[$i] = GUICtrlCreateInput("", $x+40, $y, 107, 17,BitOR($ES_CENTER, $GUI_SS_DEFAULT_INPUT, $ES_READONLY, $ES_NUMBER))
;           GUICtrlSetFont(-1, 8)
            _GUICtrlSetTip(-1, $sTxtShowName)
        $g_hTxtUpgradeLevel[$i] = GUICtrlCreateInput("", $x+130, $y, 23, 17, BitOR($ES_CENTER, $GUI_SS_DEFAULT_INPUT, $ES_READONLY, $ES_NUMBER))
;           GUICtrlSetFont(-1, 8)
            _GUICtrlSetTip(-1, $sTxtShowLevel)

....

        $g_hIntUpgradeMaxLevel = GUICtrlCreateCombo("", $x + 395, $y+1, 35, 25, BitOR($CBS_DROPDOWNLIST, $CBS_AUTOHSCROLL)) ;Create dropdown menu (combo box)
            GUICtrlSetTip(-1, $sTxtMaxLevel)
            GUICtrlSetData($g_hIntUpgradeMaxLevel, "1|2|3|4|5|6|7|8|9|10|11|12|13|14", "14") ;Populate it with potential levels

        $y += 22
    Next

So it's that combo box at the end I'm trying to reference by individual row. If I add "$g_hIntUpgradeMaxLevel[$i]" the comboboxes don't get populated (as in the screenshot) so it has to be a single variable. This means the variable will just be populated with the last combobox created so the program won't realise which row I'm trying to pull the combobox index from, if you see what I mean? :blink:

Each combobox is subject to change indvividually, I added this:

$g_hTxtUpgradeLevelRef[$i] = (_GUICtrlComboBox_GetCurSel($g_hIntUpgradeMaxLevel)) + 1

to the end of the loop which is fine for when the elements are created, but I can't think of a way to update them individually on an event.

I've messed around with functions elsewhere through SetOnEvent, but again, the variable is still just a static value of the last combobox created - also since you can't parse parameters via OnEvent things are even more difficult :P

I'm probably missing something totally obvious, but after spending hours reading the code I'm slightly burnt out and could use a fresh pair of eyes - the more I think about it the further I get from a solution :>

Thanks in advance!

mBernin

Share this post


Link to post
Share on other sites



#2 ·  Posted

 

EDIT: also to avoid confusion, the combobox data (1-14) has nothing to do with the fact there's only 14 rows, that's just a coincidence ^_^

 

Share this post


Link to post
Share on other sites

#3 ·  Posted

Maybe something like:

#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>

Example()

Func Example()
    Local $idComboBox[4], $iY = 10, $sComboRead = ""
    Local $hGUI = GUICreate("Example", 300, 200)

    ; Create a combobox control.
    For $i = 0 To 3
        $idComboBox[$i] = GUICtrlCreateCombo("Item " & $i, 10, $iY, 185, 20)
        $iY += 25
    Next
    Local $idClose = GUICtrlCreateButton("Close", 210, 170, 85, 25)

    ; Add additional items to the combobox.
    For $i = 0 To 3
        GUICtrlSetData($idComboBox[$i], "Item 1|Item 2|Item 3", "Item " & $i)
    Next
    GUISetState()
    While 1
        $iMsg = GUIGetMsg()
        For $i = 0 To 3
            If $iMsg = $idComboBox[$i] Then
               $sComboRead = GUICtrlRead($idComboBox[$i])
               MsgBox($MB_SYSTEMMODAL, "", "The combobox is currently displaying: " & $sComboRead, 0, $hGUI)
            EndIf
        Next
       Switch $iMsg
            Case $GUI_EVENT_CLOSE, $idClose
                ExitLoop
        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>Example

 

Share this post


Link to post
Share on other sites

#4 ·  Posted

@Subz A nice solution, thank you! Though the close button isn't working and CPU usage caps out, I think maybe it's stuck in that while loop (the comboboxes are created successfully)

Sorry this is my first crack at AutoIt :>

Share this post


Link to post
Share on other sites

#5 ·  Posted

9 minutes ago, mBernin said:

Though the close button isn't working and CPU usage caps out

Are you sure you copied it correctly? I tested Subz's code by itself and it closes fine with both the X button and the close button, and it barely uses any CPU.


UHJvZmVzc2lvbmFsIENvbXB1dGVyZXI=

Share this post


Link to post
Share on other sites

#6 ·  Posted

@anthonyjr2 hmm, I made a couple of adjustments just to suit my needs (14 ComboBoxes) plus added "Local" to $iMsg since it was flagging as undeclared:

Func cmbBuild()
    Local $idComboBox[14], $iY = 10, $sComboRead = ""
    Local $hGUI = GUICreate("Max Level Selection", 300, 420)



    ; Create a combobox control.
    For $i = 0 To 13
        $idComboBox[$i] = GUICtrlCreateCombo("Item " & $i, 10, $iY, 185, 20)
        $iY += 25
    Next
    Local $idClose = GUICtrlCreateButton("Close", 210, 170, 85, 25)

    ; Add additional items to the combobox.
    For $i = 0 To 13
        GUICtrlSetData($idComboBox[$i], "1|2|3|4|5|6|7|8|9|10|11|12|13|14", "14" & $i)
    Next
    GUISetState()
    While 1
    Local $iMsg = GUIGetMsg()
        For $i = 0 To 13
            If $iMsg = $idComboBox[$i] Then
               $sComboRead = GUICtrlRead($idComboBox[$i])
               MsgBox($MB_SYSTEMMODAL, "", "The combobox is currently displaying: " & $sComboRead, 0, $hGUI)
            EndIf
        Next
       Switch $iMsg
            Case $GUI_EVENT_CLOSE, $idClose
                ExitLoop
        EndSwitch
    WEnd
    GUIDelete($hGUI)
EndFunc   ;==>cmbBuild()

 

Share this post


Link to post
Share on other sites

#7 ·  Posted

That makes me think the problem is coming from another area of your code, because that still works fine for me.


UHJvZmVzc2lvbmFsIENvbXB1dGVyZXI=

Share this post


Link to post
Share on other sites

#8 ·  Posted

You're right, running it independently solves the problem. It seems to be linking itself in some way with the status of the main program's GUI - when I close the main program it closes this extra combobox handler cleanly. Strange effect, not sure where to start in solving it :shocked:

Thank you both for the replies though, given me a very nice baseline to work from! :)

Wish me luck, I'll most likely need it :lol:

Share this post


Link to post
Share on other sites

#9 ·  Posted

Do you have:

Opt("GUIOnEventMode", 1)

at the top of your program? This changes the GUI so that instead of constantly checking the GUI, it will pause the main GUI and execute whatever is in the called function. For example, if I have a main GUI with a button that opens a secondary one, it will pause the main GUI and open the secondary one, only resuming the main when the called function is finished.


UHJvZmVzc2lvbmFsIENvbXB1dGVyZXI=

Share this post


Link to post
Share on other sites

#10 ·  Posted

Yeah that's called on the program's 'main' script. Though by the time it reaches the function in question any number of things may have changed (it's a large program that I'm not the original author of - just adding a feature I thought of). The program's GUI is structured in tabs and subtabs - in theory the program's main script (could be called it's executable) should encapsulate all these tabs, but could it be possible that this GUIOnEventMode isn't applying to subtabs and their functions?

Also all of these GUI rows are produced within a function as well, so when running this extra combobox window we're essentially running functions within functions (not sure how far it goes :lol:)

Share this post


Link to post
Share on other sites

#11 ·  Posted

So I found this:

https://www.autoitscript.com/wiki/Interrupting_a_running_function

It seems due to the nature of where I'm calling this message box from it's going to be pretty difficult to interrupt it via a close button. I'm wondering which section applies - I'm assuming OnEvent mode. Though the implementation seems like it's going to get complicated :(

Share this post


Link to post
Share on other sites

#12 ·  Posted

From the help file:

Quote

OnEvent functions are only called when Opt("GUIOnEventMode", 1) - when in this mode GUIGetMsg() is NOT used at all.

So you either should switch to GUIOnEventMode or GUIGetMsg in your script, here is code using GUIOnEventMode.

#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
Global $hGUI, $hGUI_Close = False
Opt("GuiOnEventMode", 1)

_ComboBuild()

Func _ComboBuild()
    Local $idComboBox[14], $iY = 10
    $hGUI = GUICreate("Max Level Selection", 300, 420)
        GUISetOnEvent($GUI_EVENT_CLOSE, "_CloseGui", $hGUI)

    ; Create a combobox control.
    For $i = 0 To 13
        $idComboBox[$i] = GUICtrlCreateCombo("Item " & $i, 10, $iY, 185, 20)
        GUICtrlSetData($idComboBox[$i], "1|2|3|4|5|6|7|8|9|10|11|12|13|14", "14" & $i)
        GUICtrlSetOnEvent($idComboBox[$i], "_ComboRead")
        $iY += 25
    Next
    Local $idClose = GUICtrlCreateButton("Close", 210, 170, 85, 25)
    GUICtrlSetOnEvent($idClose, "_CloseGui")

    GUISetState()

    While $hGUI_Close = False
        Sleep(10)
    WEnd
    GUIDelete($hGUI)
EndFunc   ;==>_ComboBuild()

Func _ComboRead()
    $sComboRead = GUICtrlRead(@GUI_CtrlId)
    MsgBox(4096, "", "The combobox is currently displaying: " & $sComboRead, 0, $hGUI)
EndFunc

Func _CloseGui()
    $hGUI_Close = True
EndFunc   ;==>_CloseGui

 

Share this post


Link to post
Share on other sites

#13 ·  Posted

Still producing the same effect, though it's definitely on the program's end;

I ran the code independently as before and again it worked as intended. When I removed the GUIOnEventMode it reflected the behaviour of when it was being ran within the program, meaning somewhere along the line of the main program being initialized the scope of EventMode is being lost. As far as I can tell the structure of the program is this:

Main Script (EventMode set here) -> CreateMainGUI() -> CreateTabsWithinGUI() -> CreateSubtabs() -> CreateSubTabsUnderThoseSubTabs() -> CreateGUIElementsShownInScreenshot() -- GUICtrlSetOnEvent(-1, "_ComboBuild") --> FunctionWe'reCreating()

Or in simpler terms:

Main script, defining various global options etc (including EventMode) + initializing the GUI creation -> MainGUI() -> Tab1 -> Tab1a -> Tab1aa (Our function here)

 

I've tried placing

Opt("GuiOnEventMode", 1)

Further and further down the program structure but can't find the sweet spot. It's definitely the culprit of the issue, since the problem can be reproduced simply by removing this option from your latest code.

Share this post


Link to post
Share on other sites

#14 ·  Posted

Have you checked that you don't have GuiGetMsg within the script?

Share this post


Link to post
Share on other sites

#15 ·  Posted

Searching for it from the program's root folder in Windows explorer I've found there's a function (called "_ExtMsgBox") that temporarily switches EventMode off to use GuiGetMsg, switching it back on when the operation is finished. Though it isn't in the same .au3 file as where we're working, and the function isn't called anywhere in the .au3 file that I'm adding these changes either.

Might be important to note that these .au3 files containing functions (of which there's over a hundred) are all in a 'global includes' type script to allow their use anywhere in the program's code, meaning anywhere in the program I could call a function that uses GuiGetMsg, but right now it's not called in an area that should conflict with what I'm doing, plus it only temporarily uses its functionality. As far as the program is concerned before and after calling this function GuiOnEventMode should still be enabled globally

Share this post


Link to post
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