Sign in to follow this  
Followers 0
thrasher

Filtering a listview with a header filterbar control

1 post in this topic

Hello,

I'm hoping someone can help with this.

My goal seemed like it should be simple enough, but has turned into a rather difficult task that I'm unable to solve.

I just want to make use of a header filterbar for a listview control by using the text entered for a specific column to filter the items.

The example code shows what I've come up with so far, most of which is straight from the AutoIt help file, except for adding the filter bar.

#include <Constants.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>
#include <WinAPI.au3>

$gui = GUICreate("listview filter", 400, 250, -1, -1)
$listview = GUICtrlCreateListView("col0|col1|col2", 10, 10, 380, 230)
GUICtrlSendMsg(-1, 0x101E, 0, 125)
GUICtrlSendMsg(-1, 0x101E, 1, 125)
GUICtrlSendMsg(-1, 0x101E, 2, 125)
GUICtrlCreateListViewItem("blue|green|blue", $listview)
GUICtrlCreateListViewItem("red|blue|green", $listview)
GUICtrlCreateListViewItem("green|red|red", $listview)
GUICtrlCreateListViewItem("blue|green|blue", $listview)
GUICtrlCreateListViewItem("red|blue|green", $listview)
GUICtrlCreateListViewItem("green|red|red", $listview)
GUICtrlCreateListViewItem("blue|green|blue", $listview)
GUICtrlCreateListViewItem("red|blue|green", $listview)
GUICtrlCreateListViewItem("green|red|red", $listview)
GUICtrlCreateListViewItem("blue|green|blue", $listview)
GUICtrlCreateListViewItem("red|blue|green", $listview)
GUICtrlCreateListViewItem("green|red|red", $listview)
GUISetState()

;Use of lock/unlock and begin/end update is just to cause repainting so the filterbar is fully visible
GUISetState(@SW_LOCK, $gui)
_GUICtrlListView_BeginUpdate($listview)

;Add the filter bar to the header control
$header = _GUICtrlListView_GetHeader($listview)
$styles = _WinAPI_GetWindowLong($header, $GWL_STYLE)
_WinAPI_SetWindowLong($header, $GWL_STYLE, BitOR($styles, $HDS_FILTERBAR))

;Use of lock/unlock and begin/end update is just to cause repainting so the filterbar is fully visible
_GUICtrlListView_EndUpdate($listview)
GUISetState(@SW_UNLOCK, $gui)

;Register WM_NOTIFY to handle $HDN_FILTERBTNCLICK messages
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

;Loop GUI until exit
Do
    $msg = GUIGetMsg()
Until $msg = $GUI_EVENT_CLOSE


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode
    Local $tNMHDR, $tNMHEADER, $tNMHDFILTERBTNCLICK, $tNMHDDISPINFO
    Local $iHeaderItem, $tItem
    Local $HDFT_ISSTRING = 0x0
    Local $HDFT_ISNUMBER = 0x1

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $header
            Switch $iCode
                Case $HDN_FILTERBTNCLICK ; Notifies the header control's parent window when the filter button is clicked or in response to an $HDM_SETITEM message
                    $tNMHDFILTERBTNCLICK = DllStructCreate($tagNMHDFILTERBTNCLICK, $ilParam)
                    $column = DllStructGetData($tNMHDFILTERBTNCLICK, "Item")
                    MsgBox(0, "Msg", "Filter button click for column " & $column & @CRLF & _
                            "Now I need code for getting the filter text!")


                    ;Return True  ; An $HDN_FILTERCHANGE notification will be sent to the header control's parent window
                    ; This notification gives the parent window an opportunity to synchronize its user interface elements
                    Return False ; If you do not want the notification sent
                Case $HDN_FILTERCHANGE ; Notifies the header control's parent window that the attributes of a header control filter are being changed or edited
                    ;$tNMHEADER = DllStructCreate($tagNMHEADER, $ilParam)
                    ; no return value
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

The next step is to retrieve the text entered into the filter edit control and then pass that text to a function that handles filtering out the data.

There's some sample code I found at http://www.codeproject.com/KB/list/listviewfilter.aspx?msg=2279151

I've pasted the code below. Can I duplicate this in AutoIt 3.3?

I'm totally stumped by the marshaling memory functions that are used.

For reference, here are the values of the W32_XXX variables that are used.

I looked them up in Win32Msgs.cs, Win32Struct.cs, and Win32Enum.cs that are provided in the source files.

W32_HDI.HDI_FILTER = 0x0100

W32_HDFT.HDFT_ISSTRING = 0x0000

W32_HDM.HDM_GETITEMA = 0x1200 + 3

// structures used (see Win32 documentation)

HDTEXTFILTER hdTextfilter = new HDTEXTFILTER();
HDITEM       hdItem       = new HDITEM();

// get the current text content of a <code>column</code> filter.

// this is tricky since it involves marshalling pointers

// to structures that are used as a reference in another

// structure.  first initialize the receiving HDTEXTFILTER

hdTextfilter.pszText    = new string( new char[ 64 ]);
hdTextfilter.cchTextMax = hdTextfilter.pszText.Length;

// set the HDITEM up to request the current filter content

// NOTE: the HDI_FILTER flag in the mask means that the

// pvFilter points to a HDTEXTFILTER structure...

hdItem.mask = W32_HDI.HDI_FILTER;
hdItem.type = (uint)W32_HDFT.HDFT_ISSTRING;

// marshall memory big enough to contain a HDTEXTFILTER

hdITEM.pvFilter = Marshal.AllocCoTaskMem(
  Marshal.SizeOf( hdTextfilter ) );

// now copy the HDTEXTFILTER structure to the marshalled memory

Marshal.StructureToPtr( hdTextfilter, hdItem.pvFilter, false );

// retrieve the header filter string as non-wide string

SendMessage( col_hdrctl.Handle, W32_HDM.HDM_GETITEMA, <code>column</code>,
    ref hdItem );

// un-marshall the memory back into the HDTEXTFILTER structure
hdTextfilter = (HDTEXTFILTER)Marshal.PtrToStructure(
  col_hditem.pvFilter, typeof( HDTEXTFILTER ));

// remember to free the marshalled IntPtr memory...
Marshal.FreeCoTaskMem( hdItem.pvFilter );

// return the string now in the text filter area
return hdTextfilter.pszText;

Thank you in advance for any feedback or suggestions on how to get this to work in AutoIt!

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