Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

RFC for Tutorials: Using BoxSizer Layout Manager in wxPerl

by waxhead (Acolyte)
on Apr 19, 2009 at 06:30 UTC ( [id://758548]=perlmeditation: print w/replies, xml ) Need Help??

I'm looking to have this added to the Wx Tutorials already on the site. Please feel free to comment and I'll make needed changes.

I'm following the development of Parde, a perl IDE written in perl.

With this, I'm toying with a few ideas and to actually get started I've been learning Wx, the GUI tool kit Padre uses.

I've found a couple of introductory articles that get you started.

They give you enough to create a basic Frame, a Panel, then a Text Box and a Button or two.

This is fine, but not a mention of how to manage the layout on the interface.

What's missing in these introductions is mention of the layout managers, at the least if they get mentioned you can at least google for them.

Layout managers manage it much simpler to position your widgets on the GUI.

These layout managers are BoxSizer, GridSizer and GridBagSizer.

I'm only going to cover the use of the BoxSizer for now, as this is the one that allows the simplest layout and the one I've only recently got my head around.

To start with we'll create a class that will create the main frame with a couple of widgets using the BoxSizer layout manager.

To start with:

package SizerExampleFrame; use strict; use warnings; use Wx qw /:everything/; use Wx::Event qw/EVT_BUTTON/; use base 'Wx::Frame'; sub new { my $class = shift; my $self = $class->SUPER::new( undef, -1, 'SizerExampleFrame', [-1,-1], [600, 400], );

Basically if you've started with any of the introductory articles you'll see that we've created a new Frame that is 600 by 400 pixels with a Title 'SizerExampleFrame'.

For this example we'll do something arbitrary, we'll create a Frame that has 4 "rows", we'll put labels in each of the rows, and in the last "row" we'll put in some buttons.

This will show how to use the BoxSizer with the two orientations to create a reasonably complex layout.

my $vbox = Wx::BoxSizer->new( wxVERTICAL );

To start with, we'll create a $vbox to hold the "rows". wxVERTICAL is a constant that tells the BoxSizer which orientation the Sizer is to take.

We'll create some panels to put widgets on:

my $pnl1 = Wx::Panel->new($self, -1); my $pnl2 = Wx::Panel->new($self, -1); my $pnl3 = Wx::Panel->new($self, -1); my $pnl4 = Wx::Panel->new($self, -1);

Now we have 4 Panels, each Parent is $self, being the frame we created right at the start.

With the Panels, we'll just stick a label in them.

my $lbl1 = Wx::StaticText->new( $pnl1, # parent -1, # id, "Testing: 1", # label [5,10], # position );

Just do this 2 more times:

my $lbl2 = Wx::StaticText->new( $pnl2, # parent -1, # id, "Testing: 2", # label [5,10], # position ); my $lbl3 = Wx::StaticText->new( $pnl3, # parent -1, # id, "Testing: 3", # label [5,10], # position );

For the 4th Panel we'll create a BoxSizer that runs vertically:

# now we want to create a vbox for the 4th panel # in this we will put button and other panels my $pnl4Vbox = Wx::BoxSizer->new( wxVERTICAL );

and another horizontally to hold the buttons:

my $btnBox = Wx::BoxSizer->new( wxHORIZONTAL ); my $pnlBtns = Wx::Panel->new( $pnl4, #parent -1, # id [-1,-1], # position [-1,-1], # size 0 # border style );

Now we'll create a set of buttons and link them up to their actions when the click event is triggered.

my $btnButton1 = Wx::Button->new( $pnlBtns, -1, 'Button 1'); EVT_BUTTON( $pnlBtns, $btnButton1, \&btnButton1Clicked ); my $btnButton2 = Wx::Button->new( $pnlBtns, -1, 'Button 2'); EVT_BUTTON( $pnlBtns, $btnButton2, \&btnButton2Clicked );

With the buttons created, we'll add them to our $btnBox:

$btnBox->Add( $btnButton1, 1, wxALIGN_BOTTOM, 0 ); $btnBox->Add( $btnButton2, 1, wxALIGN_BOTTOM, 0 );

Here we have told the layout manager that we want these buttons to be aligned along the bottom of the panel.

And then we set this button panel to use the sizer $btnBox:

$pnlBtns->SetSizer($btnBox);

With that, lets now set $pnl4's Sizer

$pnl4->SetSizer($pnl4Vbox);

Finally, we need to ->Add() all the panels to the $vbox for this frame:

$vbox->Add( $pnl1, 1, wxEXPAND | wxALL, 3); $vbox->Add( $pnl2, 1, wxEXPAND | wxALL, 3); $vbox->Add( $pnl3, 1, wxEXPAND | wxALL, 3); $vbox->Add( $pnl4, 1, wxEXPAND | wxALL, 3);

In these ->Adds()'s we've used wxEXPAND and wxALL to have the panel expand to fill all space available to it, the '3' in the last parameter is the size in Pixels for the border.

( see http://docs.wxwidgets.org/stable/wx_sizeroverview.html#boxsizerprogramming for more details )

Lastly, we set the Frames Sizer to the $vbox and then return $self:

$self->SetSizer( $vbox ); return $self; }

That's it for the instantiation of this class.

To be complete, the button subs follow:

sub btnButton1Clicked { my( $self, $event ) = @_; print "Button 1\n"; } sub btnButton2Clicked { my( $self, $event ) = @_; print "Button 2\n"; }

That's it.

I don't profess to have used any 'best practice' here, as I'm still learning the ropes with Wx myself.

What I hope to show here is how to use BoxSizer to get a fairly complex layout up and running quickly.

Something I couldn't find myself.

I managed to get a fairly good understanding of things after reading the wxPython Wiki. ( http://wiki.wxpython.org/AnotherTutorial ).

The full code follows:

package BoxSizerExampleFrame; use strict; use warnings; use Wx qw /:everything/; use Wx::Event qw/EVT_BUTTON/; use base 'Wx::Frame'; sub new { my $class = shift; my $self = $class->SUPER::new( undef, -1, 'Jabber Frame', [-1,-1], [600, 400], ); my $vbox = Wx::BoxSizer->new( wxVERTICAL ); my $pnl1 = Wx::Panel->new($self, -1); my $pnl2 = Wx::Panel->new($self, -1); my $pnl3 = Wx::Panel->new($self, -1); my $pnl4 = Wx::Panel->new($self, -1); my $lbl1 = Wx::StaticText->new( $pnl1, # parent -1, # id, "Testing: 1", # label [5,10], # position ); my $lbl2 = Wx::StaticText->new( $pnl2, # parent -1, # id, "Testing: 2", # label [5,10], # position ); my $lbl3 = Wx::StaticText->new( $pnl3, # parent -1, # id, "Testing: 3", # label [5,10], # position ); # now we want to create a vbox for the 4th panel # in this we will put button and other panels my $pnl4Vbox = Wx::BoxSizer->new( wxVERTICAL ); # we'll create a button panel and place the buttons # horizontally my $btnBox = Wx::BoxSizer->new( wxHORIZONTAL ); my $pnlBtns = Wx::Panel->new( $pnl4, #parent -1, # id [-1,-1], # position [-1,-1], # size 0 # border style ); my $pnl4Text = Wx::Panel->new( $pnl4, #parent -1, # id [-1,-1], # position [-1,-1], # size 0, #wxSIMPLE_BORDER # border style ); my $btnButton1 = Wx::Button->new( $pnlBtns, -1, 'Button 1'); EVT_BUTTON( $pnlBtns, $btnButton1, \&btnButton1Clicked ); my $btnButton2 = Wx::Button->new( $pnlBtns, -1, 'Button 2'); EVT_BUTTON( $pnlBtns, $btnButton2, \&btnButton2Clicked ); $btnBox->Add( $btnButton1, 1, wxALIGN_BOTTOM, 0 ); $btnBox->Add( $btnButton2, 1, wxALIGN_BOTTOM, 0 ); $pnlBtns->SetSizer($btnBox); $pnl4Vbox->Add( $pnl4Text, 1, wxEXPAND, 0); $pnl4Vbox->Add( $pnlBtns, # widget 1, # vertically stretchable wxALIGN_BOTTOM | wxALIGN_RIGHT, # alignment 0 # border pixels ); $pnl4->SetSizer($pnl4Vbox); $vbox->Add( $pnl1, 1, wxEXPAND | wxALL, 3); $vbox->Add( $pnl2, 1, wxEXPAND | wxALL, 3); $vbox->Add( $pnl3, 1, wxEXPAND | wxALL, 3); $vbox->Add( $pnl4, 1, wxEXPAND | wxALL, 3); $self->SetSizer( $vbox ); return $self; } sub btnButton1Clicked { my( $self, $event ) = @_; print "Button 1\n"; } sub btnButton2Clicked { my( $self, $event ) = @_; print "Button 2\n"; } 1;

Replies are listed 'Best First'.
Re: RFC for Tutorials: Using BoxSizer Layout Manager in wxPerl
by james28909 (Deacon) on Jun 01, 2014 at 06:11 UTC
    thank you for sharing this, up until now, i was able to add buttons and execute sub routines, but the problem was if i had 4 buttons, they would all execute the same subroutine for some reason. I am gonna study this and make me a little gui for a tool i have been trying to script :)
    Anyway, thanks for posting this :)
    EDIT: didnt see this was from 2009 until now lol

      Hi James,

      did you get this sorted? I would guess you are not setting the button ID to -1 (which is the same as wxID_ANY).

      Regards

      Steve

        Yep, I did get it sorted, but I do have another question in which ill make a new thread about ;)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://758548]
Approved by ikegami
Front-paged by Tanktalus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2024-03-28 14:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found