The following script creates a window with a menu.
When clicking on the File/Run menu option it will destroy and then recreate
some of the menu items several times (100 by default).

As I can see this script leaks memory.
If I run it as it is it leaks about 20-30 bytes per run.
If I enabled the event generation code as well which is currently
commented out then with each run the RES memory will grow by ~ 600 bytes.

Any idea why is that and how could I avoid?
Do I need to explicitly remove the event handlers? How ?

Gabor



use strict;
use warnings;

my $app = Wx::SimpleApp->new;
my $x   = My->new;
$app->MainLoop;


package My;
use strict;
use warnings;

use Params::Util ();
use Wx         qw(:everything);
use Wx::Event  qw(:everything);
use base       qw(Wx::Frame);

sub get_menu {
        return [
        ['First',  [qw(A B C)]],
        ['Second', [qw(D E F)]],
        ];
}

my $file;

sub new  {
        my ($class) = @_;
        my $self = $class->SUPER::new(
                undef, -1, 'Menu', wxDefaultPosition, [ 800, 600 ],
        wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE|wxCLIP_CHILDREN );

        my $bar  = Wx::MenuBar->new;
        $file = Wx::Menu->new;
        my $add    = $file->Append( -1, 'Add' );
        my $remove = $file->Append( -1, 'Remove' );     
        my $run    = $file->Append( -1, 'Run' );
        $file->Append( wxID_EXIT, '' );
        $bar->Append( $file, "&File" );
        $self->SetMenuBar( $bar );
        $self->refresh;
        
        my $text = Wx::TextCtrl->new
                ( $self, -1, "", wxDefaultPosition, wxDefaultSize,
        wxTE_READONLY|wxTE_MULTILINE|wxNO_FULL_REPAINT_ON_RESIZE );


        EVT_MENU( $self, wxID_EXIT, sub { $self->Close } );
        EVT_MENU( $self, $add,    \&add_entries);
        EVT_MENU( $self, $remove, \&remove_entries);
        EVT_MENU( $self, $run,    \&update_menu);

        $self->Show;
        return $self;
}


sub update_menu {
        my ($self, $event) = @_;

        for ( 1..100 ) {
                $self->refresh;
        }
        return;
}


sub add_entries {
        my $self = shift;

#print "add\n";
        my @entries;
        my $menus = $self->get_menu;
        foreach my $m (@$menus) {
                my $name = $m->[0];
                my $menu = $self->create_submenu( $self, $m->[1] );
#               print "A: '$name' '$menu'\n";
                push @entries, $file->Append( -1, $name, $menu );
        }
        $self->{entries} = \...@entries;
        return 1;
}

sub remove_entries {
        my $self    = shift;
        my $entries = $self->{entries} || [];

        while ( @$entries ) {
                my $e = pop @$entries;
                #print "$e\n";
                $file->Destroy( $e );
        }
        $self->{entires} = $entries;

        return 1;
}

sub refresh {
        my ($self) = @_;
        $self->remove_entries;
        $self->add_entries;
}


sub create_submenu {
        my $self  = shift;
        my $main  = shift;
        my $items = shift;
        
        my $menu = Wx::Menu->new;
        foreach my $label ( @$items ) {
                #$menu->AppendSeparator;

                my $value = sub { print "$label\n"; };

#               Wx::Event::EVT_MENU(
#                       $main,
#                       $menu->Append( -1, $label ),
#                               sub {
#                                       eval { $value->(@_) };
#                               },
#                       );
        }

        return $menu;
}

Reply via email to