Solved

Changing Node.Text property in TreeView control

Posted on 2004-09-20
15
4,301 Views
Last Modified: 2013-12-26
Hi, I have a treeview control (V6) with nodes that show chapters with paragraphs. A chapternumber is supplied with each node, i.e:

1. Chapter One
  1.1. Chapter One, Paragraph One
2. Chapter Two
  2.1. Chapter Two, Paragraph One
  2.2. Chapter Two, Paragraph Two

I have set the treeviews LabelEdit property to tvwAutomatic, so that the user can edit the titles.
The difficulty is that the user can now also edit the chapter number, which is not allowed.

I tried setting the SelectedItem.Text property to contain the title, stripped from its number in the BeforeLabelEdit-eventhandler, but found out that the treeview control fills an internal editbox with the entire text (ie 2.2. Chapter Two, Paragraph Two) prior to raising the BeforeLabelEdit-event. So, changing the node's text property won't help me...

Now, I'm this far that I got access to the internal edit control by using windows messages and changed the text in the editbox. Everything's working fine now: The user can edit only the title, save the pressing ENTER or ESC and the new title gets displayed again, supplied with its number...

The only thing is, and this finally brings me to the question:
The treeview places the internal edit control on top of the actual node. Since I stripped the number from the text in the edit control and not from the node's text property, the node's text property is longer than the edit control and therefore shows characters on the right side of the edit control.

Who knows of a way to either:
- Catch the escape-button pressed by the user in the edit control which ends the editing session and does not raise the AfterLabelEdit-event, so I could strip the number from the node's text property as well, and append the number again in case of an ESC.
- 'hide' this text on the right by enlarging the edit control, custom drawing, etc...

Thanks in advance,

Luc Derckx

ps: I don't think the code I used to send the messages is relevant here, but if you're interested I'll post it right here.
0
Comment
Question by:ThaCoyote
  • 4
  • 3
  • 3
  • +1
15 Comments
 
LVL 12

Accepted Solution

by:
fulscher earned 250 total points
ID: 12103602
Luc,

Instead of manipulating Treeview's internal windows, you could simulate the entire process by popping up your own edit control. You probably can also find the coordinates where it has to be appear. That's the solution I used some time ago. Advantage: Avoids major problems when a new version of the Treeview control comes out.

Another option - you could pop up a small form before the user edits the control. This form would consist of a text box and OK and Cancel buttons; the text box would be loaded with the chapter name but not number.

Jan

0
 
LVL 19

Expert Comment

by:arif_eqbal
ID: 12109179
There's another easier method of getting around the problem.

On BeforeLabelEdit event store the text in a variable
txt=TreeView1.SelectedItem.Text

Then on AfterLabelEdit check if the Text enetered contains the Chapter no and whether it is same as that stored in the variable earlier or not.

In case of wrong entry You can either ask the user to correct it or Automatically add the Chapter No. based on the stored value....

In case you want to automatically add the chapter no. on AfterLableEdit, you'll need to set Cancel=True and manually set the text of the node

TreeView1.SelectedItem.Text = txt & TreeView1.SelectedItem.Text

(assuming txt contains just the chapter no. so you need to extract chapter from the whole text we stored)
0
 

Author Comment

by:ThaCoyote
ID: 12109865
Hi, thanks for the replies...

======================================

arif_eqbal,
it's important to me that I don't provide the chapter no with the editable text, as that it might confuse users and is sensitive to errors. Your second recommendation works as long as the text actually gets changed (AfterLabelEdit gets raised), but fails if the user doesn't change the text or cancels by pressing escape. If there's a way I could just handle these cases, I'd indeed be able to reset the node's text; piece of cake...
I'd just do this:

Private ClickedNode As Node

Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)
   If Not ClickedNode Is Nothing Then
      If Node = ClickedNode Then
         TreeView1.SelectedItem.Text = Mid(TreeView1.SelectedItem.Text, Len(TreeView1.SelectedItem.Tag) + 3)
         TreeView1.StartLabelEdit
      Else
         Set ClickedNode = Node
      End If
   Else
      Set ClickedNode = Node
   End If
End Sub

Private Sub TreeView1_AfterLabelEdit(Cancel As Integer, NewString As String)
   Cancel = True
   TreeView1.SelectedItem.Text = TreeView1.SelectedItem.Tag & ": " & NewString
End Sub

Private Sub MyCancelEditHandler
   TreeView1.SelectedItem.Text = TreeView1.SelectedItem.Tag & ": " & _
      TreeView1.SelectedItem.Text
End Sub

======================================

fulscher,
I like your answer as it probably is solid and that it provides flexibility in design to add more features at wish. It's only that I'm affraid that this possible solution gives me too much work on modifying the current treeview's implementation. The flexibility it'd give me is great, but would also not be needed in this context; it will thrive beyond its goal...
The feeling I currently have that I'm very close to finding a solution makes me look for a light add in code to my current implementation, or an easy and small new implementation... If I'd just be able to easily get rid of the node's text on the right of the internal edit control...
This is the code I currently have...

Private Sub tvChapters_AfterLabelEdit(Cancel As Integer, NewString As String)
   'The node's tag always contains the ChapterNo
   NewString = tvChapters.SelectedItem.Tag & ": " & NewString
End Sub

Private Sub tvChapters_BeforeLabelEdit(Cancel As Integer)
   Dim ndeSel As MSComctlLib.Node 'The selected node to increase readability
   Dim EditBoxHWnd As Long
   
   Set ndeSel = tvChapters.SelectedItem
   If Not ndeSel Is Nothing Then
      'There's one problem: The treeview holds an internal edit control which is used...
      '...to edit the node's text.
      '...The contents of this edit control have ALREADY been set to the 'old' node's text, ...
      '...so any mutation we do to the node's text property will be of no use...
      '...So we should find a way to the internel edit control and modify it manually:

      'The first thing to do is to retrieve its handle (edit control)
      'SendMessage parameter reference for TVM_GETEDITCONTROL:
      'wParam: Must be zero
      'lParam: Must be zero
      EditBoxHWnd = SendMessage(tvHoofdstukken.hWnd, TVM_GETEDITCONTROL, CLng(0), CLng(0))
           
      'Now order the edit control to select the chapter no, using its handle
      'SendMessage parameter reference for EM_SETSEL:
      'wParam = start point of the selection (0 to n - 1)
      'lParam = end point of the selection (0 to n - 1)
      SendMessage EditBoxHWnd, EM_SETSEL, CLng(0), ByVal CLng(Len(ndeSel.Tag) + 2)
         
      'Now replace the chapter no with an empty string
      'SendMessage parameter reference for EM_REPLACESEL:
      'wParam = Boolean: Action Undoable?
      'lParam = String: Replacement string
      SendMessage EditBoxHWnd, EM_REPLACESEL, CLng(0), ByVal ""
      DoEvents
   Else
      Cancel = True
   End If
   Set ndeSel = Nothing
End Sub

======================================

Your replies gave me some new thinking:
- Is there a way to 'hook in' on the internal text control's notifications/events?
  This way I could possibly handle the cases where the editing gets cancelled
- If I could just have another SendMessage or something to enlarge the edit control horizontally...?
  This way the edit control will completely cover the annoying old node's text

Looking forward to hearing from you guys again,

Luc Derckx
0
 
LVL 12

Expert Comment

by:fulscher
ID: 12109950
Luc,

Try the SetWindowPos API function with the SWP_NOMOVE flag set. This allows you to resize the control.

HTH, Jan
0
 
LVL 12

Expert Comment

by:fulscher
ID: 12110066
Luc,

Have you thought about fetching the characters at the form level (KeyPreview = TRUE) and modifying the ESC code before it's sent to the TreeView? I'm not sure whether this works, but it might be worth a try: The VB form is the owner of the TreeView and therefore should see all characters before they are sent to the Treeview.

HTH, Jan
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:ThaCoyote
ID: 12113337
Fulscher,

I haven't yet tried the SetWindowPos API function (my day has come to an end :D), but tried the KeyPreview because it only took a minute to test it. Although it would only handle the escape-key and not other triggers that would end the editing session (clicking somewhere on the form for example), I still tried it because I was rather curious about how it would behave. I placed the code in Form_KeyDown and it worked:
If KeyCode = vbKeyEscape And Me.ActiveControl.Name = "tvChapters" Then KeyCode = 0

I'll fully explore this possible solution and try to catch the other triggers as well. I will return to this and share my findings with you in a few days, since I'm off to one of our customers for 2 days as of tomorrow.

Cheers!
0
 
LVL 5

Expert Comment

by:IThema
ID: 12873879
Hi,

Sorry peeps for forgetting this question!
I eventually ended up using API calls to the internal text box of the treeview. Here's the code I used:

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

Private Sub tvHoofdstukken_BeforeLabelEdit(Cancel As Integer)
   Dim ndeSel As MSComctlLib.Node 'The selected node to increase readability
   Dim EditBoxHWnd As Long
   
   Set ndeSel = tvHoofdstukken.SelectedItem
   If Not ndeSel Is Nothing Then
      If Left$(ndeSel.Key, 1) = "L" Then
         Cancel = True
      ElseIf ndeSel.Key <> "\" Then
         If DisplayChapterNr Then
            'Set up the node's text: The .Tag property contains the ChapterNr.
            'ndeSel.Text = Mid(ndeSel.Text, Len(ndeSel.Tag) + 3)
           
            'Now there's only one problem remaining:
            '...The treeview's internal text box used for editing holds the old contents!
            '...appearantly these contents are saved BEFORE the BeforeLabelEdit-event fires.
            '...Now we've changed the actual node's text, we should also change the internal
            '...edit box text!
            'Collect the handle of the treeview controls edit box
            'wParam & lParam: Must be zero
            EditBoxHWnd = SendMessage(tvHoofdstukken.hWnd, TVM_GETEDITCONTROL, CLng(0), CLng(0))
           
            'Select the text that represents the ChapterNr in that text box
            'wParam = start point of the selection (0 to count - 1)
            'lParam = end point of the selection (0 to count - 1)
            'Special: start = 0, end = -1 --> Select everything
            'Special: start = -1 --> Select nothing
            SendMessage EditBoxHWnd, EM_SETSEL, CLng(0), ByVal CLng(Len(ndeSel.Tag) + 2)
           
            'Send the new text string
            'wParam = Boolean: Action Undoable?
            'lParam = String: Replacement string
            SendMessage EditBoxHWnd, EM_REPLACESEL, CLng(0), ByVal ""
            DoEvents
         End If
      End If
   Else
      Cancel = True
   End If
   Set ndeSel = Nothing
End Sub


I still like the possible solution fulscher provided and fulscher sticked with me the whole time. Therefore I give him full credit.

Thanks guys for helping.
0
 

Author Comment

by:ThaCoyote
ID: 12873887
Oops, didn't realize I was logged in on my other user account :(
0
 
LVL 12

Expert Comment

by:fulscher
ID: 12874397
Thank you!
0
 
LVL 5

Expert Comment

by:IThema
ID: 12891495
Hi Modulo,

Please don't be so stern on me, IThema is my account used for corporate means, ThaCoyote is used for private means... I'd like to separate those. If you still don't allow this, then ThaCoyote should be the one to be removed. I'd also like to change the name of IThema to <removed by modulo for privacy reasons>, since IThema is my old employer. I don't like to be remembered to my old employer everytime I visit this place :D
If a corporate name as an alias is not allowed, then please remove ThaCoyote and rename IThema to ThaCoyote or TheCoyote or simply Coyote (preferred). (I don't think ThaCoyote will be allowed twice in database, although one will be blocked)

If you change my name, please send me an e-mail to my IThema-account, since I probably won't be able to log in anymore


Cheers,

Luc Derckx
0
 
LVL 5

Expert Comment

by:IThema
ID: 12891878
No, remove the thacoyote please!
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now