Sign in to follow this  
Followers 0
Clark

A little elegance required

5 posts in this topic

Hi there

I know how to solve this problem with brute force, but I like my code to have some elegance so thought I would seek some help. I am not very familiar with bitwise operations so am floundering a little.

A small part of my programme has four checkboxes, labelled $cbImp[1-4]. Rather than store a binary on/off field four times I have used a bitwise operator to store all possible combinations (15) as a number, thusly:

for $item = 1 to 4
if GUICtrlRead($cbImp[$item]) = $GUI_CHECKED then $temp[$item]=2^($item-1)
Next
$Impacts=BitOR($temp[1],$temp[2],$temp[3],$temp[4])

This works well and stores in the database in a single field a number which I can (in my head) read back and restore the checkboxes to their previous state.

However, I can't find an elegant way to handle the 15 combinations (each checkbox being checked or unchecked) [actually it might be 16 - doesn't matter] with a huge case statement or some such.

I know if I read in an odd number it will always mean that $cbImp[1] will be checked. I know a number greater than 8 will mean that $cbImp[4] will be checked, but the middle two numbers look difficult.

Any pointers? (I hope I explained this well enough)

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

The function you are looking for is BitAnd.

$d_0001 = 1
$d_0010 = 2
$d_0100 = 4
$d_1000 = 8

$dFlag = BitOR($d_0010, $d_0100)

If BitAND($dFlag, $d_0001) = 1 Then MsgBox(0, "", "0001") ; False
If BitAND($dFlag, $d_0010) = 2 Then MsgBox(0, "", "0010") ; True
If BitAND($dFlag, $d_0100) = 4 Then MsgBox(0, "", "0100") ; True
If BitAND($dFlag, $d_1000) = 8 Then MsgBox(0, "", "1000") ; False

; Check for both $d_0100 and $d_0010 in one line of code:
If BitAND($dFlag, 6) = 6 Then MsgBox(0, "", "0110") ; True

; To check if all four bits are set you would use:
If BitAND($dFlag, 15) = 15 Then MsgBox(0, "", "1111") ; False
Edited by czardas

Share this post


Link to post
Share on other sites

How about

Share this post


Link to post
Share on other sites

Here is an example that can check if a number of checkboxes are checked or unchecked.

#include <GUIConstantsEx.au3>

Local $sRes, $iNumCBoxes = 15
Local $iNum = Checkboxes($iNumCBoxes)

; Check if checkboxes are checked or unchecked from the sum of the checked checkboxes.
For $item = 0 To $iNumCBoxes - 1
    If BitAND(2 ^ $item, $iNum) = 2 ^ $item Then
        ; or
    ;If BitAND(2 ^ $item, $iNum) = BitShift(1, -$item) Then
        $sRes &= $item + 1 & " checked." & @CRLF
    Else
        $sRes &= $item + 1 & " un-checked." & @CRLF
    EndIf
Next

MsgBox(0, "Results", $sRes)


Func Checkboxes($iNumCB)
    Local $msg, $cbImp[$iNumCB], $iSum
    GUICreate("My GUI Checkboxes")

    For $item = 0 To $iNumCB - 1
        $cbImp[$item] = GUICtrlCreateCheckbox("CHECKBOX " & ($item + 1), 10, 10 + ($item * 25), 120, 20)
    Next

    GUISetState()

    While 1
        $iSum = 0
        $msg = GUIGetMsg()

        ; Check if checkboxes are checked or unchecked. And, sum the checked checkboxes.
        For $item = 0 To $iNumCB - 1
            If BitAND(GUICtrlRead($cbImp[$item]), $GUI_CHECKED) = $GUI_CHECKED Then $iSum += 2 ^ $item ; or BitShift(1, -$item)
        Next

        If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    WEnd
    Return $iSum
EndFunc   ;==>Checkboxes

Share this post


Link to post
Share on other sites

Thankyou people

czardas had the best answer for me.

Here is the code I used:

for $index = 1 to 4
$text = 2^($index-1)
if BitAND($bResult[9],$text) = $text then GUICtrlSetState($cbImp[$index],$GUI_CHECKED)
Next
1 person likes this

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
Sign in to follow this  
Followers 0