0

I am using delphi xe

I want to change text of treeview node at runtime which has been circled in screen shot. enter image description here

I am using the code below to change it

TreeView1.Items[2].Item[6].Text:='Some Text';

But getting the error below

List index out of bound(6)

However the same code works if I change the text of any subitem of first item such as

TreeView1.Items[0].Item[1].Text:='Some Text';

Screen Shot

bummi
  • 27,123
  • 14
  • 62
  • 101
Khawar
  • 33
  • 1
  • 6
  • 1
    Maybe there is a hidden item. What are `TreeView1.Items.Count` and `TreeView1.Items[2].Text`? – nullptr Jun 08 '13 at 18:49
  • Clearly you are using an out of bounds index. Which one is it? – David Heffernan Jun 08 '13 at 19:01
  • 3
    Your basic problem is that `TreeView1.Items[]` accesses a flattened view of the nodes. Items[0] is Pay History, Items[1] is Specific Account History and so on. Once you understand that you'll be able to solve the problem. You could have worked this out with some debugging. That's the skill that you need to learn next. – David Heffernan Jun 08 '13 at 21:40
  • @DavidHeffernan maybe you should add this as answer, because it covers a widespread misunderstanding. – bummi Jun 09 '13 at 08:03
  • 1
    @bummi I have done so – David Heffernan Jun 09 '13 at 15:28

2 Answers2

6

Divide and conquer. You should determine where exactly the error happens, which EXECUTION STEP caused it.

Introduce a number of temporary variables of proper types and split long problematic line into a sequence of simplistic lines.

Instead of TreeView1.Items[2].Item[6].Text:='Some Text'; do something like that:

var tmp_is: TTreeNodes;
var tmp_iN, tmp_iNN: TTreeNode;

tmp_is := TreeView1.Items;

ShowMessage(IntToStr(tmp_is.Count));
tmp_iN := tmp_is[2];

ShowMessage(tmp_iN.Text + ' : ' + IntToStr(tmp_iN.Count));
tmp_iNN := tmp_iN[6];

ShowMessage(tmp_iNN.Text);
tmp_iNN.Text := 'Some Text';

Then trace it and see which line gives you an error and how many elements that node actually had and upon which elements you are actually going to operate.

Arioch 'The
  • 15,799
  • 35
  • 62
  • I fail to see how that explains anything to the OP. – Peter Jun 08 '13 at 19:43
  • 3
    @PeterVonča that gives him a generic approach how to match his idea what should happen and the actual process being happening. If you can, you can coach him in some better way, i did what i could. – Arioch 'The Jun 08 '13 at 19:59
  • @Arioch'The, I'm not saying that your approach is wrong, just IMO this whole debugging seems a bit redundant and on the end might not even give him enough information on why this is happening, but I regress. – Peter Jun 08 '13 at 20:09
  • 2
    @PeterVonča Clearly the asker has no idea how to debug. And Arioch is giving the sound advice of breaking the problem into small pieces to identify the location of the failure. – David Heffernan Jun 08 '13 at 20:35
  • There are no hidden items in treeview – Khawar Jun 09 '13 at 06:59
  • I performed some further testing on code. When i do this TreeView1.Items[0].Item[1].Text:='Some Thing'; and this TreeView1.Items[0].Item[1].Text:='Some Thing'; It is renaming the same node i-e 2nd sub item of item 1 – Khawar Jun 09 '13 at 07:15
  • Divide and conquer I tested your code. First message box shows 16 it means that count is 16 items which are all visible. Second shows Detail : 0. Then this line " tmp_iNN := tmp_iNN[6] " gives access violation – Khawar Jun 09 '13 at 07:22
  • `When i do this`....`and this` ... - you just shown two identical lines of code. Sure the same code does the same thing. you should have meant something different. /// The line is an obvious typo, you should use the variables you had bound right above. in this case after `tmp_iN := ...` you have to use `tmp_iNN := tmp_iN[6];` obviously. OTOH there is no point in this, the debug output shows that `TreeView1.Items[2]` is "Detail" node, not "Other Info" node. And that "Detail" node does not have children. you should do like `TreeView1.Items[14].Text:='Some Text';` given this debug output. – Arioch 'The Jun 09 '13 at 07:36
  • Sorry it was When i do this TreeView1.Items[0].Item[1].Text:='Some Thing'; and this TreeView1.Items[2].Text:='Some Thing'; – Khawar Jun 09 '13 at 07:42
  • Just a generic advice, try VirtualTreeView component. It might seem somewhat more complex, but it is faster and more flexible. – Arioch 'The Jun 09 '13 at 07:46
  • I tested your suggestion and used TreeView1.Items[13].Text:='Some Text'; and it just changed the text of desired item. But can I cant understand that it is an subitem of item 2 apparently then why in code it behaves like a seperate item and not a sub item of item[2] – Khawar Jun 09 '13 at 07:58
  • they all are sub-items of their owner: treeview control and it's internal collection (`.Items:TTreeNodes`). Notice different datatypes of `tmp_is` and `tmp_iN{N}`. See also http://docwiki.embarcadero.com/Libraries/XE2/en/Vcl.ComCtrls.TTreeNodes.AddChild - you call Add upon the collection, but specifying another node to prune the new one under. Those are just different hierarchies: owning and displaying – Arioch 'The Jun 09 '13 at 08:01
  • http://docwiki.embarcadero.com/RADStudio/XE2/en/Tree_Views : `The items you add become the value of the Items property.` - all items, not only the top-level ones. http://docwiki.embarcadero.com/Libraries/XE4/en/Vcl.ComCtrls.TTreeView `Each node can have a list of subnodes associated with it` - associated, not owned. It would be more uniform if TV had some virtual invisible root pseudo-element to associate with top-level ones. but perhaps that is not what Windows provides for. Again, try to learn VTV – Arioch 'The Jun 09 '13 at 08:09
  • @Arioch'The, it's funny how it took you through several comments to say what I wrote in my answer in the first place but apparently the goal of StackOverflow has now become to not provide solutions that explain the problem but solutions that vaguely describe how to debug the issue, even if the OP won't understand it, and then through comments hours after, come to the actual conclusion. But hey aslong that David gives it a +1 we can all be assured that it's the right answer. – Peter Jun 09 '13 at 08:15
  • 1
    @PeterVonča if you are sure in your answer - then don't delete it. I see your jealousy, but am i the right person to be addressed with it? What is the "solution" is a very disputable question on its own. If to avoid "vague description of how to debug/program/etc" as a primary criterion, then all topics should degenerate into "this is my code, fix it for me".Surely, all the things discussed are basic for any programmer and topic starter should have "gut feeling" for them or should have learned them from school and form google, but again i am not the one to be blamed for that. – Arioch 'The Jun 09 '13 at 08:21
  • @Khawar see also http://docwiki.embarcadero.com/Libraries/XE4/en/Vcl.ComCtrls.TTreeNode.AbsoluteIndex - perhaps remember it somewhere when you are populating the treeview with nodes and then use later – Arioch 'The Jun 09 '13 at 08:22
  • @PeterVonča i had strong disagreements with David and with Arnaud and with many "top posters" here. And they gave me minuses, and so on. So what ? If David is David you no more can find courage to be in disagreement and keep your own answer public? No, really. David and some other 5 guys gave me pluses here. So what? Who cares? Yes, David says this, David says that... Who cares if you really do have a say? And if you don't then don't you please make a fuss. – Arioch 'The Jun 09 '13 at 08:33
  • @Peter There's no need for all that nonsense. I can upvote answers if I like. Please don't get upset if, for once, it's not your answer I upvote. Your answer here, in any case, does not make the key issue clear. My comment to the question does. – David Heffernan Jun 09 '13 at 08:34
  • @Arioch'The, I'm not jealous, I'm disappointed. I predicted that the OP would probably just get confussed by your debugging example. If the question would be : " How do I debug this?" then I would agree with you completely and give a +1, but that's not the case here. And just to be clear this is nothing personal, I don't get emotionally invested in SO, I'm just disappointed to see how easy it is for certain members like David to quickly influence the way that "the default voting public" votes and reades answers. – Peter Jun 09 '13 at 08:35
  • @DavidHeffernan, how does it not make the key issue clear? Key issue is that Items property looks at ALL the items on the TreeView, including any subItems. I posted that, received no up votes and then later on I see you posting the same thing in comments. – Peter Jun 09 '13 at 08:36
  • @Peter Plenty of people disagree with me lots of the time too. We all disagree with each other and argue. That's how it should be. Healthy critical analysis. – David Heffernan Jun 09 '13 at 08:37
  • @Peter The wording doesn't say it clearly enough. I did not know what you meant when I read your answer. If your answer had been good it would have got upvotes. The problem with it is not that the voters were influenced by me. – David Heffernan Jun 09 '13 at 08:38
  • @DavidHeffernan, I don't dispute that, I think it's healthy, but I explained the key issue here, you can see my deleted answer. And yet no votes were given because probably nobody cared for reading it after you gave that comment "+1 for explaining how to solve the problem" to this answer. Just saying :) – Peter Jun 09 '13 at 08:38
  • @PeterVonča totally here been 6 votes over my answer. One is negative, one is by David himself, and this leaves us the 4 plus votes. I think SO is visited by hundreds if not thousands of Delphi programmers. And of those hundreds there were FOUR guys putting pluses ? Well, if THAT is David's influence, then it is marginally minimal. However that still does not explain why you did have deleted your answer no matter if David liked it or not. David is David, you are you. You do have a say - go on and say it. You don't - then nothign to fuss about. – Arioch 'The Jun 09 '13 at 08:39
  • @Arioch'The, there has been 68 views on this question and please don't get upset, I consider this to be a discussion not a rant. – Peter Jun 09 '13 at 08:42
  • @PeterVonča discussion about how to remove the single existing answer and leave the question with no answers at all ? Or, a very productive one... – Arioch 'The Jun 09 '13 at 08:45
  • @Arioch'The, I'm not opting in to remove this answer, what gave you that idea? I just wanted to raise to what I think is important issue. – Peter Jun 09 '13 at 08:46
  • I asked a question on this forum first time and within few hours of posting I was able to resolve it. I just want to say that you people are very helpful and this is a very active forum. thanks to all of you – Khawar Jun 09 '13 at 09:11
  • @PeterVonča You state that this is not the answer to the problem at all but just a vague discussion how one can figure the answer. Okay, this is not the answer, no one (and not you) provided another answer - that means question is left without answers at all. Actually claiming something "is not an answer" and still "opting in not to remove" looks not consistent to me. – Arioch 'The Jun 09 '13 at 09:11
  • @Khazar you're welcome. Keep learning, we all do. But SO is not a forum, it is Q&A site, you would see the difference as time passes by. For example http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Arioch 'The Jun 09 '13 at 09:13
  • @Arioch'The , you are twisting my words, I did not say that, I said : `this is a solution that vaguely describes how to debug the issue`. It is an answer to the question but in my opinion it isn't a very good answer. The OP didn't come to the right conclusion based on your answer but based on your `Comments` afterwards. – Peter Jun 09 '13 at 09:21
4

Your fundamental problem is a mis-understanding of the meaning of the indexed property

TTreeView.Items[]

Your believe that this accesses just the top level nodes. That is not so. This property gives access to each and every node in the tree. The way to understand that is to look at your tree, expand all folders, and read downwards from the top ignoring nesting. For your tree, the indexing looks like this:

Index    TreeView1.Items[Index]
-----    ----------------------
0        Pay History
1        Summary
2        Detail
3        Specific Account History
4        Summary
5        Detail
....     ....

So when you refer to TreeView1.Items[2] you are actually getting the node with caption Detail that is a child of the very first node, that named Pay History.

The node that you want has index 13 so you can change your code to be

TreeView1.Items[13].Text := ...;

The other property that you are using is TTreeNode.Item[]. This is different again. This access the list of direct children of a particular node. So, TTreeView1.Items[0].Item[] can be used to access the two nodes that are children of the first node, that named Pay History.


In your situation I would not want to write:

TreeView1.Items[13].Text := ...;

I would reject code that relied on a magic number like that. I would populate the tree view at runtime and save away in instance variables references to any nodes that I needed to use later. For example:

FPayHistoryNode := TreeView1.Add(nil, 'Pay History');
FPayHistorySummaryNode := TreeView1.AddChild(FPayHistoryNode, 'Summary');
FPayHistoryDetailNode := TreeView1.AddChild(FPayHistoryNode, 'Detail');
....

If you need to modify properties of the node later then you can do so with code that can be understood at a glance by the reader. And when you insert new nodes, or re-order the nodes, you don't break all your existing code as you would with a magic constant.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490