Jump to content

ListView GroupView Proper Export To Array


Recommended Posts

Introduction

Hi all, I'm known as Wolfeh and am new to the forum.

I apologize in advance to cover that this is my first posting after joining.

I've done my best to read over the rules and best practices for asking questions, so here goes my attempt at it.

The apology comes in if I do something incorrectly or don't provide enough information. Please feel free to correct me! 

Situation & Purpose

This is really one of my first harder coding projects outside the scope of simple send() commands and other amusing automation, and has already stumped me. What I'm attempting to do is create a small GUI targeted towards tracking day to day goals. I found the listview control to be the best approach to reaching what I envision, and now am just trying to work out the kinks to make it function the way I'd like it to. 

The functionality behind the program is simple. The user can track 3 different types of information. Things they need to do that day, things they want to get done that day and lastly what is their main goal with the day to feel accomplished. 

Features :

 - Add/Delete/Edit items in the list easily

 - Rearrange entries within their parent groups or drag them to others

 - Mark completed tasks by use of a check_box

 -  Export options to the clipboard

 - Entries saved locally and reloaded upon relaunch

This is a large goal for me and I'm attempting to introduce each feature in one at a time. I'm having some success but now am stuck at getting an export function working. 

Question(s) & Help Request

I am wanting a button that when clicked, will ultimately send data to my clipboard to be pasted elsewhere.

For now I would just like it to display an array, where the data is formatted like this:

Row [0]:  Group 1 ; Things I need to do..
Row [1]:  File my taxes ; Things I need to do item..

Row [2]:  Fix the car ; Things I need to do item..

Row [3]:  Pay the bills ; Things I need to do item..

Row [4]:  Group 2 ; Things I want to do..

Row [5]:  Program in autoit ; Things I want to do item..

Row [6]:  Order my school books ; Things I want to do item..

Row [7]:  Group 3 ; Main goals for the day..

Row [8]:  Drink 64oz of water; A goal to work towards

What I've Tried

Well I'm having all sorts of issues with stitching together examples and trying to understand what's going on at the same time. But what I've managed is to create empty entries to represent group headers. ( They hold a second purpose in that I don't know how to keep grouping active when all elements in that group are deleted, so they serve as a place holder ). I've tried different types of sorting and functions including but not limited to GUIListViewEx_ReadToArray(). This option seems like the best approach but the results sort the entries based on their index ( Creation order ).

My idea is to loop through the list reading each item's text..and checks what group it belongs to using _GUICtrlListView_GetItemGroupID(). Then maybe creating 3 arrays that store each of those items..then somehow merge those items all together into a larger array? I can't seem to draw up a way to approach this, I'm drawing a blank. I think all the features together are just bogging me down and becoming overwhelming to manage lol. So any help be it in code or pointers in the right direction would be very appreciated! Thanks in advance. 

Example Code  Note: You will need to have Melba23's GUIListViewEx() for this example to work properly. You can find it at '?do=embed' frameborder='0' data-embedContent>>

#cs --------------------------------------------------------------------------------------------------------------

Script Function : Display a ListView control with elements corresponding to a users need of data logging
Description     : Skeletal Frame for testing
Authors         : Wolfeh

Things to do:
    - Remove highlighting from all elements within a group when user clicks on group header
    - Alert user that an item has been completed by changing the appearance of an item checked
    - Find alternative method to keeping group headers after all elements in that group has been deleted
    - Add functionality to a key press - Pressing the "Delete" key will delete an item
    - Enable dragging items from group to group
    - Add button to export list to clipboard & settings file
    - Populate the listview items based on prior information entered within that same day on new load

Bugs to fix:
    - [ None ]

#ce ;--------------------------------------------------------------------------------------------------------------


 ; Includes -----------------------------------------------------------------------------------------------------
#include <Array.au3>
#include <ButtonConstants.au3>
#include <FontConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiImageList.au3>
#include <GUIListViewEx.au3>
#include <GuiMenu.au3>
#include <WindowsConstants.au3>
; ---------------------------------------------------------------------------------------------------------------

; Globals ---------------------------------------------------------------------------------------------------------
; Using params above 1000 to be safe for context menu
    Global Enum $CtrlMenu_Edit = 1000, $CtrlMenu_Del, $CtrlMenu_Add

; Font setup for Listview
    Global $hFont = _WinAPI_CreateFont(15, 6, 0, 0, $FW_NORMAL, False, False, False, _
    $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, 'Georgia')
; -----------------------------------------------------------------------------------------------------------------

; Main Form
$Sample_Form_For_Testing = GUICreate("Testing Bed", 414, 350, -1, -1)
GUISetState(@SW_SHOW)

; Button use to export the list information to the clipboard
$Button_Export_To_Clipboard = GUICtrlCreateButton("Export To Clipboard", 160, 300)

; Create a listview control to organize goals for the day
    $ListView_Goals = _GUICtrlListView_Create($Sample_Form_For_Testing, "Goals", 10, 10, 394, 268, BitOR($LVS_EDITLABELS, $LVS_REPORT, $LVS_NOCOLUMNHEADER, $LVS_SHOWSELALWAYS ))

; Then set some styling for it
    _GUICtrlListView_SetExtendedListViewStyle($ListView_Goals, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER, $LVS_EX_BORDERSELECT))
    _WinAPI_SetFont($ListView_Goals, $hFont, True)

    ; Our main column to list out our goals is lengthen to match group end
        _GUICtrlListView_SetColumnWidth($ListView_Goals, 0, 370 )

       ; These 3 items are used as place holders in our listview. Without them, when user deletes the
       ; last listview item in a group, it deletes the group header. I have not figured out a way
       ; to fix this yet, so this serves as a temporary solution by keeping one item in each group
       ; existing, as these have been hardcoded to not be deleted.
            _GUICtrlListView_AddItem($ListView_Goals, " ", 0, 1000)
            _GUICtrlListView_AddItem($ListView_Goals, " ", 0, 1001)
            _GUICtrlListView_AddItem($ListView_Goals, " ", 0, 1002)
            _RemoveCheckbox($ListView_Goals, 0)
            _RemoveCheckbox($ListView_Goals, 1)
            _RemoveCheckbox($ListView_Goals, 2)

        ; The purpose of these 3 items is to make it clear to the user what data is expected
            _GUICtrlListView_AddItem($ListView_Goals, "I need to...", 0, 1003)
            _GUICtrlListView_AddItem($ListView_Goals, "I want to...", 0, 1004)
            _GUICtrlListView_AddItem($ListView_Goals, "Main goal(s) for the day...", 0, 1005)

       ; Enable grouping within our listview
            _GUICtrlListView_EnableGroupView($ListView_Goals)

        ; Now design the 3 groups used to sort or data
            _GUICtrlListView_InsertGroup($ListView_Goals, -1, 1, "Group 1", 1) ; Need
            _GUICtrlListView_InsertGroup($ListView_Goals, -1, 2, "Group 2", 1) ; Want
            _GUICtrlListView_InsertGroup($ListView_Goals, -1, 3, "Group 3", 1) ; Goals

        ; Take our items we added before and sort them into groups.
            ; Non-Visible elements
            _GUICtrlListView_SetItemGroupID($ListView_Goals, 0, 1) ; Needs - Group 1
            _GUICtrlListView_SetItemGroupID($ListView_Goals, 1, 2) ; Wants - Group 2
            _GUICtrlListView_SetItemGroupID($ListView_Goals, 2, 3) ; Goals - Group 3
            ; Visible elements
            _GUICtrlListView_SetItemGroupID($ListView_Goals, 3, 1) ; Needs - Group 1
            _GUICtrlListView_SetItemGroupID($ListView_Goals, 4, 2) ; Wants - Group 2
            _GUICtrlListView_SetItemGroupID($ListView_Goals, 5, 3) ; Goals - Group 3

       ; Name and add styling to the groups, we do this here because you can't assign styling with insertgroups()
            _GUICtrlListView_SetGroupInfo($ListView_Goals, 1, "Things I need to do today", 1, $LVGS_COLLAPSIBLE)
            _GUICtrlListView_SetGroupInfo($ListView_Goals, 2, "Things I want to do today", 1, $LVGS_COLLAPSIBLE)
            _GUICtrlListView_SetGroupInfo($ListView_Goals, 3, "Main Goals for today", 1, $LVGS_COLLAPSIBLE)

    ; I'm using register as an event capture of mouse clicks to the listview
        GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")


; This is the main while loop used to keep the gui up as well as capturing a close event
    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                _WinAPI_DeleteObject($hFont)
                Exit
            Case $Button_Export_To_Clipboard

                ; Read array from our ListView
                Global $Array_ListView_Items = _GUIListViewEx_ReadToArray($ListView_Goals, 1)

                ; Delete the first element containing item(s) count
                _ArrayDelete($Array_ListView_Items, 0)

                ; The array as read from $Array_ListView_Items
                _ArrayDisplay($Array_ListView_Items, "Read from $Array_ListView_Items")



        EndSwitch
    WEnd
; ---------------------------------------------------------------------------------------


Func _ListView_RightClick_ContextMenu()

    Local $Item_Position ; Declare

    $Item_Position = _GUICtrlListView_SubItemHitTest($ListView_Goals) ; Define
        If ($Item_Position[0] <> -1) Then ; Error handling

        ; Create the main pop-up context menu
            $ListView_ContextMenu = _GUICtrlMenu_CreatePopup()
                ; Options -----------------------------------------------------------------------
                _GUICtrlMenu_AddMenuItem($ListView_ContextMenu, "Edit Task", $CtrlMenu_Edit)
                _GUICtrlMenu_AddMenuItem($ListView_ContextMenu, "Delete Task", $CtrlMenu_Del)
                _GUICtrlMenu_AddMenuItem($ListView_ContextMenu, "Add New Task", $CtrlMenu_Add)
                ; -------------------------------------------------------------------------------

            ; Determine which option the user selected
                Switch _GUICtrlMenu_TrackPopupMenu($ListView_ContextMenu, $ListView_Goals, -1, -1, 1, 1, 2)
                    ; Option Edit --------------------------------------------------------------------------------------------
                    Case $CtrlMenu_Edit
                        ; Find out what item was selected
                        $Selected_Item = _GUICtrlListView_GetSelectedIndices($ListView_Goals)
                            Switch $Selected_Item
                                Case 0
                                    ; Invisible element for group 1. I don't want this editable
                                Case 1
                                    ; Invisible element for group 2. I don't want this editable
                                Case 2
                                    ; Invisible element for group 3. I don't want this editable
                                Case Else
                                    ; If it's on an element in the list, other than those above..edit
                                     If $Selected_Item <> "" Then _GUICtrlListView_EditLabel($ListView_Goals, $Selected_Item)
                            EndSwitch
                    ; --------------------------------------------------------------------------------------------------------

                    ; Option Delete ------------------------------------------------------------------------------------------
                    Case $CtrlMenu_Del
                        ; Find out what item was selected
                        $Selected_Item = _GUICtrlListView_GetSelectedIndices($ListView_Goals)
                        Switch $Selected_Item
                            Case 0
                                ; Invisible element for group 1. I don't want this deletable
                            Case 1
                                ; Invisible element for group 2. I don't want this deletable
                            Case 2
                                ; Invisible element for group 3. I don't want this deletable
                            Case Else
                                ; If it's on an element in the list, other than those above..delete it
                                If $Selected_Item <> "" Then _GUICtrlListView_DeleteItemsSelected($ListView_Goals)
                        EndSwitch
                    ; --------------------------------------------------------------------------------------------------------

                    ; Option Add item ----------------------------------------------------------------------------------------
                    Case $CtrlMenu_Add
                        ; Find out what item was selected
                        $Selected_Item = _GUICtrlListView_GetSelectedIndices($ListView_Goals)

                        ; Find out what group that item belonged too
                        $Group_Item_Belonged_To = _GUICtrlListView_GetItemGroupID ( $ListView_Goals, $Selected_Item)

                        Switch $Group_Item_Belonged_To
                            Case 1 ; Group needs
                                ; Create the new item according to group
                                $Need_Count = _GUICtrlListView_AddItem($ListView_Goals, "I need to...")
                                ; Then place it into that group by assigning it the correct ID
                                _GUICtrlListView_SetItemGroupID($ListView_Goals, $Need_Count, 1)
                            Case 2 ; Group wants
                                ; Create the new item according to group
                                $Want_Count = _GUICtrlListView_AddItem($ListView_Goals, "I want to...")
                                ; Then place it into that group by assigning it the correct ID
                                _GUICtrlListView_SetItemGroupID($ListView_Goals, $Want_Count, 2)
                            Case 3 ; Group goals
                                ; Create the new item according to group
                                $Goal_Count = _GUICtrlListView_AddItem($ListView_Goals, "Main goal(s) for the day...")
                                ; Then place it into that group by assigning it the correct ID
                                _GUICtrlListView_SetItemGroupID($ListView_Goals, $Goal_Count, 3)
                        EndSwitch
                    ; --------------------------------------------------------------------------------------------------------
                EndSwitch

            ; Free up any memory that the context menu occupied
            _GUICtrlMenu_DestroyMenu($ListView_ContextMenu)

        EndIf
EndFunc


Func _RemoveCheckbox($LVM, $nIndex)

    ; Not 100% sure how this works but from what I gather it's just a blank image overlay placed over the checkbox itself

    ; ( $ListView_Handle, $Item, $Nul_State_Change, $Apply_Overlay_Image )
        _GUICtrlListView_SetItemState($LVM, $nIndex, 0, $LVIS_STATEIMAGEMASK)
    ; Return
        _WinAPI_RedrawWindow($LVM)

EndFunc


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    ; I have no idea how this function works, just doing my best to understand it
    ; I wish people would add comments to their code to help others understand it

    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo ; Initial declares

    $hWndListView = $ListView_Goals ; Handle of ListView control assignment

    ; Check- is base type pointer AND a window handle, if it's not then grab the handle
    If Not IsHWnd($ListView_Goals) Then $hWndListView = GUICtrlGetHandle($ListView_Goals)

    ; Create a C-Flavored structure:
    ;   ((Control sending the message's handle (64bit unsigned integer), Identifier of control (32bit signed integer), Add padding ), $ilParam is our pointer )
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) ; Size: 24   Handle: 1   Code: 3

    ; Grab the Handle and code from the structure
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, 1)) ; Convert before assignment
    $iCode = DllStructGetData($tNMHDR, 3)

    Switch $hWndFrom
        ; Event on listview handle
            Case $hWndListView
                ; Capture events
                Switch $iCode
                    ; Event Code: Mouse Left Click -----------------------------------------------------------
                     Case "-2"
                        ; If the user clicks on an item, we want it to be checked

                        ; Start by checking which item they clicked on
                        $Selected_Item = _GUICtrlListView_GetSelectedIndices($ListView_Goals)

                            Switch $Selected_Item
                                Case 0
                                    ; Ignore checking invisible element for group 1
                                Case 1
                                    ; Ignore checking invisible element for group 2
                                Case 2
                                    ; Ignore checking invisible element for group 3
                                Case Else

                                    If $Selected_Item <> "" Then
                                         ; If the item is already checked
                                            If _GUICtrlListView_GetItemChecked($ListView_Goals, $Selected_Item) Then
                                                ; Uncheck it
                                                _GUICtrlListView_SetItemChecked($ListView_Goals, $Selected_Item, False)
                                            Else ; If it isn't already checked
                                                ; Check it
                                                _GUICtrlListView_SetItemChecked($ListView_Goals, $Selected_Item, True)
                                            EndIf
                                    EndIf
                            EndSwitch

                        ; Build a C-Flavored structure with data from a list-view control when the user activates an item
                         $User_Activated_ListView_Control_Info = DllStructCreate($tagNMITEMACTIVATE, $ilParam)

                        ; Work with any cases in which the $iIndex param is one of our invisible elemets
                        Switch DllStructGetData($User_Activated_ListView_Control_Info, "Index")
                            Case 0, 1, 2
                                ; Simply intercept the normal return message, preventing the checkboxes from re-appearing
                                Return True
                        EndSwitch
                    ; ------------------------------------------------------------------------------------------

                    ; Event Code: Mouse Right Click ----------------------------
                    Case "-5"
                        ; Pop-up the context menu
                        _ListView_RightClick_ContextMenu()

                        ; Exit user defined function
                        Return 0
                    ; ---------------------------------------------------------

                    ; Event Code: Mouse Double Left Click --------------------------------------------------------------------------------
                    Case "-3"
                        ; Get item double clicked on
                        $Selected_Item = _GUICtrlListView_GetSelectedIndices($ListView_Goals)

                        ; Double clicking on an item first initiates a single click which checks it
                        ; We want to uncheck it to prevent accidental checking
                        If $Selected_Item <> "" Then ; Make sure it's on an item
                            ; If the item is checked as a result
                            If _GUICtrlListView_GetItemChecked($ListView_Goals, $Selected_Item) Then
                                ; Uncheck it
                                _GUICtrlListView_SetItemChecked($ListView_Goals, $Selected_Item, False)
                            EndIf
                        EndIf

                        Switch $Selected_Item  ; Make sure it's not one of the 3 group-keepers
                            Case 0
                                ; Invisible element for group 1. I don't want this editable
                            Case 1
                                ; Invisible element for group 2. I don't want this editable
                            Case 2
                                ; Invisible element for group 3. I don't want this editable
                            Case Else
                                ; If it's on an element in the list, other than those above..edit
                                 If $Selected_Item <> "" Then _GUICtrlListView_EditLabel($ListView_Goals, $Selected_Item)
                        EndSwitch

                        ; Build a C-Flavored structure with data from a list-view control when the user activates an item
                         $User_Activated_ListView_Control_Info = DllStructCreate($tagNMITEMACTIVATE, $ilParam)

                        ; Work with any cases in which the $iIndex param is one of our invisible elemets
                        Switch DllStructGetData($User_Activated_ListView_Control_Info, "Index")
                            Case 0, 1, 2
                                ; Simply intercept the normal return message, preventing the checkboxes from re-appearing
                                Return True
                        EndSwitch

                    ; --------------------------------------------------------------------------------------------------------------------

                    ; Event Code: Save the new item after edit ----------------------------------------------------------
                    Case "-176"

                        ; Build a C-Flavored structure with data from $LVN_SETDISPINFO ( $LVIF_TEXT ), (Pointer to the array of column indices)
                        Local $Item_Text_Info = DllStructCreate($tagNMLVDISPINFO, $ilParam)

                        ; Build a C-Flavored structured array based on the max size of the element edited (8bits*Max)
                        Local $Item_Buffer = DllStructCreate("char Text[" & DllStructGetData($Item_Text_Info, "TextMax") & "]", _
                            DllStructGetData($Item_Text_Info, "Text"))

                        ; We're going to temp store what we typed in from the edit into this array in "Text"
                        Local $New_List_Item_Text = DllStructGetData($Item_Buffer, "Text")

                        ; If what the user typed in is at least one character long then save the new string
                        If StringLen($New_List_Item_Text) Then Return True
                    ; ------------------------------------------------------------------------------------------------------------

                EndSwitch
            EndSwitch

    ; Have Autoit return to running its internal handler
        Return $GUI_RUNDEFMSG

EndFunc
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...