Jdun
Jdun

Reputation: 73

Wxwidgets / Wx Perl grid sizing issues

Ok. I've been stuck on this for several days now and I'm at wits end here. I'm by no means an expert in Perl.

I'm writing a GUI app using WxPerl. To cut down on the noise, I've recreated a portion of the app where I'm having issues. I designed the layout in FormBuilder, then used the resulting XRC file. The XRC data is included below, save it in a file called noname.xrc.

In a nutshell, the GUI has two grids (left and right), with two buttons in the middle. For testing, there's an "add row" button at the top of the main frame, which adds a row to the left grid. I wrote an EVT_SIZE function to adjust the last column of the grid on the left to fill the remaining space, which then modifies the grid on the right in the same way to keep them equal proportions.

Issues:

1) Click the add button 20 times, then adjust the size of the main frame window. Notice how the grid all of a sudden expands and eats up the entire bottom of the frame. Click the add button a few more times and it continues eating up the bottom... I can't seem to get the height to adjust to prevent it from eating up the bottom portion. Maybe there's an obvious form setting I'm missing? Even removing the growablecols flag from the wxGridBagSizer doesn't stop this from happening.

2) An annoying visual issue, which is probably related to the proportional sizing. Basically, there's border padding on each side of the grid (5x2), which is 10. So I've subtracted 11 from the width before it is set, but ideally it should be 10. However, if it's set to 10, when resizing occurs the last column keeps growing forever...

3) If you click the "Maximize" button in the top right corner of the main frame, then click it again (it's called "Restore Down" then), to revert it back to the previous size, you'll see that the right grid never adjusts obviously, since the left grid hasn't changed size which never triggers the EVT_SIZE event... I've been brainstorming how to fix this, maybe the on size event can check the position of the right grid and determine if it's beyond the width of the main frame? Is there an easier way to get this to size properly?

Ideally, I'd like to set minimum sizes for certain grid columns, but have all the columns grow as the main window is resized. But that's probably a pipe-dream at this point.

#!/usr/bin/perl

package wxToplevelFrame;
 use strict;
 use warnings;
 use Wx qw(:everything);
 use Wx::Grid;
 use Wx::XRC;
 use base 'Wx::Frame';
 use Data::Dumper;
 use diagnostics;

# import event registration function
use Wx::Event qw(:everything);

use base qw(Wx::Panel Class::Accessor::Fast);
__PACKAGE__->mk_ro_accessors( qw(xrc) );

$| = 1;

### GUI CODE BEGINS ###

# create specialized constructor for new subclass
sub new {
    my $class = shift;
    my $self = $class->SUPER::new();

    $self->initialize();    
    return $self;
}


sub initialize {
    my ($self) = @_;

    my $xrc_path = 'noname.xrc';

    Wx::InitAllImageHandlers();

    $self->{ xrc } = Wx::XmlResource->new();
    $self->xrc->InitAllHandlers();
    $self->xrc->Load($xrc_path);
    $self->xrc->LoadFrame($self, undef, 'MyFrame1',);

    # main frame close
    EVT_CLOSE( $self, 
        sub {
            my ($self) = @_;
            $self->Destroy();
        }
    );


    # LEFT GRID
    my $grid_left = $self->{ grid_left } = $self->FindWindow('m_grid4');
    $grid_left->CreateGrid(0, 3);

    $grid_left->SetColLabelSize(25); # label height
    $grid_left->SetRowLabelSize(25); # row width (far left, the numbers column basically)

    $grid_left->SetColLabelValue(0, 'col_1');
    $grid_left->SetColLabelValue(1, 'col_2');
    $grid_left->SetColLabelValue(2, 'col_3');

    $grid_left->EnableDragColSize(0);
    $grid_left->EnableDragRowSize(0);
    $grid_left->EnableEditing(0);

    $grid_left->SetDefaultRowSize(20);

    $grid_left->SetColSize( 0, 190 ); # col 1
    $grid_left->SetColSize( 1, 50 );  # col 2
    $grid_left->SetColSize( 2, 179 ); # col 3


    # RIGHT GRID
    my $grid_right = $self->{ grid_right } = $self->FindWindow('m_grid5');

    $grid_right->CreateGrid(0, 3);

    $grid_right->SetColLabelSize(25); # label height
    $grid_right->SetRowLabelSize(25); # row width (far left, the numbers column basically)

    $grid_right->SetColLabelValue(0, 'col_');
    $grid_right->SetColLabelValue(1, 'col_2');
    $grid_right->SetColLabelValue(2, 'col_3');

    $grid_right->EnableDragColSize(0);
    $grid_right->EnableDragRowSize(0);
    $grid_right->EnableEditing(0);

    $grid_right->SetDefaultRowSize(20);

    $grid_right->SetColSize( 0, 190 ); # col 1
    $grid_right->SetColSize( 1, 50 );  # col 2
    $grid_right->SetColSize( 2, 179 ); # col 3

    #EVT_SIZE( $grid_left, \&on_size ); # adjust grid when size changes
    #EVT_SIZE( $grid_right, \&on_size ); # adjust grid when size changes

    my $on_size = \&on_size;
    EVT_SIZE($grid_left, callback($on_size, $self, $grid_left) );


    my $button = $self->{ button } = $self->FindWindow('m_button3');

    EVT_BUTTON(
        $button,
        $button->GetId(),
        callback(my $button_sub = \&add_row, $self, $button),
    );

    my $gui_actions_text_ctrl = $self->FindWindow('m_textCtrl1');
    my $gui_log = Wx::LogTextCtrl->new( $gui_actions_text_ctrl );
    $self->{ gui_log_text_ctrl } = Wx::Log::SetActiveTarget( $gui_log );

    $self->SetStatusBarPane(-1);
    return;
}

sub callback { 
    my $coderef = shift; 
    my @args = @_;

    #print "what is args\n";
    #print Dumper \@args;

    sub { $coderef->(@args) } 

    # callback function.  when we want to pass addition args to a method call, such as an event (EVT_*), we can use this
    # example:
    # my $on_size_test = \&on_size_test;
    # EVT_SIZE($grid_left, callback($on_size, $grid_left, $self) );
} 

sub on_close {
    my ($self) = @_;
    $self->Destroy();
}

sub on_size {
    my ($self, $grid) = @_;
    print "in on_size sub\n";

    # get the number of columns and the initial width which includes the far left number column (gutter column, with row indicators 1, 2, 3 ...)
    my $num_cols   = $grid->GetNumberCols();
    my $width      = $grid->GetRowLabelSize();
    my $gutter_col = $width;

    print "num_cols: $num_cols\n";
    print "initial width: $width\n";

    my $col_0;
    my $col_1;
    my $col_2;

    # iterate over each column, get size and add it to our width
    for (my $col = 0; $col < $num_cols; $col++) {

        # conditionals of no importance currently, but used during testing
        if ($col == 0) {
            $col_0 = $grid->GetColSize($col);
            print "col: $col, width col_0: $col_0\n";

        } elsif ($col == 1) {
            $col_1 = $grid->GetColSize($col);
            print "col: $col, width col_1: $col_1\n";

        } elsif ($col == 2) {
            $col_2 = $grid->GetColSize($col);
            print "col: $col, width col_2: $col_2\n";
        }
        $width += $grid->GetColSize($col);
    }

    print "width after iterating over each column: $width\n";

    # get sizer that grid is contained in
    # get width of sizer and subtract it from the total width
    # the difference will be the size we set for our last column
    if ($num_cols > 0) {

        my $static_box_sizer = $grid->GetContainingSizer();
        my $sizer            = $static_box_sizer->GetSize();
        my $sizer_width      = $sizer->GetWidth();

        print "sizer_width: $sizer_width\n";
        print "we are setting width for the last column.  sizer_width: $sizer_width minus the total width: $width (gutter_col: $gutter_col, col_0, col_1, col_2)\n";

        my $width_diff = $sizer_width - $width + $col_2 - 11;   # ideally this should be 10 for padding (5x2) on each side of sizer
                                                                # but setting it at 10 causes the col to keep expanding...

        print "width_diff result of above calc: $width_diff\n";

        $grid->SetColSize($num_cols - 1, $width_diff); # last column

        # adjust grid right to reflect same proportions
        $self->{ grid_right }->SetColSize($num_cols - 1, $width_diff); # last column        
    }

    return;
}

sub add_row {
    my ($self, $button) = @_;

    $self->{ grid_left }->AppendRows(1);

    my $col = 0;
    foreach my $value ('testing', 100, 'Sat Aug 20 20:52:20 2016') {
        my $row;    
        if ($col == 3) {
            $self->{ grid_left }->AppendRows(1);
            $row = $self->{ grid_left }->GetNumberRows() - 1; # minus one from total rows
            print "col == 2\n";
            print "reset\n";
            print "what is row: $row\n";
            $col = 0;
        } else {
            $row = $self->{ grid_left }->GetNumberRows() - 1;
        }
        print "value: $value\n";

        $self->{ grid_left }->SetCellValue(
            $row,
            $col,
            $value,
        );

        if ($col == 1) {
            $self->{ grid_left }->SetCellAlignment(
                $row,
                $col,
                wxALIGN_RIGHT,
                wxALIGN_CENTRE,
            );

        } elsif ($col == 2) {
            $self->{ grid_left }->SetCellAlignment(
                $row,
                $col,
                wxALIGN_CENTRE,
                wxALIGN_CENTRE,
            );
        }
        $col++;

    }
}
### GUI CODE ENDS ###

# END: wxToplevelFrame package


# create an app object
package MyApp;
 use strict;
 use warnings;
 use base 'Wx::App';

# OnInit is called automatically when an app object is first constructed
sub OnInit {
    my $self = shift;
    my $toplevel_frame = wxToplevelFrame->new();
    $self->SetTopWindow($toplevel_frame);   
    $toplevel_frame->Show(1);
}
# END: MyApp package


package main;
 use strict;
 use warnings;
 use Data::Dumper;

$| = 1;

my $app = MyApp->new(); # instantiate our app first
$app->MainLoop();

exit;

XRC file: noname.xrc

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
    <object class="wxFrame" name="MyFrame1">
        <style>wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL</style>
        <size>998,700</size>
        <title>Grid Issues</title>
        <centered>1</centered>
        <aui_managed>0</aui_managed>
        <object class="wxPanel" name="m_panel6">
            <style>wxTAB_TRAVERSAL</style>
            <object class="wxBoxSizer">
                <orient>wxVERTICAL</orient>
                <object class="sizeritem">
                    <option>1</option>
                    <flag>wxALL|wxEXPAND</flag>
                    <border>5</border>
                    <object class="wxFlexGridSizer">
                        <rows>0</rows>
                        <cols>6</cols>
                        <vgap>0</vgap>
                        <hgap>0</hgap>
                        <growablecols></growablecols>
                        <growablerows></growablerows>
                        <object class="sizeritem">
                            <option>0</option>
                            <flag>wxALL</flag>
                            <border>5</border>
                            <object class="wxButton" name="m_button3">
                                <label>add row</label>
                                <default>0</default>
                            </object>
                        </object>
                    </object>
                </object>
                <object class="sizeritem">
                    <option>3</option>
                    <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
                    <border>5</border>
                    <object class="wxGridBagSizer">
                        <vgap>0</vgap>
                        <hgap>0</hgap>
                        <growablecols>0,2</growablecols>
                        <growablerows>0</growablerows>
                        <object class="sizeritem">
                            <cellpos>0,0</cellpos>
                            <cellspan>1,1</cellspan>
                            <flag>wxALL|wxEXPAND</flag>
                            <border>5</border>
                            <object class="wxStaticBoxSizer">
                                <orient>wxHORIZONTAL</orient>
                                <label>left</label>
                                <object class="sizeritem">
                                    <option>1</option>
                                    <flag>wxALL|wxEXPAND</flag>
                                    <border>5</border>
                                    <object class="wxGrid" name="m_grid4" />
                                </object>
                            </object>
                        </object>
                        <object class="sizeritem">
                            <cellpos>0,1</cellpos>
                            <cellspan>1,1</cellspan>
                            <flag>wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL</flag>
                            <border>5</border>
                            <object class="wxBoxSizer">
                                <orient>wxVERTICAL</orient>
                                <object class="sizeritem">
                                    <option>0</option>
                                    <flag>wxALL</flag>
                                    <border>5</border>
                                    <object class="wxButton" name="m_button4">
                                        <style>wxBU_EXACTFIT</style>
                                        <label>&gt;</label>
                                        <default>0</default>
                                    </object>
                                </object>
                                <object class="sizeritem">
                                    <option>0</option>
                                    <flag>wxALL</flag>
                                    <border>5</border>
                                    <object class="wxButton" name="m_button5">
                                        <style>wxBU_EXACTFIT</style>
                                        <label>&lt;</label>
                                        <default>0</default>
                                    </object>
                                </object>
                            </object>
                        </object>
                        <object class="sizeritem">
                            <cellpos>0,2</cellpos>
                            <cellspan>1,1</cellspan>
                            <flag>wxALL|wxEXPAND</flag>
                            <border>5</border>
                            <object class="wxStaticBoxSizer">
                                <orient>wxHORIZONTAL</orient>
                                <label>right</label>
                                <object class="sizeritem">
                                    <option>1</option>
                                    <flag>wxALL|wxEXPAND</flag>
                                    <border>5</border>
                                    <object class="wxGrid" name="m_grid5" />
                                </object>
                            </object>
                        </object>
                    </object>
                </object>
                <object class="sizeritem">
                    <option>2</option>
                    <flag>wxEXPAND | wxALL</flag>
                    <border>5</border>
                    <object class="wxNotebook" name="m_notebook2">
                        <object class="notebookpage">
                            <label>a page</label>
                            <selected>0</selected>
                            <object class="wxPanel" name="m_panel2">
                                <style>wxTAB_TRAVERSAL</style>
                                <object class="wxBoxSizer">
                                    <orient>wxHORIZONTAL</orient>
                                    <object class="sizeritem">
                                        <option>1</option>
                                        <flag>wxALL|wxEXPAND</flag>
                                        <border>5</border>
                                        <object class="wxTextCtrl" name="m_textCtrl1">
                                            <value></value>
                                        </object>
                                    </object>
                                </object>
                            </object>
                        </object>
                    </object>
                </object>
            </object>
        </object>
        <object class="wxStatusBar" name="m_statusBar1">
            <style>wxST_SIZEGRIP</style>
            <fields>2</fields>
        </object>
    </object>
</resource>

Any help greatly appreciated,

Thanks,

-Jdun

Upvotes: 0

Views: 229

Answers (1)

VZ.
VZ.

Reputation: 22688

There is too much code here to read it all carefully, but one thing that immediately seems suspicious to me is that you don't call $event->Skip() on the event in your on_size handler. The EVT_SIZE handler should almost invariably call Skip() to allow the default handling of the size event to take place, so while it might not explain all of your problems, I'd be surprised if it didn't explain at least some of them.

Upvotes: 1

Related Questions