Forum Discussion

markus_humm's avatar
markus_humm
Occasional Contributor
13 years ago

TC 8.60 and TVirtualTreeView.GetNodeLevel

Hello,



I'm using TC 8.6 and my application contains the well known freeware TVirtualStringTree component in various places.

Now I'm writing a library for me to handle this in my testscripts and tried to use the GetNodeLevel method from a

TVirtualStringTree but for my given node (which is the correct one) it always returns 0 (I can check this in script debugger)

but the node is 3-4 levels deep!



How can this be and what can I do?



Greetings



Markus
  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor
    While TVirtualStringTree is common, it is, to me, the bane of my existance at my last job.  These reason being is that the nodes within the virtual string tree are not Ole compatible objects but are Delphi record objects and, therefore, inaccessible to TestComplete.  Real pain..



    What we had to do is use a combination of keystrokes and explicit "DoEdit" calls on the TVirtualStringTree object to navigate and search for text within a "cell" on the component and then perform actions based upon that location...  Fortunately, our developers at a later point added controls to the form containing the component for actually executing a search and then, with the record highlighted, you can click a button on the form and it sill act on what is highlighted... we still could not directly access the rows and nodes on the string tree, but we could manipulate our way through it...



    sorry, but I really don't know of another way... if you get a different answer of figure out something else, please post it as I have some friends back at that old job who would love to be able to get away from some of those work-arounds....
  • katepaulk's avatar
    katepaulk
    Occasional Contributor
    Rob Martin has it pretty much set, there (he's a former co-worker and I'm still at the location that uses the virtual string tree component).



    Some suggestions based on the interesting times I've had:



    If your parent form has the ability to expand all nodes, that should be the first step. The alternative is a mix of selecting the parent and using keystrokes to expand. Of course, using the keystroke method, you can count the number of expand actions you perform to reach the desired node and check that against your expected node depth, which isn't available with an expand all.



    Another option, depending on how your virtual string tree is laid out, is to use TVirtualStringTree.ContentToText_1(0, ','); This will return a string formatted as a CSV file. You can split this into a string list and navigate through it - although I'd suggest you start by saving to CSV and taking a look at what's returned. (Alternatively, use a different separator and save as text, then take a look). Chances are, there's a consistent way to represent child nodes in the output of ContentToText - I've never needed more than an output comparison yet, and most of the virtual string trees I work with are no more than 2 levels deep).



    Unfortunately, the internal records structures in Delphi don't play at all well with TestComplete - they're essentially invisible.



    If you need code snippets, please ask, and I'll supply the core part of what's in use where I work. It's ugly, but it works most of the time.



    Good luck!
  • markus_humm's avatar
    markus_humm
    Occasional Contributor
    Hello,



    sorry to say, but you seem to lack some information in this area.

    If you compile your Delphi program with all debugging options on you can call

    methods of the VST componet as you wish. For instance GetFirst, GetNext etc.

    which will return a node and GetText(node, column) which will return the text on

    a node/column.



    You can also do a vst.Click(x, y);  But for this you need to know the coordinates.

    This you can calculate (node.NodeHeight is your friend for this) and if the node is

    outside of the visual area of the VST you need to scroll it into view.

    For this SetOffsetY exists.



    For finding out all of this you need to have Delphi and some programming expertise

    though, as TC might not show all of those things in the code completion window.



    SInce the VST.GetNodeLevel function always returns 0 in TC I'll investigate now if

    I can roll my own one.



    Maybe with this information you can create more rich testscripts yourself now...



    Have a nice day



    Markus
  • markus_humm's avatar
    markus_humm
    Occasional Contributor
    Hello,



    so 5 minutes later: my own GetNodeLevel works like it should. Problem solved.

    How to do that one I leave as exercise to you, if you've got the VST source code

    you can follow the implementation there...



    Greetings



    Markus
  • markus_humm's avatar
    markus_humm
    Occasional Contributor
    Ok, quite a while later it proved not so easy but I found a solution.

    The remaning issue with my own GetParentNode implementation was, that it has "phantom" parent nodes.

    Not sure why, but I simply found a way to identify them as such which works for me. I just consider my

    approach of testing vst.GetText of such phantom nodes agains 'Node' and additionally testing on assigned

    (as that's the case for the next phantom level) a hack. I hope the hack works everywhere as intended, but

    that only time will tell I guess...



    Makes me still wonder where these phantom nodes come from.



    Greetings



    Markus
  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor
    Perhaps TC's support for the VST component has been improved... or the version of the VST component you are using is different than what we used.  Both potentially likely.



    Since I'm not currently working with Delphi apps, I cannot try this out on my own.  If you could create a simple app using the VST component compiled as you indicated, I'd be VERY interested to play with it, simply for experience sake.
  • katepaulk's avatar
    katepaulk
    Occasional Contributor
    I'd also love to see the script and the sample application, because I am still working with VirtualStringTree and would love to have more options (not that I'm going to get access to Delphi)
  • markus_humm's avatar
    markus_humm
    Occasional Contributor
    Hello,



    important is, to have a good connection to a Delphi/C++ Builder developer because it's easier for them to find out wich methods, properties and fields do exist for the VST. In my case it's pretty easy, because I just need to cunsolt myself! ;-) (developer and tester in one person)



    Ok, now for a short script fragment to show you what can be done:



    // determine the number of nodes in a given vst. Doesnn't matter if they're collapsed or not visible

    function GetGridNodeCount(vst:OLEVariant):Integer;

    var node:OLEVariant;  

    begin

      result:=0;



      // to determine node count we've to iterate over them   

      node:=vst.GetFirst;

      while assigned(node) do

      begin

        inc(result);

        

        // get next node

        node:=vst.GetNext(node);    

      end;



      Log.Message('VirtualTreeView '+vst.Name+' hat '+IntToStr(result)+' Knoten');

    end;



    To get the text of a node you can use vst.GetText(node, columnid);

    (e.g. 0 for the first column or ith the tree has no columns simply the node text)



    node.Height contains the height of a node in pixel and with vst.click(x, y);

    you can click on something.



    Those pointers should give you a start. But remember: all debug information and RTTI must be

    on when compiling the Delphi application you want to test.



    I hope this level of detail is sufficient for you. Greetings



    Markus
  • katepaulk's avatar
    katepaulk
    Occasional Contributor
    Markus,



    Thank you so much! As it happens, I think your version of the virtual string tree may be different than the one I'm working with.



    The code I used to select a specific row in a virtual string tree (with the column, component, and text to search for passed in elsewhere) has now gone from a mess using position-specific clicks, the DoEdit method, and a whole lot of Keys calls to navigate through the tree to this:



    Node := Tree.GetFirst(TRUE);


    while assigned(node) do begin


        // See if the node text matches the text we're after


        // If it does, end the routine - we found it.


        if Tree.GetText(Node, VarToInteger(Column)-1) = Target then begin


            Tree.SetSelected(Node, TRUE);


            Result := TRUE;


            Exit;


            end;


        Node := Tree.GetNext(Node, TRUE);


        end;



    This is so much cleaner and less confusing than the old way.