mBernin Posted June 7, 2017 Posted June 7, 2017 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 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? 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 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
mBernin Posted June 7, 2017 Author Posted June 7, 2017 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
Subz Posted June 7, 2017 Posted June 7, 2017 Maybe something like: expandcollapse popup#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
mBernin Posted June 7, 2017 Author Posted June 7, 2017 @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
anthonyjr2 Posted June 7, 2017 Posted June 7, 2017 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=
mBernin Posted June 7, 2017 Author Posted June 7, 2017 @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()
anthonyjr2 Posted June 7, 2017 Posted June 7, 2017 That makes me think the problem is coming from another area of your code, because that still works fine for me. UHJvZmVzc2lvbmFsIENvbXB1dGVyZXI=
mBernin Posted June 7, 2017 Author Posted June 7, 2017 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 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
anthonyjr2 Posted June 7, 2017 Posted June 7, 2017 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=
mBernin Posted June 7, 2017 Author Posted June 7, 2017 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 )
mBernin Posted June 8, 2017 Author Posted June 8, 2017 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
Subz Posted June 8, 2017 Posted June 8, 2017 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. expandcollapse popup#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
mBernin Posted June 8, 2017 Author Posted June 8, 2017 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.
Subz Posted June 8, 2017 Posted June 8, 2017 Have you checked that you don't have GuiGetMsg within the script?
mBernin Posted June 8, 2017 Author Posted June 8, 2017 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now