Announcement

Collapse
No announcement yet.

ListView_getsubItemRect for first column?

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

  • ListView_getsubItemRect for first column?

    I don't see any other posts about this, so I will throw this out there. I am having issues with getting the RECT size for the first column in a listview. The r.right returned is always huge (by huge, I mean bigger than the width of the entire control). Here is an example I slapped together in PB form1 1.5, but compiled with PBwin 10:

    Code:
    #COMPILE EXE
    #DIM ALL
    
    '------------------------------------------------------------------------------
    '   ** Includes **
    '------------------------------------------------------------------------------
    #PBFORMS BEGIN INCLUDES
    %USEMACROS = 1
    #IF NOT %DEF(%WINAPI)
        #INCLUDE "WIN32API.INC"
    #ENDIF
    #IF NOT %DEF(%COMMCTRL_INC)
        #INCLUDE "COMMCTRL.INC"
    #ENDIF
    #INCLUDE "PBForms.INC"
    #PBFORMS END INCLUDES
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Constants **
    '------------------------------------------------------------------------------
    #PBFORMS BEGIN CONSTANTS
    %IDD_DIALOG1         =  101
    %IDC_SYSLISTVIEW32_1 = 1001
    %IDC_BUTTON1         = 1002
    #PBFORMS END CONSTANTS
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Declarations **
    '------------------------------------------------------------------------------
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION SampleListView(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL _
        lColCnt AS LONG, BYVAL lRowCnt AS LONG) AS LONG
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    #PBFORMS DECLARATIONS
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Main Application Entry Point **
    '------------------------------------------------------------------------------
    FUNCTION PBMAIN()
        PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR _
            %ICC_INTERNET_CLASSES)
    
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** CallBacks **
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
    LOCAL hctl AS LONG
    LOCAL r AS rect
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                ' Initialization handler
    
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
            CASE %WM_COMMAND
                ' Process control notifications
                SELECT CASE AS LONG CBCTL
                    CASE %IDC_SYSLISTVIEW32_1
    
                    CASE %IDC_BUTTON1
                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                CONTROL HANDLE CBHNDL, %IDC_SYSLISTVIEW32_1 TO hCtl
    'lets get the bounds of the first cell
                                ListView_getsubItemRect hCtl, 0, 0, %LVIR_BOUNDS, BYVAL VARPTR(R)
                            MSGBOX "r.right=  " + FORMAT$(r.right) + $CRLF + _
                                    "r.top=  " + FORMAT$(r.top) + $CRLF + _
                                    "r.bottom=  " + FORMAT$(r.bottom) + $CRLF + _
                                    "r.left=  " + FORMAT$(r.left),,"rect size"
    
    'Why is r.right returning 294?
    'the control is only 210 in width?
                        END IF
    
                END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Sample Code **
    '------------------------------------------------------------------------------
    FUNCTION SampleListView(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lColCnt _
        AS LONG, BYVAL lRowCnt AS LONG) AS LONG
        LOCAL lCol   AS LONG
        LOCAL lRow   AS LONG
        LOCAL hCtl   AS DWORD
        LOCAL tLVC   AS LV_COLUMN
        LOCAL tLVI   AS LV_ITEM
        LOCAL szBuf  AS ASCIIZ * 32
        LOCAL lStyle AS LONG
    
        CONTROL HANDLE hDlg, lID TO hCtl
    
        lStyle = ListView_GetExtendedListViewStyle(hCtl)
        ListView_SetExtendedListViewStyle(hCtl, lStyle OR %LVS_EX_FULLROWSELECT _
            OR %LVS_EX_GRIDLINES)
    
        ' Load column headers.
        tLVC.mask    = %LVCF_FMT OR %LVCF_TEXT OR %LVCF_SUBITEM
        tLVC.fmt     = %LVCFMT_LEFT
        tLVC.pszText = VARPTR(szBuf)
        FOR lCol = 0 TO lColCnt - 1
            szBuf       = USING$("Column #", lCol)
            tLVC.iOrder = lCol
            ListView_InsertColumn(hCtl, lCol, tLVC)
        NEXT lCol
    
        ' Load sample data.
        FOR lRow = 0 TO lRowCnt - 1
            tLVI.stateMask = %LVIS_FOCUSED
            tLVI.pszText   = VARPTR(szBuf)
            tLVI.iItem     = lRow
            FOR lCol = 0 TO lColCnt - 1
                szBuf         = USING$("Column # Row #", lCol, lRow)
                tLVI.iSubItem = lCol
                tLVI.lParam   = lRow
                IF lCol = 0 THEN
                    tLVI.mask = %LVIF_TEXT OR %LVIF_PARAM OR %LVIF_STATE
                    ListView_InsertItem(hCtl, tLVI)
                ELSE
                    tLVI.mask = %LVIF_TEXT
                    ListView_SetItem(hCtl, tLVI)
                END IF
            NEXT lCol
        NEXT lRow
    
        ' Auto size columns.
        FOR lCol = 0 TO lColCnt - 2
            ListView_SetColumnWidth(hCtl, lCol, %LVSCW_AUTOSIZE)
        NEXT lCol
        ListView_SetColumnWidth(hCtl, lColCnt - 1, %LVSCW_AUTOSIZE_USEHEADER)
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Dialogs **
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
    
    #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
        LOCAL hDlg  AS DWORD
    
        DIALOG NEW hParent, "Dialog1", 232, 186, 343, 249, TO hDlg
        CONTROL ADD "SysListView32", hDlg, %IDC_SYSLISTVIEW32_1, _
            "SysListView32_1", 40, 25, 210, 135, %WS_CHILD OR %WS_VISIBLE OR _
            %WS_TABSTOP OR %LVS_REPORT OR %LVS_SHOWSELALWAYS, %WS_EX_LEFT OR _
            %WS_EX_CLIENTEDGE OR %WS_EX_RIGHTSCROLLBAR
        CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Button1", 130, 175, 90, 25
    #PBFORMS END DIALOG
    
        SampleListView hDlg, %IDC_SYSLISTVIEW32_1, 3, 30
    
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
    
    #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
    #PBFORMS END CLEANUP
    
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------
    Now, obviously there are work-arounds. Since this is the first column, it would be pretty accurate to get the column width and use that for the r.right size. However, I would really like to know what I am doing wrong. Any thoughts or words of wisdom are appreciated.

    Thanks/Danke/Gracias/Merci/Spasiba etc
    Bill Scharf

  • #2
    That rect is returned in PIXELS, which may make it "seem" larger than the whole control if you are currently working in dialog units.

    MCM
    Michael Mattias
    Tal Systems Inc.
    Racine WI USA
    mmattias@talsystems.com
    http://www.talsystems.com

    Comment


    • #3
      good point, but...

      MM,

      Thank you for such a quick response. This is a great point, but it does not explain the odd results. For example, the results for the first column are huge compared to the second column:
      first column
      r.right = 294
      r.left = 0
      therefore width= about 294
      second column
      r.right = 188
      r.left = 92
      therefore width = about 96
      third column
      r.right = 294 (yes, the same as the first column?)
      r.left=188
      therefore width = about 106

      I know we cannot always make sense of everything, but I am trying to understand what is going on here and why this result is 294 instead of around 92 (the left coordinate of the the second column). Again, any thoughts are appreciated.
      Bill Scharf

      Comment


      • #4
        Run it again, but take out the autosize stuff. When you get all columns the size at which they were created, you'll know the problem is in your use of that stuff and you can go forward from there. At least that's where I think any problems are.
        Michael Mattias
        Tal Systems Inc.
        Racine WI USA
        mmattias@talsystems.com
        http://www.talsystems.com

        Comment


        • #5
          Hi Bill,
          In this example, the values seems to be correct ... something to compare your own code against.
          Code:
          'Compilable Example:
           #Compile Exe
           #Dim All
           #Include "win32api.inc"
           #Include "commctrl.inc"
           Global hDlg,hListView As Dword    'main dialog handle
           Function PBMain() As Long
              Dialog New Pixels, 0, "ListView Test",300,300,245,95,%WS_SysMenu, 0 To hDlg
              Control Add Button, hDlg, 200, "Push", 170,10,50,25
              Control Add ListView, hDlg, 100, "", 0,0,150,75   '225
              Control Handle hDlg, 100 To hListView
          
              'columns               hdlg, id&, col, "test", width, format
              ListView Insert Column hDlg, 100, 1, "test1", 75, 0
              ListView Insert Column hDlg, 100, 2, "test2", 75, 0
              'rows               hdlg, id&, row, image, "text"
              ListView Insert Item hDlg, 100, 1, 1, "one"  'row 1, col1
              ListView Insert Item hDlg, 100, 2, 2, "two"  'row 2, col1
              'items           hdlg, id&, row, col, "text"
              ListView Set Text hDlg, 100, 1,2, "12"    'row1 col2
              ListView Set Text hDlg, 100, 2,2, "22"    'row2 col2
              ListView Set Mode hDlg, 100, 1  '0-icon 1-report 2-small 3-list
          
              Dialog Show Modal hDlg Call DlgProc
           End Function
          
           CallBack Function DlgProc() As Long
              Local R As Rect
              If Cb.Msg = %WM_Command And Cb.Ctl = 200 Then
                  ListView_GetSubItemRect hListview, 0,0,%LVIR_Bounds, VarPtr(R)
                  ? Str$(R.nLeft) + Str$(R.nTop) + Str$(R.nRight) + Str$(R.nBottom)
              End If
           End Function
          Last edited by Gary Beene; 26 Aug 2011, 09:24 AM.

          Comment


          • #6
            Bill,
            This seems to work in your original code..
            Code:
                                        ListView_getsubItemRect hCtl, 0, 0, %LVIR_LABEL, BYVAL VARPTR(R)
            Rgds, Dave

            Comment


            • #7
              Gary,

              Did you put your ruler against your results?
              Rgds, Dave

              Comment


              • #8
                hmmm

                Thank you for your responses. This is VERY interesting. When I use Gary's example, I get a messagebox with "0 17 150 31" in it. That "150" should be "75" I believe. Gary's example (imo) shows the issue more concisely.

                Dave's response works (I think)--Using %LVIR_LABEL instead of %LVIR_BOUNDS seems to work.

                MS's reference at http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx seems to have thrown me off. Not only does it state that the subitem is 1-based, but it says, "LVIR_LABEL...This is identical to LVIR_BOUNDS." I thought about trying LVIR_LABEL, but I did not because it is supposed to be identical....hmmm.

                Many thanks to all of you for your help.
                Bill Scharf

                Comment


                • #9
                  >Did you put your ruler against your results

                  What, you called Gary for a quote instead of calling me?

                  I'm hurt.
                  Michael Mattias
                  Tal Systems Inc.
                  Racine WI USA
                  mmattias@talsystems.com
                  http://www.talsystems.com

                  Comment


                  • #10
                    The results show that LVIR_LABEL is not identical to LVIR_BOUNDS - at least not for SubItem 0 !
                    Code:
                    LVIR_BOUNDS                    LVIR_LABEL                    
                    ---------------------------    ---------------------------   
                    iSubItem    2                  iSubItem    2                 
                    ---------------------------    ---------------------------   
                    r.right=  294                  r.right=  294                 
                    r.top=     19                  r.top=     19                 
                    r.bottom=  33                  r.bottom=  33                 
                    r.left=   188                  r.Left =  188                 
                    ---------------------------    ---------------------------   
                    iSubItem    1                  iSubItem    1                 
                    ---------------------------    ---------------------------   
                    r.right=  188                  r.right=  188                 
                    r.top=     19                  r.top=     19                 
                    r.bottom=  33                  r.bottom=  33                 
                    r.left=    92                  r.left=    92                 
                    ---------------------------    ---------------------------   
                    iSubItem    0                  iSubItem    0                 
                    ---------------------------    ---------------------------   
                    r.right=  294                  r.right=   92                 
                    r.top=     19                  r.top=     19                 
                    r.bottom=  33                  r.bottom=  33                 
                    r.left=     0                  r.left=     2                 
                    ---------------------------    ---------------------------
                    Rgds, Dave

                    Comment


                    • #11
                      Code:
                       
                          Listview_GetSubItemRect LVRcdZ_aLvHWin(LvIndex), LvRowNo, LvColNo, %LVIR_BOUNDS, ByVal VarPtr(tRect)
                          If LvColNo=0 And LvColCount>1 Then
                              Listview_GetSubItemRect LVRcdZ_aLvHWin(LvIndex), LvRowNo, 1, %LVIR_BOUNDS, ByVal VarPtr(tRect2)
                              tRect.nRight = tRect2.nLeft-1
                          End If
                      this is old code, so ignore the code
                      but, the concept is;
                      getting the rect of the first col returns the whole item (all columns)
                      so, if the row has more than one column;
                      1. get the first column (return all columns)
                      2. get second column
                      3. subtract second column's left from the first column's right
                      I don't remember why, but I had a "-1" there - probably for the grid line
                      Last edited by Stanley Durham; 26 Aug 2011, 11:01 AM.
                      stanthemanstan~gmail
                      Dead Theory Walking
                      Range Trie Tree
                      HLib ~ Free Data Container Lib ~ Arrays, Lists, Stacks, Queues, Deques, Trees, Hashes

                      Comment


                      • #12
                        I found this code - old code - use with caution
                        Code:
                        Function LvColCount( ByVal hDlg As Long, ByVal Id As Long )  As Long
                            ' get col count
                            Local hHead&
                            hHead& = SendMessage(GetDlgItem(hDlg,Id),%LVM_GetHeader,0,0)
                            Function = SendMessage( hHead&, %hdm_GetItemCount, 0, 0 )
                        End Function
                        Sub LvCellRect( ByVal hDlg As Long, ByVal Id As Long, ByVal LvRowNo As Long, ByVal LvColNo As Long, tRect As RECT )
                            Local tRect2 As RECT
                            Local hWin, colCount As Long
                            'if column=0 and more than one column; then
                            '   need to get column 1 rect
                            '   column zero tRect.nRight = tRect2.nLeft-1
                            '   (column zero rect = whole item (whole row)
                            Control Handle hDlg, Id To hWin
                            colCount = LvColCount(hDlg, Id)
                            Listview_GetSubItemRect hWin, LvRowNo, LvColNo, %LVIR_BOUNDS, ByVal VarPtr(tRect)
                            If LvColNo=0 And colCount>1 Then
                                Listview_GetSubItemRect hWin, LvRowNo, 1, %LVIR_BOUNDS, ByVal VarPtr(tRect2)
                                tRect.nRight = tRect2.nLeft-1
                            End If
                        End Sub
                        stanthemanstan~gmail
                        Dead Theory Walking
                        Range Trie Tree
                        HLib ~ Free Data Container Lib ~ Arrays, Lists, Stacks, Queues, Deques, Trees, Hashes

                        Comment


                        • #13
                          Listview_GetSubItemRect
                          ...

                          iItem
                          Index of the subitem's parent item.
                          iSubItem
                          The one-based index of the subitem.
                          Source: SDK on disk ca. 2003

                          One based? Hmm, fooled me, too, until I RTFM.
                          Michael Mattias
                          Tal Systems Inc.
                          Racine WI USA
                          mmattias@talsystems.com
                          http://www.talsystems.com

                          Comment


                          • #14
                            Gosh, a guy takes a short nap and the world keeps on moving without him!

                            Dave,

                            No, just eyeballed it - apparently from too far away!

                            MCM,
                            What, you called Gary for a quote instead of calling me?
                            For more money, I'd have worn my eyeglasses!

                            Comment


                            • #15
                              Thanks to all

                              Thanks to all for your help on this issue. Stanley's solution is what I was using as a work-around. Dave's solution seems to give me the best results, so I am going with that for now. I appreciate both the knowledge and expertise of all of you guys.

                              I am sure we have all had days when a work-around temporarily covered up a larger problem. I wanted to make sure I did not have that larger problem. I can now rest better at night
                              Bill Scharf

                              Comment

                              Working...
                              X