Setting Styles

From AutoIt Wiki
Jump to navigation Jump to search

Introduction

Setting styles and extended styles is an integral part of coding in AutoIt - but it is very easy to get something other than the result you wanted if you do not take care when specifying them!

Note: Although the text and examples in this tutorial deal with styles, everything here is also applicable to extended styles.

Multiple Styles

Most styles are set at the bit level - they require specific bits within the total style value to be set in order for the specific style to be activated. This is why you should always use BitOR rather than simple addition when setting multiple styles to make sure you do not inadvertently set/unset bits you do not mean to! Let us look why this might happen - but if you do not understand binary maths, you might want to go and read about that first!

Let us imagine we want to set two styles which have the values seventeen and thirtythree (these values have been chosen just for illustration and are not valid styles). Expressing the two styles in binary gives us:

 $Style_1 = 17 ; 17 in binary is 00010001
 $Style_2 = 33 ; 33 in binary is 00100001

Now let us see what happens when we try and combine the two styles:

Using BitOR (which sets bits if either or both bits are set) we get:

 BitOR($Style_1, $Style_2) ; --> 00110001

However, if we use simple addition, we get:

 17 + 33 = 50 ; --> 00110010

Windows uses a form of BitAND to check for styles which means that it looks for specific bits within the larger number. So if Windows is checking for $Style1, it looks for bits four and eight. In the BitOr result, these bits are set - and Windows will apply the style. The same is true for $Style2 - this time bits three and eight are set in both the style and the combined result. However, if we try the same tests against the result obtained by simple addition, we see that in neither case Windows does find the correct bits set. So Windows will apply neither style to our control - and will probably apply some other completely different styles instead. So, always use BitOR to set multiple styles. Remember that you can combine several styles within a single BitOr.

Adding and Removing Styles

Most AutoIt controls have default styles - look in the <Appendix - GUI Control Styles> section of the Help file to see what they are. For example, a List control is created with the $LBS_SORT, $WS_BORDER, and $WS_VSCROLL styles set automatically. As you can see from the <List Styles> section of the above Help file page, these have been conveniently combined as the $GUI_SS_DEFAULT_LIST style and similar values are available for all the usual controls. However, there is no need to specify any of these default styles in the initial GUICtrlCreate* statement as they are automatically included as previously mentioned. Where users often have difficulty is when they want to add further styles to a control. Whenever you specify a particular style (or multiple styles using BitOR as explained above) you overwrite the existing style value and set only the value you have just specified.

Here is an example of this overwriting using ListViews.

- The first default ListView is automatically created with the $LVS_SHOWSELALWAYS and $LVS_SINGLESEL styles.

- If we want to sort the items, we need to set the $LVS_SORTASCENDING/DESCENDING style. So we do this for the second ListView - but as we only specify the $LVS_SORTASCENDING style we overwrite the default styles.

- The final ListView shows how to add the $LVS_SORTASCENDING style correctly by using the BitOR operator on the default setting AND the new style.

If you play with the ListViews, you will see that although the middle ListView is indeed sorted, it now permits multiple selections and does not show the selected items when it does not have focus - because it no longer has the $LVS_SINGLESEL and $LVS_SHOWSELALWAYS styles. The bottom ListView is sorted and has retained the default styles - which is want we wanted.

 #include <GUIConstantsEx.au3>
 #include <ListviewConstants.au3>
 
 $hGUI = GUICreate("Test", 500, 600)
 
 $hLV_Default = GUICtrlCreateListView("Header", 10, 10, 480, 180)
 GUICtrlSetBkColor(-1, 0xC4C4C4)
 $hLV_Sorted = GUICtrlCreateListView("Header", 10, 200, 480, 180, $LVS_SORTASCENDING)
 GUICtrlSetBkColor(-1, 0xC4C4C4)
 $hLV_Default_Sorted = GUICtrlCreateListView("Header", 10, 400, 480, 180, BitOr($GUI_SS_DEFAULT_LISTVIEW, $LVS_SORTASCENDING))
 GUICtrlSetBkColor(-1, 0xC4C4C4)
 
 For $i = 1 To 8
     $iItem = Random(0, 9, 1)
     GUICtrlCreateListViewItem($iItem, $hLV_Default)
     GUICtrlCreateListViewItem($iItem, $hLV_Sorted)
     GUICtrlCreateListViewItem($iItem, $hLV_Default_Sorted)
 Next
 
 GUISetState()
 
 While 1
     Switch GUIGetMsg()
         Case $GUI_EVENT_CLOSE
             Exit
     EndSwitch
 WEnd

Things can get a little more complicated if we created the control with a non-standard style set and want to change it. How do we find out what styles are currently set? You may have noticed that there is no GUICtrlGetStyle to match the GUICtrlSetStyle command.

As it is you who are setting the styles in your own script, a good tip is to keep the current value in a variable which you can then easily modify. But we can also get the current style values by calling the Windows API directly:

 #include <Constants.au3> ; Do not forget these include files!
 #include <WinAPI.au3>
 
 $iStyle   = _WinAPI_GetWindowLong(GUICtrlGetHandle($iControlID), $GWL_STYLE)
 $iExStyle = _WinAPI_GetWindowLong(GUICtrlGetHandle($iControlID), $GWL_EXSTYLE)

Once you have the current value then you can easily add or subtract other styles from it.

Adding a new style is simple - we just use BitOR as we have already seen:

 GUICtrlSetStyle($iControlID, BitOR($iOldStyleValue, $iNewStyle))

Subtracting a style can be done in two ways - although one is much easier to use:

 GUICtrlSetStyle($iControlID, BitXOR($iOldStyleValue, $iStyleToRemove))
 
 GUICtrlSetStyle($iControlID, BitAnd($iOldStyleValue, BitNOT($iStyleToRemove)))

You can see that we are using Bit* operators again. Explaining exactly how they affect the values we give as parameters is beyond the scope of this tutorial, but they all operate in a similar manner to the BitOR/BitAND case we looked at when combining styles earlier.

Finally, here is a script which shows these various operators and API calls in action. You can see that the Edit control style value changes between 0x503310C4 and 0x503318C4 depending on whether the $ES_READONLY syle is included - and you can check that the style is applied/removed by attempting to change the Edit content.

 #include <GUIConstantsEx.au3>
 #include <EditConstants.au3>
 #include <Constants.au3>
 #include <WinAPI.au3>
 
 $iCount = 1
 $sBut_Add = "Press to add ReadOnly style"
 $sBut_Sub = "Press to remove ReadOnly style"
 $sEdit_Text = "You can edit me if you wish"
 $sRead_Text = "But you can only read me"
 
 $hGUI = GUICreate("Test", 500, 160)
 
 $hEdit = GUICtrlCreateEdit($sEdit_Text, 10, 10, 480, 100)
 $hEdit_Handle = GUICtrlGetHandle(-1)
 
 $hButton = GUICtrlCreateButton($sBut_Add, 150, 120, 200, 30)
 
 GUISetState()
 
 ; Read default values
 $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
 MsgBox(0, "Initial Style", "Style = " & "Ox" & Hex($iStyle, 8))
 
 While 1
     Switch GUIGetMsg()
         Case $GUI_EVENT_CLOSE
             Exit
         Case $hButton
             Switch $iCount
                 Case 1
                     ; Use BitOR to ADD style
                     GUICtrlSetStyle($hEdit, BitOr($iStyle, $ES_READONLY))
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     $iCount += 1
                     MsgBox(0, "ReadOnly Added", "Style = " & "Ox" & Hex($iStyle, 8))
                     GUICtrlSetData($hButton, $sBut_Sub)
                     GUICtrlSetData($hEdit, $sRead_Text)
                 Case 2
                     ; Read the current style
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     ; Use BitXOR to SUBTRACT style
                     GUICtrlSetStyle($hEdit, BitXOR($iStyle, $ES_READONLY))
                     ; Read the new style
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     $iCount += 1
                     MsgBox(0, "ReadOnly Removed", "Style = " & "Ox" & Hex($iStyle, 8))
                     GUICtrlSetData($hButton, $sBut_Add)
                     GUICtrlSetData($hEdit, $sEdit_Text)
                 Case 3
                     ; Read the current style
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     ; Use BitOR to ADD style
                     GUICtrlSetStyle($hEdit, BitOr($iStyle, $ES_READONLY))
                     ; Read the new style
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     $iCount += 1
                     GUICtrlSetData($hButton, "")
                     MsgBox(0, "ReadOnly Added", "Style = " & "Ox" & Hex($iStyle, 8))
                     GUICtrlSetData($hButton, $sBut_Sub)
                     GUICtrlSetData($hEdit, $sRead_Text)
                 Case 4
                     ; Read the current style
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     ; Use BitAnd and BitNOT to SUBTRACT style
                     GUICtrlSetStyle($hEdit, BitAnd($iStyle, BitNOT($ES_READONLY)))
                     ; Read the new style
                     $iStyle   = _WinAPI_GetWindowLong($hEdit_Handle, $GWL_STYLE)
                     $iCount += 1
                     MsgBox(0, "ReadOnly Removed", "Style = " & "Ox" & Hex($iStyle, 8))
                     GUICtrlSetData($hButton, "Exit")
                     GUICtrlSetData($hEdit, $sEdit_Text)
                 Case 5
                     Exit
             EndSwitch
     EndSwitch
 WEnd

Summary

Setting styles is not difficult, but does require you to combine multiple styles correctly using BitOR. And if you want to add or subtract styles for an existing control you need to remember to take the existing styles into account or you will not end up with the final result you wanted.