Jump to content

ListView : Right click on column header


Recommended Posts

Hi guys,

In a listview, when you right click on a column header, why is the associated handle different from the listview handle ?

If you look at the example found in the help file, topic _GUICtrlListView_Create, you will notice that the following 5 actions are associated to the same listview handle.
These 5 actions are : LEFT click on a column header, single or double left click on items, single or double right click on items. But please notice how a right click on column headers does nothing in the help file example.

I can provide a script to show this, just clic everywhere and see how 2 different handles will be shown in the Console, as soon as you right clic on a column header. There is a context menu in the script but even if you comment the 3 lines creating it, you should still get 2 different handles.

Thanks to anyone who can explain this behavior :)
(a 2nd question, concerning $GUI_RUNDEFMSG, will be discussed later)

#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>

Global $hGUI = GUICreate("Right click for context menu", 300, 300)
Global $idListview = GUICtrlCreateListView(" Col A | Col B", 25, 25, 250, 250)

For $i = 0 To 4
    GUICtrlCreateListViewItem($i*10 & "|" & $i*10 +1, $idListview)
Next

Global $idMenu = GUICtrlCreateContextMenu($idListview)
Global $idMenu_1 = GUICtrlCreateMenuItem("Option 1", $idMenu)
Global $idMenu_2 = GUICtrlCreateMenuItem("Option 2", $idMenu)

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tNMHDR, $hWndFrom, $iIDFrom, $iCode

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    ; $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")

    Local $sMsgConsole = ""
    Switch $iCode
        Case $NM_CLICK
            $sMsgConsole = "Left click"
        Case $NM_RCLICK
            $sMsgConsole = "Right click"
        Case $NM_DBLCLK
            $sMsgConsole = "Double left click"
        Case $NM_RDBLCLK
            $sMsgConsole = "Double right click"
        Case $LVN_COLUMNCLICK
            $sMsgConsole = "Column left click"
    EndSwitch
    If $sMsgConsole <> "" Then
        ConsoleWrite($sMsgConsole & " : handle = " & $hWndFrom & @CRLF)
    EndIf

    Return $GUI_RUNDEFMSG ; we'll discuss later about Return, Return 0 and Return 1
EndFunc

 

Edited by pixelsearch
Link to comment
Share on other sites

  • Moderators

pixelsearch,

Quote

In a listview, when you right click on a column header, why is the associated handle different from the listview handle ?

Because the header is a separate control from the ListView itself - just as a button is separate from the GUI which contains it. The _GUICtrlListView_GetHeader function will get you the header handle if required.

The same thing is true for combo controls, where the combo, input and dropdown list are all separate controls - look at the example for _GUICtrlComboBox_GetComboBoxInfo to see this illustrated.

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

1 minute ago, Melba23 said:

look at the example for _GUICtrlComboBox_GetComboBoxInfo to see this illustrated.

@pixelsearch Or just "spy" it using AutoItWindowInfoTool :)
You'll notice that the ListView handle and the ListView header handle are different.

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

Thanks for your both answers :)
@Francesco : I still wonder how I forgot the AutoIt Window Info to double check the handle !

@Melba23 : glad you mentioned the _GUICtrlListView_GetHeader function (I didn't know it) and it will help me in another script, here, to detect where exactly is pressed the right mouse button, so I can manage the context menu rebuild in a better way.

Now the 2nd question concerns $GUI_RUNDEFMSG
Here is a part of what we can read in the help file, topic GUIRegisterMsg() :
"By default the AutoIt internal message handler (if there is one for that message) will be actioned after the user function exits. The AutoIt internal message handler will also be actioned if the keyword Return is used with the constant $GUI_RUNDEFMSG"

"However, if Return is used with any other value (including no value at all) the AutoIt internal message handler will NOT be actioned"

Reading this, I understand that Return (without any value), Return 0 or Return 1 will all prevent the AutoIt internal message handler to be actioned, right ?

But if you try them all in the script presented above, you will notice that :
* Return : same as Return $GUI_RUNDEFMSG : an item is selected when left click, the context menu appears when right click
* Return 0 : an item is selected when left click, context menu doesn't show when right click
* Return 1 : an item is not selected when left click, context menu doesn't show when right click

So can't we conclude that Return and Return $GUI_RUNDEFMSG do exactly the same ?
Because if "Return (without any value) doesn't action the AutoIt internal message handler" (as stated in the help file), so why does the context menu appear when you use the single word Return ?

Thanks for reading :)

Edited by pixelsearch
Link to comment
Share on other sites

"So an early return from the user function requires Return $GUI_RUNDEFMSG"

Early is the keyword, if you put the return at the very end of a func, it doesn't make a difference.  It is simply a way to tell the programmer that you want autoit to continue his work. Early return...

Link to comment
Share on other sites

Hi Nine,
It's been a long time, at least a few days  :)

My concern is that it should maybe be stated :
"So an early return from the user function requires Return $GUI_RUNDEFMSG or Return"

Because even if I don't place the word "Return" at the very end of the function, then AutoIt internal message handler is actioned. Let's try to place it at an incredible place in the function, did you say early ?

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Return
    
    Local $tNMHDR, $hWndFrom, $iIDFrom, $iCode
    ; All the rest of the function here...
    ; etc...
EndFunc

And here we are, nothing changes in the way I described it : an immediate Return keeps showing the context menu.
The question is : does "showing the context menu" mean that AutoIt internal message handler is actioned ?

* If the answer is "yes", then Return is equivalent to Return $GUI_RUNDEFMSG, no matter where the word Return is found in the function.

* If the answer is "no", then my bad... but one will have to explain then, why Return 0 or Return 1 don't display the context menu, when Return displays it :sweating:

Link to comment
Share on other sites

Hey @pixelsearch :)

2 hours ago, pixelsearch said:

The question is : does "showing the context menu" mean that AutoIt internal message handler is actioned ?

Yes, because right click is an event, and if you don't action the AutoIt internal message handler, it won't be processed and you'll not see the context menu to appear.

There is a "flow chart" created by @LarsJ which explains the flow of a Windows Message, and the role of $GUI_RUNDEFMSG in a function (WM_*) :)

 

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

I've been asked for a comment in this post.

pixelsearch, You're probably right that Return (without a value) and Return $GUI_RUNDEFMSG both causes the AutoIt internal message code to be executed. At least for WM_NOTIFY.

There are slightly different explanations in different versions of the help file.

I can see from what you've copied from the Help file that you're at 3.3.14.5. I'm still at 3.3.14.2. At 3.3.14.2, the text in the help file and especially the text at the bottom of the WM_COMMAND example is slightly better in accordance with what you have experienced.

The text at the bottom of the WM_COMMAND example:

; !!! But only 'Return' (without any value) will not proceed
; the default AutoIt3-message in the future !!!
Return $GUI_RUNDEFMSG

Note the last 3 words in the comment: "in the future".

But in the text above the example it's also mentioned that Return (without a value) does not execute the internal code. So it's not completely clear. If in doubt, just test it.


With regard to actual return values, you should check the Microsoft documentation so that you only return valid values. There are, for example, no return values for NM_CLICK (listview), while return values for NM_RCLICK (listview) are zero and non-zero. If you return a value that is not documented by Microsoft, check that it has no unintended effects.


It seems that the difficulties of using GUIRegisterMsg and the return values are somewhat overstated. In a real concrete example, it's very easy.


Merry Christmas.

Edited by LarsJ
Link to comment
Share on other sites

3 hours ago, LarsJ said:

pixelsearch, You're probably right that Return (without a value) and Return $GUI_RUNDEFMSG both causes the AutoIt internal message code to be executed. At least for WM_NOTIFY.


Now that made my day, thanks LarsJ for your expertise :)

Something should be done to clarify all these Return codes (concerning $GUI_RUNDEFMSG) because it's too complicated actually and Return 0 is definitely not the same as Return 1 (see how Return 1 doesn't allow to select an item in the script above, when Return 0 allows it) and both are different from Return as I clearly explained it earlier (Return allows the context menu to appear, same as Return $GUI_RUNDEFMSG) while Return 0 or 1 don't allow the context menu to appear.

I just followed your advice and consulted 2 MSDN web pages concerning Microsoft return codes :
* NM_RCLICK (list view) notification code : "Return nonzero to not allow the default processing, or zero to allow the default processing"
* WM_SIZE (like in this script ) : "If an application processes this message, it should return zero."

Now let's look at the help file. What do we read in it, concerning the "Return" keyword ?
We read this : "Unlike built-in functions, user-defined functions return 0 unless another return value is specified."

This means that in any udf, the 3 following actions always return 0 :
1) No Return keyword, the UDF ends with EndFunc, 0 is returned (that's important to know)
2) Return keyword anywhere in the UDF, 0 is returned (important too)
3) Return 0 anywhere in the UDF, 0 is returned

I wish this behavior had been applied to $GUI_RUNDEFMSG since day 1, I mean grouping these 3 cases, resulting in a one and single action (actioning or not AutoIt internal message handler, you choose, though Microsoft seems to use "0 to allow default processing")

Then any "non 0 Return" (like Return 1, Return -1, Return $GUI_RUNDEFMSG) would behave same, doing the opposite of the 3 cases exposed just above, that looks simple ! (too simple ?)

I guess it's a bit too late to do it that way, because it would be script breaking until the end of time...

Anyway, we'll see how this will be handled in a future AutoIt release
I wish you all a Merry Christmas and a good year 2019. Be safe and have a happy life :)

Edit : LarsJ, I would like to ask why you didn't upgrade with the last AutoIt release ?

 

Edited by pixelsearch
Forgot to ask LarsJ why he didn't upgrade !
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...