Jump to content

Action on selection in TreeView


Tjalve
 Share

Recommended Posts

Hi everyone. Im creating a GUI for an application. Im usinga  treeview item and i want to add some information to the side of the treeview based on what cilditem you are pressing. For the moment i have a "get info" button that works. But that means that you have to select your child in the treeview, and then press a button to gte the info. I want the info to be visable as soon as you select it.

With uther controls you can just add it to the loop but it doesnt seem to work with tyhe UDF version of the treeview control. Is there anything I can do?

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

;~ Create GUI
dim $guilabel[7]
local $currentlevel = 1
Local $hGui = GUICreate( "Grejs", 1000, 500, 600, 300, BitOR( $GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX ) )
Local $iBorderWidth = 4, $aPos = WinGetClientSize( $hGui )
$idTV = _GUICtrlTreeView_Create($hGui, $iBorderWidth, $iBorderWidth, $aPos[0]-2*$iBorderWidth-400, $aPos[1]-2*$iBorderWidth-30 )
$root_level = _GUICtrlTreeView_Add($idTV,0,"Root")
$item1 = _GUICtrlTreeView_AddChild($idTV, $root_level, "child1")
$item2 = _GUICtrlTreeView_AddChild($idTV, $root_level, "child2")
$item3 = _GUICtrlTreeView_AddChild($idTV, $root_level, "child3")

;~ Start Gui
GUISetState()
While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
        ExitLoop

        Case $idTV
            MsgBox(0,"","")

    EndSwitch
WEnd
GUIDelete($hGui)

Exit

In this example, i want the msgbox to appear whenevr i select something in the treeview. It ios not my full code, but its an example of the problam i have. Help is much appritiated :)

/G

Link to comment
Share on other sites

  • Moderators

Tjalve,

Here you go:

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

; Flag for TV selection change
Global $hItemSelected = 9999

;~ Create GUI
dim $guilabel[7]
local $currentlevel = 1
Local $hGui = GUICreate( "Grejs", 1000, 500, 600, 300, BitOR( $GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX ) )
Local $iBorderWidth = 4, $aPos = WinGetClientSize( $hGui )
$hTV = _GUICtrlTreeView_Create($hGui, $iBorderWidth, $iBorderWidth, $aPos[0]-2*$iBorderWidth-400, $aPos[1]-2*$iBorderWidth-30 )
$root_level = _GUICtrlTreeView_Add($hTV,0,"Root")
$item1 = _GUICtrlTreeView_AddChild($hTV, $root_level, "child1")
$item2 = _GUICtrlTreeView_AddChild($hTV, $root_level, "child2")
$item3 = _GUICtrlTreeView_AddChild($hTV, $root_level, "child3")

;~ Start Gui
GUISetState()

GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
        ExitLoop

    EndSwitch

    ; If flag set
    If $hItemSelected <> 9999 Then
        ; Here is the action
        MsgBox($MB_SYSTEMMODAL, "Selected", _GUICtrlTreeView_GetText($hTV, $hItemSelected))
        ; Clear flag
        $hItemSelected = 9999
    EndIf


WEnd
GUIDelete($hGui)

Exit

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam
    ; Create NMTREEVIEW structure
    Local $tStruct = DllStructCreate("struct;hwnd hWndFrom;uint_ptr IDFrom;INT Code;endstruct;" & _
            "uint Action;struct;uint OldMask;handle OldhItem;uint OldState;uint OldStateMask;" & _
            "ptr OldText;int OldTextMax;int OldImage;int OldSelectedImage;int OldChildren;lparam OldParam;endstruct;" & _
            "struct;uint NewMask;handle NewhItem;uint NewState;uint NewStateMask;" & _
            "ptr NewText;int NewTextMax;int NewImage;int NewSelectedImage;int NewChildren;lparam NewParam;endstruct;" & _
            "struct;long PointX;long PointY;endstruct", $lParam)
    If DllStructGetData($tStruct, "hWndFrom") = $hTV Then
        Switch DllStructGetData($tStruct, "Code")
            ; If item selection changed
            Case $TVN_SELCHANGEDA, $TVN_SELCHANGEDW
                Local $hItem = DllStructGetData($tStruct, "NewhItem")
                ; Set flag to selected item handle
                If $hItem Then $hItemSelected = $hItem
        EndSwitch
    EndIf
EndFunc

Note that I changed the variable in which you store the return from _GUICtrlTreeView_Create to reflect the fact that you get a handle and not a ControlID - please ask if you do not understand why this is important (or if you have any other questions).

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Hi Melba23 and thank you for your replay.

That work flawlessly! However i still dont really understand. I can deffenently use your code (and i will) but it would be nice to unerstand what is happening.

If i understand it correctly, the UDF fuctions doesnt return a ControlID, but a handle. I suspect there is a good reson for it, but thats boyond my understanding. Anyways, To use Switch and GuiGetMsg() i need a controlID. And since the function does not return one, it wont work.

In your case you are using an IF-statement to check if the itemselected varible has changed. What i dont understand is how that varible change. I see your function and I see some kind of DLL call ore something. But there is no way i would be able to write that myself. So is there some kind of logic to it?

Thank you again for your assistance?

Link to comment
Share on other sites

  • Moderators

Tjalve,

First, let us deal with handles and ControlIDs.

Windows handles are unique identifiers that the OS uses to keep track of everything on the system, such as GUIs and controls, which continually send messages around the system so that everything in the system knows what is going on (which GUI is active, which control has just been actioned, which key was pressed, etc, etc). These messages contain all sorts of data, but essentially explain "which control has just done what".

AutoIt tries to make life simple for you by using ControlIDs to identify its native controls - theses IDs are actually the indIces of an internal array of all controls maintained by AutoIt. So when you look for these ControlIDs in a GUIGetMsg loop you are asking AutoIt to access the Windows message stream and pick put those messages which refer to that control - the OnEvent commands work in a similar manner.

Now to how the script I posted works.

As the UDF functions return handles and not ControlIDs (which as explained above are only returned by AutoIt native functions) we cannot use a GUIGetMsg loop to look for messages, so we have to do it ourselves rather than relying on AutoIt to do it for us. This is where the GUIRegisterMsg command comes into play - it peeks into the Windows message stream and lets us see what is happening. In the script above we are asking to look at WM_NOTIFY messages - a pretty comprehensive set which, amongst many other things, covers selecting items in a TreeView. When a WM_NOTIFY message is detected in the stream AutoIt then runs the allocated function or "handler" where we can examine the message in detail:

  1. We create a data structure to look at the detailed content of the message - this data is stored by Windows and we use one of the message parameters ($lParam) to access it.
  2. We then check that this message was indeed sent by the treeview by looking inside the data structure - we can ignore the vast majority of messages which have been sent by other controls.
  3. Finally we check if the message deals with a change of the selected item in the treeview - and if it does than we know that we have found the message we were looking for.

And there you have it - because the treeview was created by a UDF and not by an internal AutoIt function, we had to recreate what AutoIt does for us "under the hood" and peer into the Windows message stream ourselves to intercept the message telling us that the user had selected another item in the treeview. You can see the same thing happening with tab controls if you read the Tabs tutorial in the Wiki - if you create the tab with the UDF you need to do a lot more work to make it work correctly.

I hope that the above explanation makes you realise how much AutoIt does for you behind the scenes - please ask again if anything is still unclear.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

On 2017-02-10 at 2:44 PM, Melba23 said:

Tjalve,

First, let us deal with handles and ControlIDs.

Windows handles are unique identifiers that the OS uses to keep track of everything on the system, such as GUIs and controls, which continually send messages around the system so that everything in the system knows what is going on (which GUI is active, which control has just been actioned, which key was pressed, etc, etc). These messages contain all sorts of data, but essentially explain "which control has just done what".

AutoIt tries to make life simple for you by using ControlIDs to identify its native controls - theses IDs are actually the indIces of an internal array of all controls maintained by AutoIt. So when you look for these ControlIDs in a GUIGetMsg loop you are asking AutoIt to access the Windows message stream and pick put those messages which refer to that control - the OnEvent commands work in a similar manner.

Now to how the script I posted works.

As the UDF functions return handles and not ControlIDs (which as explained above are only returned by AutoIt native functions) we cannot use a GUIGetMsg loop to look for messages, so we have to do it ourselves rather than relying on AutoIt to do it for us. This is where the GUIRegisterMsg command comes into play - it peeks into the Windows message stream and lets us see what is happening. In the script above we are asking to look at WM_NOTIFY messages - a pretty comprehensive set which, amongst many other things, covers selecting items in a TreeView. When a WM_NOTIFY message is detected in the stream AutoIt then runs the allocated function or "handler" where we can examine the message in detail:

  1. We create a data structure to look at the detailed content of the message - this data is stored by Windows and we use one of the message parameters ($lParam) to access it.
  2. We then check that this message was indeed sent by the treeview by looking inside the data structure - we can ignore the vast majority of messages which have been sent by other controls.
  3. Finally we check if the message deals with a change of the selected item in the treeview - and if it does than we know that we have found the message we were looking for.

And there you have it - because the treeview was created by a UDF and not by an internal AutoIt function, we had to recreate what AutoIt does for us "under the hood" and peer into the Windows message stream ourselves to intercept the message telling us that the user had selected another item in the treeview. You can see the same thing happening with tab controls if you read the Tabs tutorial in the Wiki - if you create the tab with the UDF you need to do a lot more work to make it work correctly.

I hope that the above explanation makes you realise how much AutoIt does for you behind the scenes - please ask again if anything is still unclear.

M23

I applaud you sir! Simple and understandable explanation. As i said, I probably would not be able to write it myself (maybe if i copy and paste some of your code :P). But now, atleast i understand whats going on. Great summary and many thanks!

Link to comment
Share on other sites

  • 3 months later...

I faced this problem too, my solution was a bit simpler:

$oldItem = ""
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    endSwitch
    
    $newItem = _GUICtrlTreeView_GetSelection($TreeView1)
    If $newItem <> $oldItem Then
        $oldItem = $newItem
        ;do stuff here with $newItem
    endif
wend

Maybe not as optimum, but straightforward.

0x616e2069646561206973206c696b652061206d616e20776974686f7574206120626f64792c20746f206669676874206f6e6520697320746f206e657665722077696e2e2e2e2e

Link to comment
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
 Share

×
×
  • Create New...