Announcement

Collapse
No announcement yet.

ListView select row

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • ListView select row

    I have a listview that is populated after a database query.
    The listview has 4 columns (0-3).
    I want for when the user clicks the listview, that I can get the value of column 4 of the row they clicked and do something with that data.

    My problems is in the callback.
    What API group do I need?

    Code:
            CASE %wm_notify
                udtNMListview = CBLPARAM
                SELECT CASE @udtNMListview.hdr.Code
                    CASE %LVN_COLUMNCLICK
                        ' column heading is clicked
                        
                    CASE %LVN_ITEMCHANGED
                        ' row clicked
                         lngIndex = ListView_GetNextItem( mainLV, - 1, %LVNI_SELECTED )
                         MSGBOX STR$(lngIndex)
                         CALL ListView_GetItemText( mainLV, lngIndex, 3, aszText, SIZEOF( aszText ))
                         msgbox aszText
    
                END SELECT
    %LVN_ITEMCHANGED is not what I want because that will throw up a value for every item in the LV.

    Is there something like %LVN_ITEMSELECTED?

    I just don't see what I need in the API reference.

  • #2
    want for when the user clicks the listview, that I can get the value of column 4 of the row they clicked and do something with that data
    You can look for WM_NOTIFY/NM_CLICK. The selected item (row) is in NMITEMACTIVATE.iITem .. but only if the click occured where a selection occurs. (Full row select style on/off affects this).

    Better (more reliable).....use Listview_HitTest against nmitemactivate.ptaction to know exactly where that click occurred.

    OR.... if you want to do this on "change of selection" rather than on click .. eg, the user uses the arrow keys to navigate within the listview control (forget about the keyboard interface for a moment, did we?)......

    Yes, you CAN use WM_NOTIFY/LVN_ITEMCHANGED... you are looking for a "state" change to LVIF_FOCUSED.. only one row is ever focused... and it not even need be in a selected state. (single- and multiple-selection listviews act differently).

    (Just forget about Listview_GetNextITem, you don't need it at all).

    MCM
    Last edited by Michael Mattias; 8 Apr 2008, 01:59 PM.
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      thanks, for now I just did this
      Code:
              CASE %wm_notify
                  udtNMListview = CBLPARAM
                  SELECT CASE @udtNMListview.hdr.Code
                      CASE %LVN_COLUMNCLICK
                          ' column heading is clicked
                          ' use later for sort?
                          
                      CASE %nm_click
                          ' row clicked
                           lngIndex = ListView_GetNextItem( mainLV, - 1, %LVNI_SELECTED )
                           strName = LV_ReadItem( lngIndex, 3 )
                           retrieveRecord(strName)
      
                  END SELECT
      not as nice as what you suggested but I understand it enough so I can move on. The ability for keyboard selection is not necessary this time.
      ListView needs a wrapper!

      Comment


      • #4
        Code:
        CASE %nm_click
                  [B]          ' row clicked[/B]
        You were not paying attention, because IT AIN'T NECESSARILY SO!

        Demo: Click on your listview control OUTSIDE the location of the rows.

        Oops, huh?

        Like your mama always told you, if it's worth doing, it's worth doing right.

        This does Selected rather than focused, which is what I do with single-selection listviews:
        Code:
        #IF NOT %DEF(%LVUNION)
         UNION LvUnion
            NMHDR  AS NMHDR
            NMLV   AS NMLISTVIEW
            NMIA   AS NMITEMACTIVATE
            LVDI   AS LV_DISPINFO
            LVCD   AS NMLVCUSTOMDRAW
            NMLVK  AS NMLVKEYDOWN
           ' NMTVDI AS TV_DISPINFO
           ' NMTV   AS NM_TREEVIEW
         END UNION
         %LVUNION = 1
        #ENDIF
        ...
        
        FUNCTION Window/DialogProc....
        
           LOCAL plvu AS LvUnion PTR
        
          SELECT CASE AS LONG wMsg 
        
        
                 CASE %WM_NOTIFY
                     plvu = lparam          ' always needed to do anything, whatever the control is.
        
                     SELECT CASE AS LONG @plvu.nmhdr.idfrom
                          CASE %ID_LV      ' message from the listview 
                              SELECT CASE AS LONG @plvu.nmhdr.code 
                                       CASE %LVN_ITEMCHANGED
                                           IF ISTRUE (@plvu.NMLV.uChanged AND %LVIF_STATE)  THEN 
                                                ' an item's state has changed
                                               ' Is that state change a selected/unselected state change?
                                               IF ISTRUE  (@plvu.nmlv.uNewState AND %LVIS_SELECTED)  THEN
        
                                               DO STUFF HERE
        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          that's true, but I'm pulling a value from the row.
          If it is an empty string then I just ignore it.

          Code:
          FUNCTION  retrieveRecord(recordNumber AS STRING) AS LONG
              LOCAL sqlStatement AS STRING
              LOCAL errMsg AS STRING
              LOCAL d AS STRING
              LOCAL tST AS SYSTEMTIME
          
              IF recordNumber="" THEN EXIT FUNCTION
          
              sqlStatement = "select * from mainTable where quoteNumber="+recordNumber     
          ...... and so forth
          no?

          Comment


          • #6
            >If it is an empty string then I just ignore it.

            You got me there.

            I guess I'd forgotten how to program lazily^h^h^h^h^h^h like a Microsoft Visual Basic 'programmer'

            Yes, I will have fries with that, thank you.
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              For what it's worth, here is my wm_notify event handler. You may find some info here that is useful.

              Code:
                  CASE %WM_NOTIFY
                      SELECT CASE CBCTL
                        CASE 1005 '%RPTLISTVIEW
                           CONTROL HANDLE CBHNDL, %RPTLISTVIEW TO hctrl&
                           my_LpLvNm = CBLPARAM
                           SELECT CASE @my_LpLvNm.hdr.code
                             CASE %NM_DBLCLK
                               I = ListView_GetNextItem(BYVAL hctrl&, -1, %LVNI_SELECTED)
                               IF I > -1 THEN
                                 GETLISTVIEWSELECT = I
                                 NEW_FLAG = 0
                                 MAC_WINPOS(idlg&)
                                 ShowWindow idlg&, %SW_SHOW
                                 DIALOG END CBHNDL,2 'simulate LOAD query
                               END IF
                             CASE %NM_CLICK
                               I = ListView_GetNextItem(BYVAL hctrl&, -1, %LVNI_SELECTED)
                               IF I > -1 THEN
                                 GETLISTVIEWSELECT = I
                               ELSEIF I = -1 THEN
                                 tLVI.iSubItem = 0
                                 tLVI.iItem    = 0
                                 tLVI.STATE    = %LVIS_FOCUSED OR %LVIS_SELECTED
                                 tLVI.stateMask = %LVIS_FOCUSED OR %LVIS_SELECTED
                                 CONTROL SEND CBHNDL,CBCTL, %LVM_SETITEMSTATE, 0&, VARPTR(tLVI) 'don't highlight first row. Make them select
                                 tLVI.STATE = 0
                                 tLVI.stateMask = 0
                                 I = ListView_GetNextItem(BYVAL hctrl&, -1, %LVNI_SELECTED)
                                 GETLISTVIEWSELECT = I
                               END IF
                             CASE %LVN_COLUMNCLICK
                               LV_COLUMNID = @my_LpLvNm.iSubItem
                               SELECT CASE PARSE$(FDA(LV_COLUMNID + 1),",",2)
                                 CASE "C"
                                   CDIRECTION = NOT CDIRECTION
                                   IF CDIRECTION THEN
                                     sortdir$ = "ascending"
                                   ELSE
                                     sortdir$ = "descending"
                                   END IF
                                 CASE "N"
                                   NDIRECTION = NOT NDIRECTION
                                   IF NDIRECTION THEN
                                     sortdir$ = "ascending"
                                   ELSE
                                     sortdir$ = "descending"
                                   END IF
                                 CASE "D"
                                   DDIRECTION = NOT DDIRECTION
                                   IF DDIRECTION THEN
                                     sortdir$ = "ascending"
                                   ELSE
                                     sortdir$ = "descending"
                                   END IF
                               END SELECT
                               CONTROL SET TEXT CBHNDL,1006,"Sorting..."
                               ListView_SortItems(@my_LpLvNm.hdr.hwndFrom, CODEPTR(CompareFunc), my_LpLvNm)
                               CONTROL SET TEXT CBHNDL,1006,"Sorted " + sortdir$ + " by " + PARSE$(FDA(LV_COLUMNID + 1),",",1)
                               FixLParam(@my_LpLvNm.hdr.hwndFrom)
                               VKEY = 21
                           END SELECT
                           kp = CBLPARAM
                           SELECT CASE @kp.hdr.code
                             CASE %LVN_KEYDOWN
                               SELECT CASE @kp.wVKEY
                                 CASE %VK_ADD
                                   I = ListView_GetNextItem(BYVAL hctrl&, -1, %LVNI_SELECTED)
                                   IF I > -1 THEN
                                     GETLISTVIEWSELECT = I
                                     MAC_WINPOS(idlg&)
                                     ShowWindow idlg&, %SW_SHOW
                                     DIALOG END CBHNDL,2 'simulate LOAD query
                                   END IF
                                 CASE %VK_DOWN
                                   I = ListView_GetNextItem(BYVAL hctrl&, -1, %LVNI_SELECTED)
                                   IF I > -1 THEN
                                     GETLISTVIEWSELECT = I
                                   END IF
                                 CASE %VK_UP
                                   I = ListView_GetNextItem(BYVAL hctrl&, -1, %LVNI_SELECTED)
                                   IF I > -1 THEN
                                     GETLISTVIEWSELECT = I
                                   END IF
                               END SELECT
                           END SELECT
                      END SELECT

              Comment


              • #8
                like a Microsoft Visual Basic 'programmer'
                AHHH! Cuts me to the quick man! CUTS ME TO THE QUICK! Ouch!

                yeah I know

                Thanks everyone.

                Comment


                • #9
                  like a Microsoft Visual Basic 'programmer'
                  MCM...don't forget we were "lulled" into it, not knowing any better

                  The good part is, the ones that see the light, start wondering "Why do I do this?...How does it REALLY work? and more importantly WHY?

                  Maybe rare breeds, but rare breeds are what makes computing so great
                  Engineer's Motto: If it aint broke take it apart and fix it

                  "If at 1st you don't succeed... call it version 1.0"

                  "Half of Programming is coding"....."The other 90% is DEBUGGING"

                  "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                  Comment


                  • #10
                    For whatever it's worth, here are some functions I use.

                    The "get selection" gets the FIRST selected item, so it's only useful with single-select listviews. The "set" also sets the focused status, so while it will work with both single- and multi-select listviews, you need to be aware the focused item changes when you use it with a multi-select listview.


                    Code:
                    ' Get the first selected row of a listview
                    FUNCTION ListView_GetSelection (BYVAL hWnd AS LONG) AS LONG
                      FUNCTION = SendMessage(hWnd, %LVM_GETNEXTITEM, -1, %LVNI_SELECTED)
                    END FUNCTION
                    'selected status of a listview row to true 
                    FUNCTION ListView_SetSelection (BYVAL hWnd AS LONG, BYVAL Rowno AS LONG) AS LONG
                      ListView_SetItemState hWnd, RowNo, &hFFFFFFFF, (%LVIS_SELECTED OR %LVIS_FOCUSED)
                    END FUNCTION
                    Yes, you could convert these to MACROs pretty easily, but these were created before MACROS were supported by the compilers, and if it ain't broke.....

                    MCM
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      As long as it seems to be "listview day..."


                      Here's an edited and commented version of the NM_CLICK processing I use to determine the row and column of a click on a listview control ..
                      Code:
                       LOCAL plvu AS LVUNION PTR             ' <<<< LVUNION IN PRIOR POST ABOVE 
                       LOCAL hti  AS AS LVHITTESTINFO        ' <<< IN COMMCTRL.INC
                      
                       SELECT CASE AS LONG wMSg   (or "CBMSG" for DDT'ers) 
                        
                          CASE  %WM_NOTIFY                                ' a message from one of the Common Controls  
                               SELECT CASE AS LONG @pvlu.nmhdr.idFrom     ' which control is WM_NOTIFY from?
                                    CASE %ID_LISTVIEW
                                       ' Ok, it's from that listview, now what is the specific notification? 
                                        SELECT CASE  AS LONG @plvu.nmhdr.code 
                                    
                                                     CASE %NM_CLICK   ' returns NMIA
                                                             ' hti.pt  = @plvu.nmia.ptAction              ' get real click pos
                                                             ' above only valid with common controls 4.71 or higher.
                      
                                                             ' for generic, works regardless of Common Controls version:
                                                             GetCursorPos        hti.pt
                                                             ScreenToClient      hWnd, hti.pt
                      
                                                            ' test the point:
                                                            iHit = Listview_SubItemHitTest (@plvu.nmhdr.hWndFrom, hti)
                                                            ' and decide if I'm on the item:
                                                            ' NOWHERE=in control client area, but not on any item
                                                            IF ISTRUE (hti.flags AND %LVHT_NOWHERE) THEN
                                                               Do whatever you do when user clicks not on a row
                                                            ELSEIF ISTRUE (hti.flags AND [b]%LVHT_ONITEM[/b]) THEN
                                                                ROW (item)       ==> hti.iTem
                                                                COLUMN (subitem) ==> hti.iSubITem but ONLY with CC version 4.70+
                                                                'but doc also says iSubItem is always zero when hit testing
                                                                'so I'm not sure exactly what you get here. 
                                                                ' but I usually don't care about which subitem* 
                                                            ......
                      A little extra doc from SDK re hit testing.....
                      'You can test for LVHT_ONITEM to determine whether a specified position is over a list-view item. This value is a bitwise-OR operation on LVHT_ONITEMICON, LVHT_ONITEMLABEL, and LVHT_ONITEMSTATEICON.
                      Again, this is for testing CLICKS... but - especially when using a single-select listview - it may be more advantageous to intercept the LVIS_SELECTED state changes posted above than testing specifically for mouse clicks... remember the listview control WILL process the up and down arrow keys if the listview control has the keyboard focus, and will move the focused item (and selection, if single select) up and down one row as you use them. IIRC, with multi-select listview, the arrow keys do not set the selection, but do set the focused item... you then toggle the selected status of the currently-focused row with <spacebar>.



                      * There is a (subjective) nice demo of processing DOUBLE clicks at Listview with Multiple Checkbox Columns Demo 2-20-05. The doc for NM_DBLCLK then says you CAN get sub-item (column) reliably with Listview_SubItemHitTest.

                      MCM
                      PS: In case you can't tell, the listview control is one of my favorites.
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Marvelous, fantastic...
                        It was simpler than I thought.
                        Have modified the code that had inserted in the post (Listview with Multiple Checkbox Columns Demo 2-20-05.) to manage the single clik (the double click should be very simple!)
                        Have you seen that the things can be resolved in very simple way without so many complications of planning??
                        Now that I have understood the mechanism I believe (I hope) not to have big problems.
                        Still thanks
                        Roberto


                        ' Global.bas
                        '*****************************
                        .
                        .
                        UNION LvUnion
                        NMHDR AS NMHDR
                        NMLV AS NMLISTVIEW
                        NMIA AS NMITEMACTIVATE
                        LVDI AS LV_DISPINFO
                        LVCD AS NMLVCUSTOMDRAW
                        NMTTDI AS NMTTDISPINFO
                        END UNION

                        ' Main file
                        .
                        CALLBACK FUNCTION xxxxxxxxxx()
                        LOCAL plvu AS LvUnion PTR
                        LOCAL iSelRow AS LONG, iSelCol AS LONG

                        LOCAL lvNm AS NM_LISTVIEW PTR
                        STATIC zText AS ASCIIZ * 256
                        STATIC l_Testo AS STRING

                        SELECT CASE AS LONG CBMSG
                        CASE %WM_NOTIFY
                        plvu = CBLPARAM
                        SELECT CASE AS LONG @plvu.nmhdr.idfrom
                        CASE %IDC_SYSLISTVIEW32

                        SELECT CASE AS LONG @plVU.nmhdr.code
                        CASE %NM_CLICK
                        iSelRow = @plvu.nmia.iItem
                        iSelCol = @plvu.nmia.iSubItem
                        IF iSelRow >= 0 THEN ' if something is selected
                        ' Column 0 = the identify of the user to retrieve the data in the database
                        ListView_getITemText @plvu.nmhdr.hwndFrom, iSelRow, 1, zText, SIZEOF(zText) ' Surname
                        l_Testo= zText
                        ListView_getITemText @plvu.nmhdr.hwndFrom, iSelRow, 2, zText, SIZEOF(zText) ' Name
                        l_Testo=l_Testo & " " & zText
                        CONTROL SET TEXT h_frmAnagrafeOUT, %lbl_Info, l_Testo ' Fill the label with the informations
                        .
                        .
                        robcondor

                        Comment

                        Working...
                        X