Tabs
Tabs And How To Deal With Them
Tabs are a valuable tool when you need to fit a lot of controls into a small GUI. But inexperienced users often have problems with them - particularly in making sure that controls only appear on the correct tab. This tutorial should help. Before going further, it is important to understand the differences between controls created using the built-in AutoIt commands (GUICtrlCreate*) and those created with the UDFs. The built-in commands produce controls which are managed internally by AutoIt - they return ControlIDs. The UDF commands create controls that are not in Autoit's internal management structure and need to be managed by the code - they normally return handles (the special unique identifier for all Windows components).
Tabs Created With Native AutoIt Functions
Any tabs created by the built-in AutoIt commands GUICtrlCreateTab/TabItem will automatically take care of displaying any built-in controls created at the same time within the tab creation structure. Here is an example:
#include <GUIConstantsEx.au3>
$hGUI = GUICreate("Built-In Tab Example", 500, 500)
$hTab = GUICtrlCreateTab(10, 10, 480, 480)
; Create tabitems
For $i = 0 To 2
GUICtrlCreateTabItem("Tab " & $i)
GUICtrlCreateButton("Button " & $i, 20 + ($i * 100), 40 + ($i * 50), 80, 30)
Next
; Close Tab definiton
GUICtrlCreateTabItem("")
GUISetState()
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
As you can see, the controls for each tab are created just after the TabItem on which they are to appear and before the next TabItem. Do not forget to close the Tab definition - many tab problems are caused by omitting this vital line.
What happens if we add some UDF created controls to these tabs?
#include <GUIConstantsEx.au3>
#Include <GuiButton.au3>
$hGUI = GUICreate("Built-In Tab Example", 500, 500)
$hTab = GUICtrlCreateTab(10, 10, 480, 480)
; Create tabitems
For $i = 0 To 2
GUICtrlCreateTabItem("Tab " & $i)
GUICtrlCreateButton("Built-In " & $i, 20 + ($i * 100), 40 + ($i * 50), 80, 30)
_GUICtrlButton_Create($hGUI, "UDF " & $i, 20 + ($i * 100), 80 + ($i * 50),80, 30)
Next
; Close Tab definiton
GUICtrlCreateTabItem("")
GUISetState()
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
As you can see, the UDF created controls appear on every tab. Remember this is because they are not part of the internal AutoIt control management structure, so AutoIt does not know how to handle them. It is up to you to manage them by seeing which tab is active and hiding/showing these controls as required:
#include <GUIConstantsEx.au3>
#Include <GuiButton.au3>
Global $hButtons[3]
$hGUI = GUICreate("Built-In Tab Example", 500, 500)
$hTab = GUICtrlCreateTab(10, 10, 480, 480)
; Create tabitems
For $i = 0 To 2
GUICtrlCreateTabItem("Tab " & $i)
GUICtrlCreateButton("Built-In " & $i, 20 + ($i * 100), 40 + ($i * 50), 80, 30)
; Add a label to the first tab
If $i = 0 Then GUICtrlCreateLabel("See how 'laggy' the UDF buttons are when selecting this tab because of using WinSetState", 20, 200, 150, 60)
Next
GUICtrlCreateTabItem("")
; Create UDF controls
For $i = 0 To 2
$hButtons[$i] = _GUICtrlButton_Create($hGUI, "UDF " & $i, 20 + ($i * 100), 80 + ($i * 50),80, 30)
Next
; Hide the controls so only the one on the first tab is visible
WinSetState($hButtons[1], "", @SW_HIDE)
WinSetState($hButtons[2], "", @SW_HIDE)
GUISetState()
; This is the current active tab
$iLastTab = 0
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
Case $hTab
; Check which Tab is active
$iCurrTab = GUICtrlRead($hTab)
; If the Tab has changed
If $iCurrTab <> $iLastTab Then
; Show/Hide controls as required
Switch $iCurrTab
Case 0
; Note lag when WinSetState is used
WinSetState($hButtons[1], "", @SW_HIDE)
WinSetState($hButtons[2], "", @SW_HIDE)
WinSetState($hButtons[0], "", @SW_SHOW)
Case 1
; No lag when using ControlHide/Show
ControlHide($hGUI, "", $hButtons[0])
ControlHide($hGUI, "", $hButtons[2])
ControlShow($hGUI, "", $hButtons[1])
Case 2
; Nor when using this DLL
DllCall("User32.dll", "bool", "ShowWindowAsync", "hwnd", $hButtons[0], "int", @SW_HIDE)
DllCall("User32.dll", "bool", "ShowWindowAsync", "hwnd", $hButtons[1], "int", @SW_HIDE)
DllCall("User32.dll", "bool", "ShowWindowAsync", "hwnd", $hButtons[2], "int", @SW_SHOW)
EndSwitch
; Store the value for future comparisons
$iLastTab = $iCurrTab
EndIf
EndSwitch
WEnd
Note the lag in hiding/showing the UDF created controls if you use WinSetState - I would recommend using ControlShow/Hide which gives an instantaneous response. Also how you do not need to create the UDF controls within the tab creation structure - as you have to look after them, there is no requirement to do so.
Tabs Created With UDFs
Now let us look at Tabs created with the GUITab UDF. In this case you need to manage all of the controls on the tabs yourself, even if they are created using the built-in commands:
#include <GUIConstantsEx.au3>
#Include <GuiButton.au3>
#include <GuiTab.au3>
Global $hBuiltIn_Buttons[3]
Global $hUDF_Buttons[3]
$hGUI = GUICreate("Built-In Tab Example", 500, 500)
$hTab = _GUICtrlTab_Create($hGUI, 10, 10, 480, 480)
GUISetState()
; Add tabs
_GUICtrlTab_InsertItem($hTab, 0, "Tab 0")
_GUICtrlTab_InsertItem($hTab, 1, "Tab 1")
_GUICtrlTab_InsertItem($hTab, 2, "Tab 2")
; Create the Built-in and UDF buttons
For $i = 0 To 2
$hBuiltIn_Buttons[$i] = GUICtrlCreateButton("Button " & $i, 20 + ($i * 100), 40 + ($i * 50), 80, 30)
$hUDF_Buttons[$i] = _GUICtrlButton_Create($hGUI, "UDF " & $i, 20 + ($i * 100), 80 + ($i * 50),80, 30)
Next
; Hide the controls so only the one on the first tab is visible
GUICtrlSetState($hBuiltIn_Buttons[1], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[2], $GUI_HIDE)
ControlHide($hGUI, "", $hUDF_Buttons[1])
ControlHide($hGUI, "", $hUDF_Buttons[2])
GUISetState()
; This is the current active tab
$iLastTab = 0
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
; Check which Tab is active
$iCurrTab = _GUICtrlTab_GetCurFocus($hTab)
; If the Tab has changed
If $iCurrTab <> $iLastTab Then
; Store the value for future comparisons
$iLastTab = $iCurrTab
; Show/Hide controls as required
Switch $iCurrTab
Case 0
GUICtrlSetState($hBuiltIn_Buttons[1], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[2], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[0], $GUI_SHOW)
ControlHide($hGUI, "", $hUDF_Buttons[1])
ControlHide($hGUI, "", $hUDF_Buttons[2])
ControlShow($hGUI, "", $hUDF_Buttons[0])
Case 1
GUICtrlSetState($hBuiltIn_Buttons[0], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[2], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[1], $GUI_SHOW)
ControlHide($hGUI, "", $hUDF_Buttons[0])
ControlHide($hGUI, "", $hUDF_Buttons[2])
ControlShow($hGUI, "", $hUDF_Buttons[1])
Case 2
GUICtrlSetState($hBuiltIn_Buttons[0], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[1], $GUI_HIDE)
GUICtrlSetState($hBuiltIn_Buttons[2], $GUI_SHOW)
ControlHide($hGUI, "", $hUDF_Buttons[0])
ControlHide($hGUI, "", $hUDF_Buttons[1])
ControlShow($hGUI, "", $hUDF_Buttons[2])
EndSwitch
EndIf
WEnd
A lot of work but a very satisfactory result. Note the need to use different commands to hide/show the built-in and UDF created controls to avoid "lag" on the latter as was shown in the earlier example.
So, a couple of lessons to draw from this:
- 1. When using tabs, try and use built-in commands if at all possible. If you do, AutoIt looks after the showing/hiding problem for you as long as you create the controls within the tab creation structure. See the next section for how to add controls to tabs after their creation.
- 2. If you must use UDF created controls for any reason, you have to manage hiding/showing all controls yourself.
Adding Controls To Tabs After Creation
If you need to add built-in controls to a tab after the tabs have already been created, then you must use GUISwitch with the tabitemID parameter to select the correct tab before you create the control or you will find that it is visible on all tabs.
Here is an example to show how to do it:
#include <GUIConstantsEx.au3>
$hGUI = GUICreate("Test", 500, 500)
$cTab = GUICtrlCreateTab(10, 10, 480, 350)
$cTab_0 = GUICtrlCreateTabItem("Tab 0")
$cTab_1 = GUICtrlCreateTabItem("Tab 1")
GUICtrlCreateTabItem("")
$cButton = GUICtrlCreateButton("Add controls", 10, 450, 80, 30)
GUISetState()
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
Case $cButton
; Correct
GUISwitch($hGUI, $cTab_0)
GUICtrlCreateLabel("Only on Tab 0", 40, 40, 200, 20)
GUICtrlSetBkColor(-1, 0xCCFFCC)
GUICtrlCreateTabItem("")
GUISwitch($hGUI)
; Incorrect
GUICtrlCreateLabel("OnTab 0 AND Tab 1", 40, 100, 200, 20)
GUICtrlSetBkColor(-1, 0xFFCCCC)
EndSwitch
WEnd
Do not forget to reclose the tab definition after adding the new controls.
Multiple Tabs In A GUI
Unfortunately, only one built-in tab control can be created per GUI - you cannot have several tabs on a single GUI. But there is a way around this - just create child GUIs which can each hold a tab:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
$hGUI = GUICreate("Test", 500, 500)
GUISetState()
; Create child GUIs to hold tabs
$hTab_Win0 = GUICreate("", 400, 200, 50, 20, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
$hTab_0 = GUICtrlCreateTab(10, 10, 380, 180)
$hTab_00 = GUICtrlCreateTabitem("00")
GUICtrlCreateButton("00", 160, 90, 80, 30)
$hTab_01 = GUICtrlCreateTabitem("01")
GUICtrlCreateButton("01", 160, 90, 80, 30)
GUICtrlCreateTabitem ("")
GUISetState()
$hTab_Win1 = GUICreate("", 400, 200, 50, 250, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
$hTab_1 = GUICtrlCreateTab(10, 10, 380, 180)
$hTab_10 = GUICtrlCreateTabitem("10")
GUICtrlCreateButton("10", 160, 90, 80, 30)
$hTab_11 = GUICtrlCreateTabitem("11")
GUICtrlCreateButton("11", 160, 90, 80, 30)
GUICtrlCreateTabitem ("")
GUISetState()
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Easy when you know how!
Tab switching with CTRL+TAB / CTRL+SHIFT+TAB
#include <GUIConstantsEx.au3>
#include <TabConstants.au3>
Global $aTab[3]
$hGUI = GUICreate("Test", 500, 500)
$cTab = GUICtrlCreateTab(10, 10, 480, 200)
$aTab[0] = GUICtrlCreateTabItem("Tab 0")
$aTab[1] = GUICtrlCreateTabItem("Tab 1")
$aTab[2] = GUICtrlCreateTabItem("Tab 2")
GUICtrlCreateTabItem("")
$cTab_Right = GUICtrlCreateDummy()
$cTab_Left = GUICtrlCreateDummy()
GUISetState()
Global $aAccelKeys[2][2] = [["^{TAB}", $cTab_Right],["^+{TAB}", $cTab_Left]]
GUISetAccelerators($aAccelKeys)
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
Case $cTab_Right
$iTab = GUICtrlRead($cTab) + 1
If $iTab > (UBound($aTab) - 1) Then $iTab = 0
GUICtrlSendMsg($cTab, $TCM_SETCURFOCUS, $iTab, 0)
Case $cTab_Left
$iTab = GUICtrlRead($cTab) - 1
If $iTab < 0 Then $iTab = UBound($aTab) - 1
GUICtrlSendMsg($cTab, $TCM_SETCURFOCUS, $iTab, 0)
EndSwitch
WEnd
Based on Melba23 code from Tab switching with CTRL+TAB / CTRL+SHIFT+TAB
Related links
Below Links to interesting topics in the forum related to the use of Tab
- Tab BG Colour
- GUICtrlSetTip with Multi Lines for TabItems
- How to detect when a Tab loses focus ?
- Tab control with Richedit
- Resize tabs relative to GUI width
- GUISetAccelerators click on two buttons on different TabItem
Summary
Tabs are useful controls, but can be difficult to master. After this tutorial you should be well on your way!