Search code examples
perlwindowglade

Multiple instances of window in perl, using gtk builder


To get started, I am inexperienced scripting in perl, or using gtk, but I've been googling and researching how to for the past two or so weeks. It was difficult just figuring out where I could find the PMs for gtk on windows, and then even more so getting it to some semblance of 'working'. However, there have of course still been problems.

Skipping the above, I have two problems. For a slight bit of relevant background, I am trying to port an mirc script over to xchat, but to do that I obviously need to learn a whole 'nother language.. but anyway. The two problems are thus:

  1. The window consists of several buttons, labels, and text areas. However, the window is.. 'frozen' in time unless one clicks on the title bar and holds. Clicking a button does nothing, not even to show it has been clicked, unless of course the title bar is clicked and held.

  2. I have no idea how to initialize multiple instances of the same window. I have of course tried researching, but it's either not out there or I just haven't found it yet. To be specific.. My mirc script requires that multiple instances be allowed to exist, but I need the buttons for the specific instance to only affect that instance.. and so on.

In regards to problem 1, I do not know if the .xml glade file is important, so I won't post it immediately. I will however post the code that calls it:

my $glade_file = "window3.xml";
my $glade = Gtk2::Builder->new();
$glade->add_from_file($glade_file);

sub charopen {
    my $window = $glade->get_object('window1');
    $glade->connect_signals(undef, $window);
    my $hp_cur = $glade->get_object('HP_Cur');
    $window->set("title"=>$_[0][1]);
    $hp_cur->set("label"=>$ini->val($_[0][1],"HPC"));
    $window->show();
}

Solution

  • Graphical interface design relies on event processing. To work properly, it is important to reserve a thread to process user events (keyboard, mouse clicks...). That is the aim of calling Gtk2->main() when user interface is ready to accept user interaction.

    To make the event thread exiting the event loop, an event callback method may invoke Gtk2->main_quit()

    The Gtk2::Builder creates Gtk widget hierarchy from XML. To get multiple instance of the same window, you have to create a builder for each one.

    Then your event callback methods has to get information about which window has sent the event, and the $user_data parameter may be used in that aim.

    Here is a code proposal with a simple button click callback which use Perl reference to a hash so you can pass as many information as you want between window creator code and event callbacks:

    sub createWindow($)
        my $windowTitle = $_[0];
        my $windowBuilder = Gtk2::Builder->new();
        $windowBuilder->add_from_file($glade_file);
        my $window = $windowBuilder->get_object('window1');
        my $hp_cur = $windowBuilder->get_object('HP_Cur');
    
        # Create hash with data (alternative: use Class::Struct for better code)
        my %window_user_data = {
            "title" => $windowTitle,
            "window" => $window,
            "hp_cur" => $hp_cur };
        # Pass hash reference as user data
        $windowBuilder->connect_signals(\%window_user_data);
    
        # prepare interface: set data model into view and then...
        $window->show();
    }
    
    # Click callback method defined on a button in window
    sub button_click_callback($$) {
        my $button = $_[0];
        my $window_user_data_ref = $_[1];
        # get back data model from view
        print "Click received from button on "
           . $window_user_data_ref->{"title"} . "\n";
    }
    

    There is another way to handle callbacks per window but it requires more Perl skills: you can design a Perl package to create an object instance for a specific window, and use $windowbuilder->connect_signals ($user_data, $windowcallbackinstance). In that case, such an object is called controller, and you have built your graphical interface based on Model-View-Controller (MVC) pattern.