Results 1 to 14 of 14

Thread: [RESOLVED] border a single item on mousmove event in listview

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Mar 2005
    Posts
    2,586

    Resolved [RESOLVED] border a single item on mousmove event in listview

    border a single item on mousemove event in listview?

  2. #2
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,140

    Re: border a single item on mousmove event in listview

    No..

  3. #3
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: border a single item on mousmove event in listview

    Trying to ask the same question a different way? I recall you asking how to custom highlight a listview subitem.

    Actually drawing the border will likely require subclassing. It is possible to create a 'fake' border-control and position if over the listview subitems. Though I think that is not a great solution. The steps for that are briefly outlined here. APIs to use for cutting holes in forms: SetWindowRgn along with region-creating APIs

    - use a borderless form
    - cut a rectangular hole in the form leaving outside edges (2+ pixels) visible. This will be the border-control.
    - set that form's backcolor to the border color you want to use
    - as mouse moves over subitems or entire item if that's what you want then
    :: get coordinates of the subitem and its size & convert them to screen coordinates
    :: resize the border-control form to the subitem, adjusting for the border width/height
    :: make that form visible and move it so it's positioned over the listview
    - when the border-control form is no longer needed, either unload it or hide it

    I'll leave the above as an exercise for the curious
    Last edited by LaVolpe; Jul 28th, 2020 at 11:56 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  4. #4
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,714

    Re: border a single item on mousmove event in listview

    It's really not that hard to subclass and do custom colors. Here's an old demo by Brad Martinez:
    Name:  lvcd.jpg
Views: 1018
Size:  92.4 KB

    I'd recommend a newer subclassing method, e.g. the one in my sig, all you need to worry about is the response to the NM_CUSTOMDRAW message:
    Code:
            Case NM_CUSTOMDRAW
              Static iElement As Long
              
    'Debug.Print "&H" & Hex(lvcd.nmcd.dwDrawStage)
    
              Select Case lvcd.nmcd.dwDrawStage
              
                ' ====================================================
                Case CDDS_PREPAINT
                  ' Tell the listview we want CDDS_ITEMPREPAINT for each item
                  WndProc = CDRF_NOTIFYITEMDRAW
                  Exit Function
      
                ' ====================================================
                Case CDDS_ITEMPREPAINT
                  If g_fNewDraw Then
                    iElement = lvcd.nmcd.dwItemSpec And &HF
                  Else
                    iElement = ((lvcd.nmcd.dwItemSpec * 4) - 1) And &HF
                  End If
                  
                  Call SelectObject(lvcd.nmcd.hdc, g_IFonts(iElement).hFont)
                  lvcd.clrText = g_crl16(iElement)
                  lvcd.clrTextBk = g_crl16(15 - iElement)
                  MoveMemory ByVal lParam, lvcd, Len(lvcd)
                  ' Tell the listview we want (CDDS_ITEMPREPAINT Or CDDS_SUBITEM)
                  ' for each item's subitems, and that we changed the item's font.
                  WndProc = CDRF_NOTIFYSUBITEMDRAW Or CDRF_NEWFONT
                  Exit Function
      
                ' ====================================================
                Case (CDDS_ITEMPREPAINT Or CDDS_SUBITEM)
                  If g_fNewDraw Then
                    iElement = (lvcd.nmcd.dwItemSpec + (lvcd.iSubItem + 1)) And &HF
                  Else
                    iElement = (((lvcd.nmcd.dwItemSpec * 4) - 1) + (lvcd.iSubItem + 1)) And &HF
                  End If
    'Debug.Print iElement; g_IFonts(iElement).Name
                  
                  Call SelectObject(lvcd.nmcd.hdc, g_IFonts(iElement).hFont)
                  lvcd.clrText = g_crl16(iElement)
                  lvcd.clrTextBk = g_crl16(15 - iElement)
                  MoveMemory ByVal lParam, lvcd, Len(lvcd)
                  ' Tell the listview that we changed the subitem's font.
                  WndProc = CDRF_NEWFONT
                  Exit Function
                  
              End Select   ' lvcd.nmcd.dwDrawStage
              
    #End If   ' (WIN32_IE >= &H300)
          
          End Select   ' nmh.code
    The message will be fired when the item gets a mouseover... so you'd add a block to get the cursor get the cursor position and do a hittest:
    Code:
    Private Function ListView_HitTestEx(hwndLV As Long, pInfo As LVHITTESTINFO) As Long
    'HitTestEx is used if you need the iGroup and iSubItem members filled
      ListView_HitTestEx = SendMessage(hwndLV, LVM_HITTEST, -1, pInfo)
    End Function
    Then you check if it's on an item, If (pInfo.Flags And LVHT_ONITEM) Then, and then get the item number from pInfo.iItem.
    Attached Files Attached Files

  5. #5
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,714

    Re: border a single item on mousmove event in listview

    Actually here, I was bored.

    This project does highlighting both on click and on mouseover. On mouseover is a little flickery, I tried to minimize it by redrawing only the last and current item, so it's not that bad.

    Name:  lvcd2.jpg
Views: 1274
Size:  44.1 KB

    There's an option to change the text color too if you want.

    Just drawing a border is a whole other ballgame, since there's no built in way, you'd have to do something even more complicated than highlighting. But since you've been asking about highlighting, and this will at least show you how to identify the item, figured it would be useful.

    This uses the Common Controls 5.0 ListView, but I've confirmed it also works with the 6.0 control, and would of course work with an API control.

    Here's the key routines, as mentioned above, it's just a small block of code to respond to NM_CUSTOMDRAW:
    Code:
    Public Sub SetOnMouseMove(px As Long, py As Long)
    If gOnMO = True Then
        Dim nOld As Long
        nOld = gHighlight
        Dim LVHTI As LVHITTESTINFO
        LVHTI.pt.x = px
        LVHTI.pt.y = py
        SendMessage Form1.ListView1.hWnd, LVM_SUBITEMHITTEST, 0&, LVHTI
        If (LVHTI.Flags And LVHT_ONITEM) Then
            gHighlight = LVHTI.iItem
            gHighlightSub = LVHTI.iSubitem
        Else
            gHighlight = -1: gHighlightSub = -1
        End If
        If nOld <> -1 Then
            SendMessage Form1.ListView1.hWnd, LVM_REDRAWITEMS, nOld, ByVal nOld
        End If
        If gHighlight <> -1 Then
            SendMessage Form1.ListView1.hWnd, LVM_REDRAWITEMS, gHighlight, ByVal gHighlight
        End If
    End If
    End Sub
    
    Public Function LVWndProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
    Select Case uMsg
       Case WM_NOTIFY
            Dim tNMH As NMHDR
            CopyMemory tNMH, ByVal lParam, Len(tNMH)
            Select Case tNMH.Code
                Case NM_CLICK
                    If gOnMO = False Then
                        Dim LVHTI As LVHITTESTINFO
                        Dim nmia As NMITEMACTIVATE
                        CopyMemory nmia, ByVal lParam, LenB(nmia)
                        LVHTI.pt.x = nmia.PTAction.x
                        LVHTI.pt.y = nmia.PTAction.y
                        SendMessage Form1.ListView1.hWnd, LVM_SUBITEMHITTEST, 0&, LVHTI
                        If (LVHTI.Flags And LVHT_ONITEM) Then
                            gLastItem = gHighlight
                            gHighlight = LVHTI.iItem
                            gHighlightSub = nmia.iSubitem
                        Else
                            gHighlight = -1: gHighlightSub = -1
                        End If
                        RedrawList Form1.ListView1.hWnd
                    End If
                Case NM_CUSTOMDRAW
                    Dim nmcdr As NMLVCUSTOMDRAW
                    CopyMemory nmcdr, ByVal lParam, LenB(nmcdr)
                    Select Case nmcdr.nmcd.dwDrawStage
                        Case CDDS_PREPAINT
                            LVWndProc = CDRF_NOTIFYITEMDRAW
                            Exit Function
                        Case CDDS_ITEMPREPAINT
                            LVWndProc = CDRF_NOTIFYSUBITEMDRAW Or CDRF_NEWFONT
                            Exit Function
                        Case (CDDS_ITEMPREPAINT Or CDDS_SUBITEM)
                            If gHighlightSub > 0 Then
                                If (nmcdr.nmcd.dwItemSpec = gHighlight) And (nmcdr.iSubitem = gHighlightSub) Then
                                    If gSetBk Then nmcdr.clrTextBk = vbYellow
                                    If gSetTxt Then nmcdr.clrText = vbRed
                                Else
                                    If gSetBk Then nmcdr.clrTextBk = vbWhite
                                    If gSetTxt Then nmcdr.clrText = vbBlack
                                End If
                                CopyMemory ByVal lParam, nmcdr, LenB(nmcdr)
                                LVWndProc = CDRF_NEWFONT
                                Exit Function
                            End If
                    End Select
            End Select
                
       Case WM_DESTROY
         Call UnSubclass(hWnd, PtrLVWndProc)
    
    End Select
    LVWndProc = DefSubclassProc(hWnd, uMsg, wParam, lParam)
    
    End Function
    Attached Files Attached Files
    Last edited by fafalone; Jul 28th, 2020 at 08:21 PM. Reason: Cleaned up code in demo project a bit

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: border a single item on mousmove event in listview

    FYI to fafalone. The border is more tricky because you need to also trap the CDDS_ITEMPOSTPAINT event else any custom drawing during CDDS_ITEMPREPAINT will get erased.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7
    Hyperactive Member
    Join Date
    Mar 2017
    Posts
    500

    Re: border a single item on mousmove event in listview

    I'm playing around with the project from post #5 and I can move my border around the list view on the sub items but it is not exactly what I had in mind. What I don't know is how to capture the X and Y of the sub items that the mouse is over. I have my single line of code in this Sub
    Code:
    Public Sub SetOnMouseMove(px As Long, py As Long)
    If gOnMO = True Then
        Dim nOld As Long
        nOld = gHighlight
        Dim LVHTI As LVHITTESTINFO
        LVHTI.pt.x = px
        LVHTI.pt.y = py
        SendMessage Form1.ListView1.hWnd, LVM_SUBITEMHITTEST, 0&, LVHTI
        
        
        If (LVHTI.Flags And LVHT_ONITEM) Then
            gHighlight = LVHTI.iItem
            gHighlightSub = LVHTI.iSubitem
            Form1.UC_Border.Move px * 15, (py + 20) * 15
        Else
            gHighlight = -1: gHighlightSub = -1
        End If
        If nOld <> -1 Then
            SendMessage Form1.ListView1.hWnd, LVM_REDRAWITEMS, nOld, ByVal nOld
        End If
        If gHighlight <> -1 Then
            SendMessage Form1.ListView1.hWnd, LVM_REDRAWITEMS, gHighlight, ByVal gHighlight
        End If
    End If
    End Sub
    Also I don't know how to use CDDS_ITEMPOSTPAINT. I have it in the LVWndProc function like this but it is never entered so I know I'm not using it correctly and even if I did know I wouldn't know what code should be there

    Code:
      '
      '
    Public Function LVWndProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
    Select Case uMsg
       Case WM_NOTIFY
         Dim tNMH As NMHDR
         CopyMemory tNMH, ByVal lParam, Len(tNMH)
      
         Select Case tNMH.Code
           Case NM_CLICK
             If gOnMO = False Then
               Dim LVHTI As LVHITTESTINFO
               Dim nmia As NMITEMACTIVATE
               CopyMemory nmia, ByVal lParam, LenB(nmia)
               LVHTI.pt.x = nmia.PTAction.x
               LVHTI.pt.y = nmia.PTAction.y
               SendMessage Form1.ListView1.hWnd, LVM_SUBITEMHITTEST, 0&, LVHTI
     
               If (LVHTI.Flags And LVHT_ONITEM) Then
                 gLastItem = gHighlight
                 gHighlight = LVHTI.iItem
                 gHighlightSub = nmia.iSubitem
               Else
                 gHighlight = -1: gHighlightSub = -1
               End If
      
               RedrawList Form1.ListView1.hWnd
             End If
                    
           Case NM_CUSTOMDRAW
             Dim nmcdr As NMLVCUSTOMDRAW
             CopyMemory nmcdr, ByVal lParam, LenB(nmcdr)
       
             Select Case nmcdr.nmcd.dwDrawStage
               Case CDDS_ITEMPOSTPAINT       
                 '
                 '
                 '
                 Exit Function
                
              Case CDDS_PREPAINT
                LVWndProc = CDRF_NOTIFYITEMDRAW
                Exit Function
        
              Case CDDS_ITEMPREPAINT
                LVWndProc = CDRF_NOTIFYSUBITEMDRAW Or CDRF_NEWFONT
                Exit Function
                
              Case (CDDS_ITEMPREPAINT Or CDDS_SUBITEM)
                If gHighlightSub > 0 Then
                  If (nmcdr.nmcd.dwItemSpec = gHighlight) And (nmcdr.iSubitem = gHighlightSub) Then
                    If gSetBk Then nmcdr.clrTextBk = vbYellow
                    If gSetTxt Then nmcdr.clrText = vbRed
                  Else
                  
                  If gSetBk Then nmcdr.clrTextBk = vbWhite
                    If gSetTxt Then nmcdr.clrText = vbBlack
                  End If
         
                  CopyMemory ByVal lParam, nmcdr, LenB(nmcdr)
                  LVWndProc = CDRF_NEWFONT
                  Exit Function
                End If
              End Select
            End Select
                
       Case WM_DESTROY
         Call UnSubclass(hWnd, PtrLVWndProc)
    
    End Select
    
    LVWndProc = DefSubclassProc(hWnd, uMsg, wParam, lParam)
    
    End Function

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: border a single item on mousmove event in listview

    Quote Originally Posted by Ordinary Guy View Post
    Also I don't know how to use CDDS_ITEMPOSTPAINT. I have it in the LVWndProc function like this but it is never entered so I know I'm not using it correctly and even if I did know I wouldn't know what code should be there
    If you have further questions regarding handling custom drawing of the listview, you probably should start a new thread vs. unintentionally hijacking this thread for that purpose.

    To draw during post-paint, trap this among your Case statements
    Code:
    Const CDDS_POSTPAINT As Long = &H2
    Const CDDS_ITEM As Long = &H10000
    Const CDDS_ITEMPOSTPAINT As Long = (CDDS_ITEM Or CDDS_POSTPAINT)
    ...
    
    Case CDDS_ITEMPOSTPAINT
      -- use the nmcdr.nmcd members for drawing, i.e., the .Hdc & .Rc members
    Case (CDDS_ITEMPOSTPAINT Or CDDS_SUBITEM)
      -- use the nmcdr.nmcd members for drawing, i.e., the .Hdc & .Rc members
    To get the post-paint events/message, return CDRF_NOTIFYPOSTPAINT, for example using your code:
    Code:
        ...
              Case CDDS_ITEMPREPAINT
                LVWndProc = CDRF_NOTIFYSUBITEMDRAW Or CDRF_NEWFONT Or CDRF_NOTIFYPOSTPAINT
                Exit Function
                
              Case (CDDS_ITEMPREPAINT Or CDDS_SUBITEM)
                If gHighlightSub > 0 Then
                    ...
                   LVWndProc = CDRF_NEWFONT Or CDRF_NOTIFYPOSTPAINT
                  Exit Function
                End If
        ...
    edited: forgot a constant
    Const CDRF_NOTIFYPOSTPAINT As Long = &H10
    Last edited by LaVolpe; Jul 30th, 2020 at 07:51 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9
    Hyperactive Member
    Join Date
    Mar 2017
    Posts
    500

    Re: border a single item on mousmove event in listview

    I got that nmcdr.nmcd.rc member and use it as nmcdr.nmcd.rc.Left and nmcdr.nmcd.rc.Top. Now the .Left comes very close to the left edge of the column but the .Top is like really wierd. .Top gives really large numbers like 1392577417 and 6106344 which are totally out of range so here I am completely baffeled

  10. #10
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    603

    Re: border a single item on mousmove event in listview

    Quote Originally Posted by fafalone View Post

    Name:  lvcd2.jpg
Views: 1274
Size:  44.1 KB
    It is harder to draw highlight background in text region only. I ever give up.

  11. #11
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: border a single item on mousmove event in listview

    Quote Originally Posted by DaveDavis View Post
    It is harder to draw highlight background in text region only. I ever give up.
    It's a bit more work but completely doable with subclassing. Here is an example, notice that I gave a 'raised' appearance to the gold highlighted subitem. The problem really is that you have so very little room to draw a border before you start to overdraw onto the item text.



    Edited: If really wanting a border on a mouse move event, don't think I'd go the route taken in my sample image. That's a lot of listview redrawing and potential flicker to draw within a subitem. A smarter option may be to overlay a movable window onto the listivew or getting the listview hDC (GetDC, GetWindowDC APIs) and drawing an XOR (rubberband-like) border. In my sample, in actual code, the border and gold highlighting are applied on clicks and keyboard navigation, not mouse movements.
    Last edited by LaVolpe; Aug 1st, 2020 at 11:35 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  12. #12

    Thread Starter
    PowerPoster
    Join Date
    Mar 2005
    Posts
    2,586

    Re: border a single item on mousmove event in listview

    My last work, attached .
    Have difficult to show a rectangle in item out the raw 10...
    If i select a item, for example on raw 11, the rectangle appear out the listview.
    Attached Files Attached Files

  13. #13
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    679

    Re: border a single item on mousmove event in listview

    Quote Originally Posted by luca90 View Post
    My last work, attached .
    Have difficult to show a rectangle in item out the raw 10...
    If i select a item, for example on raw 11, the rectangle appear out the listview.
    Code:
    Dim itmTmp As ListItem
         
        Set itmTmp = ListView1.GetFirstVisible
         
        
        picMover1.Height = ALTEZZA
        picMover1.Width = LARGHEZZA
        picMover1.Left = SINISTRA + 30
        picMover1.Top = SOTTO + 40 - (itmTmp.Index - 1) * ITMX.Height

  14. #14

    Thread Starter
    PowerPoster
    Join Date
    Mar 2005
    Posts
    2,586

    Re: border a single item on mousmove event in listview

    Quote Originally Posted by xxdoc123 View Post
    Code:
    Dim itmTmp As ListItem
         
        Set itmTmp = ListView1.GetFirstVisible
         
        
        picMover1.Height = ALTEZZA
        picMover1.Width = LARGHEZZA
        picMover1.Left = SINISTRA + 30
        picMover1.Top = SOTTO + 40 - (itmTmp.Index - 1) * ITMX.Height
    wow!
    Tks bro, excellent code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width