swamprich has asked for the wisdom of the Perl Monks concerning the following question:

So I'm trying to dynamically process an XML file using the Wx::Perl::TreeChecker package. I've taken the treechecker.pl demo included in the TreeChecker source download and modified it for my use. My code and XML sample is below.

content_tree.pl
use strict; use Wx qw(:everything); use Wx::Perl::Carp; use XML::Simple; package Content_App; use vars '@ISA'; @ISA = 'Wx::App'; sub OnInit { my $self = shift; my $frame = MyTreeChecker_Frame->new('Wx::Perl::TreeChecker', Wx:: +wxDefaultPosition(), [450,450]); $self -> SetTopWindow ($frame); $frame -> Show(1); 1; } package MyTreeChecker_Frame; use vars '@ISA'; @ISA = 'Wx::Frame'; use Wx qw(:sizer :misc wxOK wxICON_INFORMATION wxBITMAP_TYPE_ICO wxID_ +ANY); use Wx::Perl::TreeChecker; sub new { my $class = shift; my ($title, $pos, $size) = @_; my $self = $class->SUPER::new (undef, -1, $title, $pos, $size); $self -> SetIcon (Wx::Icon->new("Resources\\Graphics\\main.ico", w +xBITMAP_TYPE_ICO)); my $filemenu = new Wx::Menu; my $menubar = new Wx::MenuBar; $filemenu -> Append (1, 'E&xit'); $menubar -> Append ($filemenu, '&File'); $self -> SetMenuBar ($menubar); use Wx::Event 'EVT_MENU', 'EVT_BUTTON', 'EVT_RIGHT_UP', 'EVT_RIGHT +_DOWN', 'EVT_TREE_ITEM_RIGHT_CLICK'; EVT_MENU ($self, 1, \&OnQuit); EVT_MENU ($self, 2, \&OnToggleMultiple); EVT_MENU ($self, 3, \&OnToggleItems); EVT_MENU ($self, 4, \&OnToggleContainers); EVT_MENU ($self, 5, \&OnToggleSelectAll); my $panel = new Wx::Panel ($self); my $sizer = new Wx::BoxSizer (wxVERTICAL); $self -> {treechecker} = new Wx::Perl::TreeChecker ($panel, -1, wx +DefaultPosition, wxDefaultSize); $sizer -> Add ($self -> {treechecker}, 1, wxGROW); $panel -> SetSizer ($sizer); $self -> fill_treechecker(); EVT_RIGHT_DOWN ( $self->{treechecker} , \&RightClickMenu); $self->{treechecker}->items_only(1); $self->{treechecker} -> allow_multiple(0); Wx::Event::EVT_TREELIST_ITEM_EXPANDING($self, $self->{treechecker} +, \&OnItemExpanding); Wx::Event::EVT_TREELIST_ITEM_EXPANDED($self, $self->{treechecker}, + \&OnItemExpanded); #Wx::Log::SetActiveTarget (new Wx::LogTextCtrl ($self -> {textctrl +})); return $self; } sub fill_treechecker { my $self = shift; my $treechecker = $self -> {treechecker}; our %scapHash = (); my $xml = XML::Simple::XMLin("modified_options.xml", ForceArray => + 1); foreach my $stream (@{$xml->{contents}}) { for my $content_name (@{$stream->{content}}) { for my $profile (@{$content_name->{profiles}}) { for my $profile_name (@{$profile->{profile}}) { push @{$scapHash{"$content_name->{stream}->[0]"}}, + $profile_name; } } } } _populate_tree($treechecker, "", \%scapHash); } sub _populate_tree { my ($tree, $id, $data) = @_; my $root; #recursively build a tree control return unless $data && ref $data; if (ref($data) eq 'HASH') { foreach my $stream (sort keys %$data) { print "\n". $stream . "\n"; my $stream_id = $tree -> AddRoot($stream); #my $container = $tree -> AppendContainer($stream_id, $str +eam, td($stream)); _populate_tree($tree, $stream_id, $data->{$stream}); } } elsif (ref $data eq 'ARRAY') { foreach my $profile (@$data) { print "\t$profile\n"; $tree-> AppendItem ($id, $profile, td($profile)); } } #$tree -> Expand ($id); } sub td { return new Wx::TreeItemData(shift); } sub OnQuit { my ($self, $evt) = @_; $self -> Close (1); } sub OnToggleMultiple { my ($self, $evt) = @_; my $tree = $self -> {treechecker}; $tree -> UnselectAll(); $tree -> allow_multiple($evt->IsChecked); } sub OnToggleItems { my ($self, $evt) = @_; my $tree = $self -> {treechecker}; $tree -> UnselectAll(); $tree -> containers_only(0); $tree -> items_only(1); } sub OnToggleContainers { my ($self, $evt) = @_; my $tree = $self -> {treechecker}; $tree -> UnselectAll(); $tree -> items_only(0); $tree -> containers_only(1); } sub OnToggleSelectAll { my ($self, $evt) = @_; my $tree = $self -> {treechecker}; $tree -> UnselectAll(); $tree -> items_only(1); $tree -> containers_only(0); } sub RightClickMenu { my( $self, $event ) = @_; my $menu = Wx::Menu->new( "" ); $menu->Append(7, "Select All", sub {$self->{treechecker}->Unselec +tAll(); $self->{treechecker}->items_only(1);}); $menu->AppendSeparator(); $menu->Append(8, "Clear All", sub {$self->{treechecker}->Unselect +All(); $self->{treechecker}->items_only(1);} ); $self->PopupMenu( $menu , $event->GetX, $event->GetY); } sub OnItemExpanded { my ($self, $event) = @_; my $item = $event->GetItem; my $itemtext = $self->{treechecker}->GetItemText($item); print('Evt Item has expanded : %s', $itemtext); } sub OnItemExpanding { my ($self, $event) = @_; my $item = $event->GetItem; my $itemtext = $self->{treechecker}->GetItemText($item); print "\n $itemtext"; Wx::LogMessage('Evt Item is expanding : %s', $itemtext); } ###################################################################### +######## package main; my $sample = new Content_App; $sample -> MainLoop;
modified_options.xml
<?xml version="1.0" encoding="UTF-8"?> <options> <timeStamp>2017-03-30T10:07:38</timeStamp> <contents> <content> <stream>stream_1</stream> <profiles> <profile>no_profile_selected</profile> <profile>profile_1</profile> </profiles> </content> <content> <stream>stream_2</stream> <profiles> <profile>no_profile_selected</profile> <profile>profile_1</profile> </profiles> </content> <content> <stream>stream_3</stream> <profiles> <profile>profile_1</profile> <profile>profile_2</profile> <profile>profile_3</profile> <profile>profile_4</profile> <profile>profile_5</profile> </profiles> </content> <content> <stream>stream_4</stream> <selectedProfile>profile_1</selectedProfile> <profiles> <profile>profile_1</profile> <profile>profile_2</profile> <profile>profile_3</profile> <profile>profile_4</profile> <profile>profile_5</profile> </profiles> </content> <content> <stream>stream_5</stream> <profiles> <profile>profile_1</profile> <profile>profile_2</profile> <profile>profile_3</profile> <profile>profile_4</profile> <profile>profile_5</profile> </profiles> </content> <content> <stream>stream_6</stream> <profiles> <profile>profile_1</profile> <profile>profile_2</profile> <profile>profile_3</profile> <profile>profile_4</profile> <profile>profile_5</profile> </profiles> </content> <content> <stream>stream_7</stream> <profiles> <profile>profile_1</profile> <profile>profile_2</profile> <profile>profile_3</profile> <profile>profile_4</profile> <profile>profile_5</profile> </profiles> </content> </contents> </options>
The print statements in the _populate_tree function prints everything as expected but the Window only displays stream_1 and it's profiles. Is it possible to have multiple roots in a single tree? Am I missing something or do I need to treat each stream as a separate tree?

Replies are listed 'Best First'.
Re: Wx::Perl::TreeChecker multiple root nodes
by beech (Parson) on Apr 10, 2017 at 18:05 UTC

    Hi

    If you search for "root" in http://docs.wxwidgets.org/trunk/classwx_tree_ctrl.html you'll find

    wxTR_LINES_AT_ROOT: Use this style to show lines between root nodes. Only applicable if wxTR_HIDE_ROOT is set and wxTR_NO_LINES is not set.

    wxTR_HIDE_ROOT: Use this style to suppress the display of the root node, effectively causing the first-level nodes to appear as a series of root nodes.

    So this is what that looks like

    #!/usr/bin/perl -- use strict; use warnings; use Wx; use Wx::Perl::TreeChecker; my $frame = Wx::Frame->new( undef, -1, 'Wx::Perl::TreeChecker' ); my $tree = Wx::Perl::TreeChecker->new( $frame, -1, [ -1, -1 ], [ -1, -1 ], Wx::wxTR_DEFAULT_STYLE() | Wx::wxTR_HIDE_ROOT() ^ Wx::wxTR_LINES_AT_ROOT() ); if( $tree ->IsEmpty ){ $tree -> AddRoot('/'); } my $root = $tree->GetRootItem; for my $ix (1..10){ my $id = $tree->AppendItem ($root, "noot $ix"); $tree->AppendItem ($id, "$_ noot $ix") for 1..3; } $tree->ExpandAll; $frame->Show(1); Wx::SimpleApp->new->MainLoop;

    In your code change the constructor

    $self -> {treechecker} = Wx::Perl::TreeChecker->new( $panel, -1, [ -1, -1 ], [ -1, -1 ], Wx::wxTR_DEFAULT_STYLE() | Wx::wxTR_HIDE_ROOT() ^ Wx::wxTR_LINES_AT_ROOT() );

    and modify _populate_tree

    if( $tree ->IsEmpty ){ $tree -> AddRoot('/'); } my $root = $tree->GetRootItem; my $stream_id = $tree-> AppendItem( $root, $stream ); _populate_tree($tree, $stream_id, $data->{$stream});
      Thank you! I saw the wxTR_HIDE_ROOT() but I misunderstood the description and assumed it would hide the stream names. Again, thanks a ton, you've said me a ton of trial and error in getting this to populate as I need it.