Change value in tree from tcl procedure

Moderator: GiD Team

Post Reply
tiago_valente
Posts: 7
Joined: Wed May 18, 2022 10:16 am

Change value in tree from tcl procedure

Post by tiago_valente »

Is it possible to change tha value of a field in the tree, from a tcl procedure and update its value in the tree?
If it is, can you provide an simple example.
User avatar
escolano
Posts: 1918
Joined: Sun Sep 05, 1982 10:51 pm

Re: Change value in tree from tcl procedure

Post by escolano »

Yes,
the data tree is stored in a XML DOM structure, and the window treectrl is filled from this data.
using the tdom package (https://docs.activestate.com/activetcl/8.6/tcl/tdom) you can access to this data
https://gidsimulation.atlassian.net/wik ... nformation

e.g.
load the problemtype Examples/cmas2d_customlib
you will see a tree like this
cmas2d_customlib_tree.png
cmas2d_customlib_tree.png (33.9 KiB) Viewed 2648 times
you can see the XML of his DOM with a command like this:
-np- W [[$::gid_groups_conds::doc documentElement] asXML]

Code: Select all

rials" pn="Edit materials" icon="darkorange-block1.png" proc="Cmas2d::EditDatabaseListDirect %W %DICT %BC"/>
            </value>
        </condition>
        <container n="materials" pn="Materials" icon="darkorange-block1" help="Materials database">
            <blockdata n="material" name="Air" sequence="1" editable_name="unique" icon="darkorange-wind-sign" help="Material definition" morebutton="0">
                <value n="Density" pn="Density" v="1.01" help="Superficial density assuming a thickness of 1 meter" unit_magnitude="M/L^2" units="kg/m^2"/>
            </blockdata>
            <blockdata n="material" name="Steel" sequence="1" editable_name="unique" icon="darkorange-bracket" help="Material definition" morebutton="0">
                <value n="Density" pn="Density" v="7850" help="Superficial density assuming a thickness of 1 meter" unit_magnitude="M/L^2" units="kg/m^2"/>
            </blockdata>
            <blockdata n="material" name="Aluminium" sequence="1" editable_name="unique" icon="darkorange-alu" help="Material definition" morebutton="0">
                <value n="Density" pn="Density" v="2650" help="Superficial density assuming a thickness of 1 meter" unit_magnitude="M/L^2" units="kg/m^2"/>
            </blockdata>
        </container>
    </container>
    <display_options frame_width="321" is_frame_open="1" view_conditions_search="1" conditions_search_values="" frame_side="left"/>
    <global_preferences>
        <units>
            <unit_magnitude_user_sel n="M" values="kg"/>
            <unit_magnitude_user_sel n="L" values="m"/>
            <unit_mesh n="m"/>
        </units>
        <tree_preferences/>
    </global_preferences>
</cmas2d_customlib_data>
If do you want for example ask for the 'Density' of the material named 'Steel' , can see in the XML that in this problemtype the materials are in a node named 'container' with an attribute 'n' with value 'materials' and then several child nodes named 'blockdata' with an attribute 'n' with value 'material' and we want the one that match the attribute 'name' that we want to ask.
then we use an xpath like this
set x_path "//container\[@n='materials'\]/blockdata\[@n='material' and @name='$material'\]"
and inside there are sub-childs with name= 'value for each question, and we want the one with attribute 'n' equal to our question to ask
set x_path_3 ".//value\[@n='$question'\]"

can define these procedures

Code: Select all

proc my_get_dom_nodes { xpath } {
    set doc $gid_groups_conds::doc
    set root [$doc documentElement]
    set dom_nodes [$root selectNodes $xpath]
    return $dom_nodes
}

proc my_get_material { material question } {
    set value ""
    set x_path "//container\[@n='materials'\]/blockdata\[@n='material' and @name='$material'\]"
    set dom_material [my_get_dom_nodes $x_path]
    if { [llength $dom_material] != 1 } {
        error "Error: material '$material' not found"
    } else {
        set x_path_3 ".//value\[@n='$question'\]"
        set dom_node [lindex [$dom_material selectNodes $x_path_3] 0]
        if { $dom_node == "" } {
            error "GiD_AccessValue: property $question not found in material $material"
        }
        set value [$dom_node getAttribute v ""]
    }
    return $value
}
and use it like this:
-np- W [my_get_material Steel Density]
and will get the value
7850

if do you want to set its value, can define another procedure like this:

Code: Select all

proc my_set_material { material question value } {
    set x_path "//container\[@n='materials'\]/blockdata\[@n='material' and @name='$material'\]"
    set dom_material [my_get_dom_nodes $x_path]
    if { [llength $dom_material] != 1 } {
        error "Error: material '$material' not found"
    } else {
        set x_path_3 ".//value\[@n='$question'\]"
        set dom_node [lindex [$dom_material selectNodes $x_path_3] 0]
        if { $dom_node == "" } {
            error "GiD_AccessValue: property $question not found in material $material"
        }
        $dom_node setAttribute v $value
    }
    return $value
}
and use it like this to set to other value:
-np- W [my_set_material Steel Density 8200.5]

and to refresh the tree widget is possible to use something like this (simple but expensive because will destroy and rebuild the whole widget)
-np-GidUtils::UpdateWindow CUSTOMLIB
tiago_valente
Posts: 7
Joined: Wed May 18, 2022 10:16 am

Re: Change value in tree from tcl procedure

Post by tiago_valente »

Thanks for the reply.

In regard to the update of the tree, the command gid_groups_conds::actualize_conditions_window is less "expensive" than the proposed GidUtils::UpdateWindow ?

Best regards
User avatar
escolano
Posts: 1918
Joined: Sun Sep 05, 1982 10:51 pm

Re: Change value in tree from tcl procedure

Post by escolano »

They will have similar cost,
in fact GidUtils::UpdateWindow CUSTOMLIB will call gid_groups_conds::actualize_conditions_window

I recommend you use GidUtils::UpdateWindow instead directly gid_groups_conds::actualize_conditions_window
because it use a common centralized syntax to update several windows (CUSTOMLIB, GROUPS, LAYER, ...)
and the same for
GidUtils::OpenWindow, GidUtils::CloseWindow, GidUtils::ExistsWindow, GidUtils::ToggleWindow
(see comments on <GiD>\scripts\dev_kit.tcl to know the names of windows for these hight level functions)

If you do several changes of the tree and do a final update the cost doesn't matter, but don't update it after each change, in this case must use some lower level function to not rebuild the whole tktreectrl widget)
Post Reply