Co ordinate of a node in a treeview control 
Author Message
 Co ordinate of a node in a treeview control

Hi all,
I am using treeview control in Access 97. How do I find out a node for a
given x,y co ordinate? Please help me out.

Thanks

Best regards,
Karunakaran N



Mon, 03 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
Hello,

Quote:
> I am using treeview control in Access 97. How do I find out a node for a
> given x,y co ordinate? Please help me out.

Use the treeview's HitTest method:

Dim n As Node
Set n = TreeView1.HitTest(x, y)

--
Ben Baird, Microsoft MVP
Visual Basic Thunder
http://www.vbthunder.com
Please keep your programming questions on the newsgroups.



Mon, 03 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control



Quote:
> > I am using treeview control in Access 97. How do I find out a node for a
> > given x,y co ordinate? Please help me out.

> Use the treeview's HitTest method:

> Dim n As Node
> Set n = TreeView1.HitTest(x, y)

Ben, is there a reverse? If you have a node, can you get its x,y
coordinates, at least relative to the treeview itself?


Mon, 03 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
Jeff...

Quote:
> > Dim n As Node
> > Set n = TreeView1.HitTest(x, y)

> Ben, is there a reverse? If you have a node, can you get its x,y
> coordinates, at least relative to the treeview itself?

An intrinsic way? Yes. You can send a TVM_GETITEMRECT to the TreeView
window. I'm not sure if this will do anything in the VB6 OCX because it is
no longer based on Comctl32.dll, but it will definitely work for the VB5
version. For list of TreeView API constants all packaged into a VB BAS
module, check out:

VB Translation of CommCtrl.h
... in the Win32 Reference section of my Web site.

Also, you'll need to know how to get a TreeView's hItem from a Node object,
which you can do with a demo which was written by Brad Martinez. Check it
out, it's the first downloadable example at:
http://www.mvps.org/btmtz/treeview/

--
Ben Baird, Microsoft MVP
Visual Basic Thunder
http://www.vbthunder.com
Please keep your programming questions on the newsgroups.



Mon, 03 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control

Quote:
> Ben, is there a reverse? If you have a node, can you get its x,y
> coordinates, at least relative to the treeview itself?

I just too haven't tried whether the API way would work, but in pure VB this
seems to be a solution:

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long,
lpRect As RECT) As Long

Private Function GetNodeRect( _
 tvw As TreeView, _
 ThisNode As Node, _
 RetLeft As Single, _
 RetTop As Single, _
 RetRight As Single, _
 RetBottom As Single _
 ) As Boolean

  Dim nRect As RECT
  Dim nItemHeight As Integer
  Dim nLines As Integer
  Dim nLine As Integer
  Dim nCol As Integer
  Dim nIndent As Integer
  Dim nHeight As Single
  Dim nSTPPX As Integer
  Dim nSTPPY As Integer
  Dim nFoundNode As Node
  Dim nIndentation As Integer
  Dim nScaleMode As Integer

  With tvw
    If ThisNode.Visible Then
      ' for least speed improvement:
      nSTPPX = Screen.TwipsPerPixelX
      nSTPPY = Screen.TwipsPerPixelY

      GetClientRect .hwnd, nRect
      nItemHeight = (nRect.Bottom \ .GetVisibleCount) * nSTPPY
      With nRect
        .Right = .Right * nSTPPX
      End With

      ' evaluate only max count of nodes if less than possible:
      If .GetVisibleCount > .Nodes.Count Then
        nLines = .Nodes.Count
      Else
        nLines = .GetVisibleCount
      End If
      ' try to get the container's ScaleMode,
      ' because .Indentation depends on it (bug??):
      On Error Resume Next
      nScaleMode = .Container.ScaleMode
      If Err.Number Then
        ' always default - vbTwips
        nIndentation = CInt(.Indentation) * nSTPPX
      Else
        nIndentation = .Parent.ScaleX(CInt(.Indentation), nScaleMode,
vbTwips)
      End If
      On Error GoTo 0
      ' vertical steps middle of a line's height:
      For nLine = nItemHeight \ 2 To nLines * nItemHeight Step nItemHeight
        ' horizontal steps with indentation width:
        For nIndent = nSTPPX To nRect.Right Step nIndentation
          Set nFoundNode = .HitTest(nIndent, nLine)
          If nFoundNode Is Nothing Then
            ' do nothing
          ElseIf nFoundNode Is ThisNode Then
            ' node begins here:
            RetLeft = nIndent
            ' now scan line pixel by pixel:
            For nCol = nIndent To nRect.Right Step nSTPPX
              Set nFoundNode = .HitTest(nCol, nLine)
              If nFoundNode Is Nothing Then
                ' behind the node:
                RetRight = nCol - nSTPPX
                nHeight = nItemHeight
                RetTop = nLine - (nHeight \ 2)
                RetBottom = RetTop + nHeight
                GetNodeRect = True

                ' ****** got it!
                '   indicates succes:
                GetNodeRect = True
                Exit Function
                ' ******
              End If
            Next 'nCol
          Else
            ' any other node found
            Exit For
          End If
        Next 'nIndent
      Next 'nLine
    End If
  End With
End Function

The first point is that the visible property of a node is only true if this
node is really visible, because it is inside the TreeViews's client rect and
it's parent node is not collapsed. For an invisble node it would not make
sense to evaluate the coordinates.

The second point is that GetVisibleCount is always valid, even if there is
no node in the nodes collection.

It should be exact for +/- one pixel. And it is not as slow as I did fear
first...

Regards,

Harald M. Genauck

ABOUT Visual Basic - das Webmagazin
http://www.aboutvb.de



Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
... Some improvements for the GetNodeRect function from the previos posting,
for the cases that the treeview is scrolled vertically or horizontally
and/or a node is visible only partial...

Public Function GetNodeRect(tvw As TreeView, ThisNode As Node, RetLeft As
Single, RetTop As Single, RetRight As Single, RetBottom As Single) As
Boolean
    Dim nRect As RECT
    Dim nItemHeight As Integer
    Dim nLines As Integer
    Dim nLine As Integer
    Dim nCol As Integer
    Dim nIndent As Integer
    Dim nSTPPX As Integer
    Dim nSTPPY As Integer
    Dim nFoundNode As Node
    Dim nIndentation As Integer
    Dim nScaleMode As Integer
    Dim nLastIndentStep As Integer
    Dim nInNode As Boolean

    With tvw
        If ThisNode.Visible Then
            nSTPPX = Screen.TwipsPerPixelX
            nSTPPY = Screen.TwipsPerPixelY
            GetClientRect .hwnd, nRect
            nItemHeight = (nRect.Bottom \ .GetVisibleCount) * nSTPPY
            With nRect
                .Right = .Right * nSTPPX
            End With
            If .GetVisibleCount > .Nodes.Count Then
                nLines = .Nodes.Count
            Else
                nLines = .GetVisibleCount
            End If
            On Error Resume Next
            nScaleMode = .Container.ScaleMode
            If Err.Number Then
                nIndentation = CInt(.Indentation) * nSTPPX
            Else
                nIndentation = .Parent.ScaleX(CInt(.Indentation),
nScaleMode, vbTwips)
            End If
            On Error GoTo 0
            For nLine = 0 To nLines * nItemHeight Step nItemHeight
                For nIndent = 0 To nRect.Right Step nIndentation
                    Set nFoundNode = .HitTest(nIndent, nLine)
                    If nFoundNode Is Nothing Then
                    ElseIf nFoundNode Is ThisNode Then
                        RetTop = nLine
                        RetBottom = RetTop + nItemHeight
                        For nCol = nIndent To 0 Step -nSTPPX
                            Set nFoundNode = .HitTest(nCol, nLine)
                            If nFoundNode Is Nothing Then
                                RetLeft = nCol
                                Exit For
                            End If
                        Next 'nCol
                        For nCol = nIndent To nRect.Right Step nSTPPX
                            Set nFoundNode = .HitTest(nCol, nLine)
                            If nFoundNode Is Nothing Then
                                RetRight = nCol - nSTPPX
                                GetNodeRect = True
                                Exit Function
                            End If
                        Next 'nCol
                        RetRight = nRect.Right
                        GetNodeRect = True
                        Exit Function
                    Else
                        Exit For
                    End If
                    nLastIndentStep = nIndent
                Next 'nIndent
                For nCol = nRect.Right To nLastIndentStep Step -nSTPPX
                    Set nFoundNode = .HitTest(nCol, nLine)
                    If nFoundNode Is Nothing Then
                        If nInNode Then
                            RetLeft = nCol
                            RetTop = nLine
                            RetBottom = RetTop + nItemHeight
                            RetRight = nRect.Right
                            GetNodeRect = True
                            Exit Function
                        End If
                    ElseIf nFoundNode Is ThisNode Then
                        nInNode = True
                    Else
                        Exit For
                    End If
                Next 'nCol
            Next 'nLine
        End If
    End With
End Function

Regards,

Harald M. Genauck

ABOUT Visual Basic - das Webmagazin
http://www.aboutvb.de



Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control



Quote:
> > Ben, is there a reverse? If you have a node, can you get its x,y
> > coordinates, at least relative to the treeview itself?
> An intrinsic way? Yes. You can send a TVM_GETITEMRECT to the TreeView
> window.

Don't mean to second guess you, but are you SURE this will do the trick? I
got the impression from the MSDN documentation that you would get a RECT
that simply described the dimensions of the node. In other words, Left and
Top would be 0,0 instead of relative to the TreeView. Am I wrong?


Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
Harald...

Wow, that's a bit of code you've got there... <g> Yep, for a non-API method
it should work pretty well.

--
Ben Baird, Microsoft MVP
Visual Basic Thunder
http://www.vbthunder.com
Please keep your programming questions on the newsgroups.



Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
Jeff...

Quote:
> > An intrinsic way? Yes. You can send a TVM_GETITEMRECT to the TreeView
> > window.

> Don't mean to second guess you, but are you SURE this will do the trick? I
> got the impression from the MSDN documentation that you would get a RECT
> that simply described the dimensions of the node. In other words, Left and
> Top would be 0,0 instead of relative to the TreeView. Am I wrong?

Well, you could have tried it to find out... <g>

Yes, you are wrong. Directly from the MSDN documentation:

"Address of a RECT structure that, when sending the message, contains the
handle of the item to retrieve the rectangle for. See the example below for
more information on how to place the item handle in this parameter. After
returning from the message, this parameter contains the bounding rectangle.
The coordinates are relative to the upper-left corner of the tree view
control."

The Top and Left members will contain the x,y coordinates of the item's
origin.

--
Ben Baird, Microsoft MVP
Visual Basic Thunder
http://www.vbthunder.com
Please keep your programming questions on the newsgroups.



Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control



Quote:
> Yes, you are wrong. Directly from the MSDN documentation:

> "Address of a RECT structure that, when sending the message, contains the
> handle of the item to retrieve the rectangle for. See the example below
for
> more information on how to place the item handle in this parameter. After
> returning from the message, this parameter contains the bounding
rectangle.
> The coordinates are relative to the upper-left corner of the tree view
> control."

Sunuvabich. I asked because a similar question came up once where a poster
wanted to place a popup menu over a node when the user invoked it via the
keyboard, but he didn't know how to get the coordinates of the node. I
looked through a bunch of messages, including this one, and I swear I never
saw that last part. Thanks!


Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
Jeff, Ben,

it works, with both COMCTL32.OCX and MSCOMCTL.OCX. You'll retrieve the
coordinates of the rectangle for the actual selected node:

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Private Declare Function SendMessage Lib "user32" _
 Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
 wParam As Any, lParam As Any) As Long

Private Const TV_FIRST = &H1100
Private Const TVM_GETNEXTITEM = (TV_FIRST + 10)
Private Const TVM_GETITEMRECT = (TV_FIRST + 4)
Private Const TVGN_CARET = &H9

Public Function GetTvwNodeRect(Tvw As TreeView, _
 RetLeft As Single, RetTop As Single, _
 RetRight As Single, RetBottom As Single) As Boolean

  Dim nRect As RECT

  With Tvw
    nRect.Left = SendMessage(.hwnd, TVM_GETNEXTITEM, _
     ByVal TVGN_CARET, 0)
    If nRect.Left Then
      SendMessage .hwnd, TVM_GETITEMRECT, 1, nRect
      GetTvwNodeRect = True
      With nRect
        RetLeft = .Left
        RetTop = .Top
        RetRight = .Right
        RetBottom = .Bottom
      End With
    End If
  End With
End Function

Another question would be, how to retrieve the rect of an arbitrary node,
not just for the selected one. Brad's code seems to deliver all you need,
but it seems a bit of work (resulting in a heavy overhead) to retrieve the
item handle of a node from a arbitrary node reference. My former VB code
solution works with any node, but, of course, has a little performance
problem...

But, one point of the MSDN documentation seems not to be really exact:

Quote:
> The coordinates are relative to the upper-left corner of the tree view
> control.

The coordinates are relative to the client rect, not to the whole control's
rect. The difference is caused by the borderstyle and appearance settings.
If you want the coordinates relative to the control's rect, they have to be
mapped via ClientToScreen, reduced by the results of a call of GetWindowRect
etc...

Regards,

Harald M. Genauck

ABOUT Visual Basic - das Webmagazin
http://www.aboutvb.de



Tue, 04 Jun 2002 03:00:00 GMT  
 Co ordinate of a node in a treeview control
Harald...

Quote:
> it works, with both COMCTL32.OCX and MSCOMCTL.OCX.

Yeah, I'd heard that the VB6 controls still respond to some of the comctl
messages but I didn't want to say without knowing for sure... thanks.

-
Ben Baird, Microsoft MVP
Visual Basic Thunder
http://www.vbthunder.com
Please keep your programming questions on the newsgroups.



Tue, 04 Jun 2002 03:00:00 GMT  
 
 [ 12 post ] 

 Relevant Pages 

1. print box with co ordinate control

2. Line Co-ordinates

3. EXCEL 2000 : Selection Co-ordinates

4. Obtaining x,y co-ordinates of a Dropped Object

5. MDI co-ordinates, docking form and more

6. Forcing mouse pointer to move to a co-ordinate

7. Finding mouse co-ordinates

8. Co-ordinates

9. how do i use mouse co-ordinates

10. mouse co-ordinates...

11. Mouse Co-ordinates

12. Getting point co-ordinates from cad tablet/digitizer in VB application

 

 
Powered by phpBB® Forum Software