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

Revered Monks,
It is with humility and penitence that I bring to you my first question. Please forgive my ungraceful coding style and lengthy post, as I am new to this monastery, and am but a lowly electrical engineering student.

I am an engineering intern for the summer, and have been made by my superiors to learn to code in Perl. Among other things, I have to program a GUI that allows the engineers to create a list of solutions to a problem from an established list. They also have to be able to edit/remove any one of these solutions from the same interface.

The issue I'm having is as follows: I (plan to) load the available solutions from a text file into $AvailListbox, from which they can be moved to and from $SelectedListbox using two buttons. If a solution needs to be removed or modified, I have a button that opens a Toplevel into which (for convenience) I pack the already existing $AvailListbox.

When I withdraw the Toplevel, however, $AvailListbox is still present in $MW, but can no longer be accessed as an element thereof. In other words, any subroutine I try to call using $AvailListbox->curselection() does not work on the selection in $MW, but rather in the Toplevel, even after it has been withdrawn. I'm wondering how I would go about restoring the "control" over $AvailListbox to $MW. And hopefully that makes sense.

Here are some relevant sections, with most of the formatting calls in pack() or widget creations removed, for readability. If you paste all the snippets of code together, it should reproduce the same scenario as I mention above.

Here I create $AvailListbox, which holds the available solutions.
#!/usr/local/bin/perl use warnings; use strict; use Tk; # Predeclaring the subroutines and variables sub initialize_step_selection(); sub select_soln_step(); sub deselect_soln_step(); sub modify_remove_step_dialog(); # Building the GUI skeleton, i.e. predeclaring some widgets my $MW = MainWindow->new; my $StepFrame; my $AvailListbox; my $SelectListbox; # Run the subroutines initialize_step_selection(); MainLoop(); # Creates the solutions frame, and its contents sub initialize_step_selection() { # Frame for selecting solutions $StepFrame = $MW->Frame(); $StepFrame->pack(-fill => 'both'); # Scrollbars for available solutions my $AvailScroll = $StepFrame->Scrollbar(-orient => 'vertical +'); # Listbox of available solutions $AvailListbox = $StepFrame->Listbox(-yscrollcommand => ['set +' => $AvailScroll]); $AvailListbox->pack(-fill => 'y', -side => 'left'); $AvailScroll->configure(-command => ['yview' => $AvailLis +tbox]); $AvailScroll->pack(-fill => 'y',-side => 'left'); $AvailListbox->insert('end', "Just", "for", "testing", "purposes") +; # Scrollbar for selected solutions my $SelectScroll = $StepFrame->Scrollbar(-orient => 'vertica +l'); # Listbox of selected solutions $SelectListbox = $StepFrame->Listbox(-yscrollcommand => ['se +t' => $SelectScroll]); $SelectListbox->pack(-fill => 'y', -side => 'left'); $SelectScroll->configure(-command => ['yview' => $SelectL +istbox]); $SelectScroll->pack(-fill => 'y',-side => 'left'); # Select/Deselect solutions buttons my $SelectStep = $StepFrame->Button(-text => ">",-command + => sub{select_soln_step();}); $SelectStep->pack(); my $DeselectStep = $StepFrame->Button(-text => "<",-command + => sub{deselect_soln_step();}); $DeselectStep->pack(); my $ModRmvStep = $StepFrame->Button( -text => "Modify/Remove a Step", -command => sub{modify_remove_step_dialog();} ); $ModRmvStep->pack( -padx => 2, -pady => 3); } # Closing initialize_step_selection()
And then I repack $AvailListbox in the Toplevel here:
sub modify_remove_step_dialog() { my $ModRmvStep = $MW->Toplevel(); $ModRmvStep->title("Modifier une étape"); my $MRSFrame1 = $ModRmvStep->Frame(-label => "Sélectionnez u +ne étape à modifier"); $MRSFrame1->pack(-fill => 'both'); # Listbox of available solutions my $StepModRmvScroll = $MRSFrame1->Scrollbar(-orient => 'ver +tical'); $AvailListbox = $MRSFrame1->Listbox(-yscrollcommand => ['set +' => $StepModRmvScroll]); $AvailListbox->pack(-fill => 'both', -side => 'left +'); $AvailListbox->insert('end', "Just", "for", "testing", "purposes") +; # Configuring available listbox scrollbars $StepModRmvScroll->configure(-command => ['yview' => $Ava +ilListbox]); $StepModRmvScroll->pack(-fill => 'y', -side => 'left') +; my $MRSFrame2 = $ModRmvStep->Frame(); $MRSFrame2->pack(-fill => 'both'); my $MRSMod = $MRSFrame2->Button(-text => 'Rien'); $MRSMod->pack(); my $MRSCancel = $MRSFrame2->Button(-text => 'Rien'); $MRSCancel->pack(); my $MRSRmv = $MRSFrame2->Button(-text => 'Cancel', -command + => sub{$ModRmvStep->withdraw;}); $MRSRmv->pack(); }
Now, when I call sub select_soln_step() by pushing the top button in the $MW, it moves the selected solution from the left box to the right one. The bottom button does the opposite:
# This subroutine will move the selected solution from the AvailListbo +x # to the SelectListbox sub select_soln_step() { # Get the contents of the current selection my $selIndex = $AvailListbox->curselection(); # If no item is selected, we do nothing. unless($selIndex eq "") { my $selection = $AvailListbox->get($selIndex); # Remove the selected value from the AvailListbox, and add it +to the SelectListbox $SelectListbox->insert('end', $selection); $AvailListbox->delete($selIndex); } } # This subroutine will move the selected solution from the SelectListb +ox # to the AvailListbox sub deselect_soln_step() { # Get the contents of the current selection my $selIndex = $SelectListbox->curselection(); # If no item is selected, we do nothing. unless($selIndex eq "") { my $selection = $SelectListbox->get($selIndex); # Remove the selected value from the AvailListbox, and add it +to the SelectListbox $AvailListbox->insert('end', $selection); $SelectListbox->delete($selIndex); } }
However, once the Toplevel has been opened, the button to move the solutions from the left box to the right one no longer works on the curselection(); in $MW, but on the curselection(); in the Toplevel... Is there any way to give control over $AvailListbox to $MW?

Replies are listed 'Best First'.
Re: Tk - Giving control over a Widget to $MW from a Toplevel
by lamprecht (Friar) on Aug 13, 2009 at 12:16 UTC
    Hi,

    you are reusing variable $AvailListbox. So after it gets assigned a reference to the new Listbox instance that is what it points to. You need seperate variables to hold references to different widgets. I do not see why you need the second Listbox instance at all. Why do you want an extra Toplevel for the content editing part?
    As a side note: You can create scrolled widgets much easier like so: $mw->Scrolled('Listbox', @args)

    Cheers, Christoph