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

Dear Perl team,

I’m creating this below script that use tk gui Menu to Add, Delete, and Reset users in my environment now I’m doing the form design but could not get it to work like I want to I have tried the forget, destroy however it does not work or maybe I’m doing it wrong.

My Goal is when I click “Add” menu I can do add user in my form and when I click “Delete” menu I want the Add form to be clear and the Delete form will load the same as when I click the “Reset” menu it should clear the Delete form and load cleanly the next form. Can you please show me the way on how to do this. Thank you

#!/usr/local/bin/perl use strict; use warnings; use Tk; use feature 'say'; my $mainwindow = MainWindow->new(); $mainwindow->geometry("600x150"); $mainwindow->title("Add/Delete/Reset Password"); # Disable the window Resize $mainwindow->resizable(0,0); my $main_menu = $mainwindow->Menu(); $mainwindow->configure(-menu => $main_menu); # File my $menu_menu = $main_menu->cascade(-label=>"Menu", -underline => 0, - +tearoff=>0); $menu_menu->command(-label=>"Password Reset for users", -underline= +>0, -command=>\&Show_ResetPassword_menu); $menu_menu->command(-label=>"Add User", -underline=>0, -command=>\& +Show_AddUser_menu); $menu_menu->command(-label=>"Delete User", -underline=>0, -command= +>\&Show_DeleteUser_menu); # About $main_menu->command(-label=>"About", -underline => 0, -command=>sub{$mainwindow->messageBox(-title=> "Ab +out", -message=>"Version 3.0.0", -type => "ok")}); MainLoop(); sub Show_ResetPassword_menu { my $passwordreset_handle_return; my $label_resetp = $mainwindow->Label(-text=>"Password Reset for user +", -width => 40) -> pack ( -side=>'left'); my $entry_resetp = $mainwindow->Entry(-width => 30)->pack(-side => 'le +ft'); $entry_resetp->bind("<Return>", \$passwordreset_handle_return ); my $button = $mainwindow->Button(-text=>"Click to reset", -command => +\$passwordreset_handle_return , -width => 15) -> pack ( -side=>'botto +m' ); $passwordreset_handle_return = sub { say $mainwindow -> messageBox( -message=>"Password Reset", -title=> "Password", -type=>"ok", -icon=>"info"); } } sub Show_AddUser_menu{ my $adduser_handle_return; my $label_adduser = $mainwindow->Label(-text=>"Add user ", -width => 4 +0) -> pack ( -side=>'left'); my $entry_adduser = $mainwindow->Entry(-width => 30)->pack(-side => 'l +eft'); $entry_adduser->bind("<Return>", \$adduser_handle_return); my $button = $mainwindow->Button(-text=>"Click to reset", -command => +\$adduser_handle_return, -width => 15) -> pack ( -side=>'bottom' ); $adduser_handle_return = sub { say $mainwindow -> messageBox( -message=>"Add User", -title=> "ADD", -type=>"ok", -icon=>"info"); } } sub Show_DeleteUser_menu { my $deleteuser_handle_return; my $label_deleteuser = $mainwindow->Label(-text=>"Delete User ", -widt +h => 40) -> pack ( -side=>'left'); my $entry_deleteuser = $mainwindow->Entry(-width => 30)->pack(-side => + 'left'); $entry_deleteuser ->bind("<Return>", \$deleteuser_handle_return); my $button = $mainwindow->Button(-text=>"Click to reset", -command => +\$deleteuser_handle_return, -width => 15) -> pack ( -side=>'bottom' ) +; $deleteuser_handle_return = sub { say $mainwindow -> messageBox( -message=>"Delete User", -title=> "DELETE", -type=>"ok", -icon=>"info"); } }

-when this script load and select the Add menu then click again the Reset menu it will load in the screen form

  • Comment on Resolved: tk widget - How to hide and unhide the forms in my script
  • Download Code

Replies are listed 'Best First'.
Re: tk widget - How to hide and unhide the forms in my script
by Marshall (Canon) on Mar 01, 2017 at 13:17 UTC
    Your code worked well enough for me to see the direction that you are going. Some suggestions:
    • With the pack geometry manager, make frames to put your widgets into. I think here, one frame for the menu buttons and one frame for the display that varies according to the File menu option selected. I highly suspect that some of the spacing problems would be solved by using frames instead of putting all of the widgets into the MainWindow. You can pack and unpack a frame. Try that to make things "disappear" within a window.
    • I re-coded "Show_ResetPassword_menu" to show how to have that communicate with other subs. Note the -textvariable. Note the binding of <Return>.
    • The user interface could be easier. See if you can make one screen with all of the concepts of: add user/update user password/delete user. Normally this sort of screen would stay there until some other menu option is selected, perhaps a menu button for Reports or whatever.One advantage of a GUI is that it can present multiple options at once.
    Hope this helps.
    #!/usr/local/bin/perl use strict; use warnings; use Tk; my $mainwindow = MainWindow->new(); $mainwindow->geometry("600x150"); $mainwindow->title("Add/Delete/Reset Password"); # Disable the window Resize # $mainwindow->resizable(0,0); # Why??? don't need it? my $main_menu = $mainwindow->Menu(); $mainwindow->configure(-menu => $main_menu); # File my $menu_menu = $main_menu->cascade(-label=>"Menu", -underline => 0, - +tearoff=>0); $menu_menu->command(-label=>"Password Reset for users", -underline= +>0, -command=>\&Show_ResetPassword_menu); $menu_menu->command(-label=>"Add User", -underline=>0, -command=>\& +Show_AddUser_menu); $menu_menu->command(-label=>"Delete User", -underline=>0, -command= +>\&Show_DeleteUser_menu); # About $main_menu->command(-label=>"About", -command=>sub{$mainwindow->messageBox(-title=> "Ab +out", -message=>"Version 3.0.0", -type => "ok")}); MainLoop(); my $user; sub password_reset { my $answer = $mainwindow -> messageBox( -message=>"Password Reset for user: $user", -title=> "Password", -type=>"YesNoCancel", -icon=>"info"); if ($answer =~ /yes/i) { # code to reset password goes here.... # whatever log messasges you want print "PASSWORD RESET SUCEEDED: $user\n"; # a log entry? } else { print "PASSWORD RESET ABORTED: $user\n"; # a log entry? } } sub Show_ResetPassword_menu { my $label_resetp = $mainwindow->Label(-text=>"Password Reset for u +ser ", -width => 40) -> pack ( -side=>'left'); my $entry_resetp = $mainwindow->Entry(-width => 30, -textvariable +=>\$user )->pack(-side => 'left'); $entry_resetp->bind("<Return>", \&password_reset); my $button = $mainwindow->Button(-text=>"Click to reset", -command + => \&password_reset , -width => 15) -> pack ( -side=>'bottom' ); } # more code modifications to be done by poster.... sub add_user { my $answer = $mainwindow -> messageBox( -message=>"Add user: $user", -title=> "Password", -type=>"ok", -icon=>"info"); } sub Show_AddUser_menu { my $label_adduser = $mainwindow->Label(-text=>"Add user ", -width +=> 40) -> pack ( -side=>'left'); my $entry_adduser = $mainwindow->Entry(-width => 30)->pack(-side = +> 'left'); # $entry_adduser->bind("<Return>", \$adduser_handle_return); my $button = $mainwindow->Button(-text=>"Click to reset", -command + => \&adduser, -width => 15) -> pack ( -side=>'bottom' ); } sub Show_DeleteUser_menu { my $deleteuser_handle_return; my $label_deleteuser = $mainwindow->Label(-text=>"Delete User ", -widt +h => 40) -> pack ( -side=>'left'); my $entry_deleteuser = $mainwindow->Entry(-width => 30)->pack(-side => + 'left'); $entry_deleteuser ->bind("<Return>", \$deleteuser_handle_return); my $button = $mainwindow->Button(-text=>"Click to reset", -command => +\$deleteuser_handle_return, -width => 15) -> pack ( -side=>'bottom' ) +; $deleteuser_handle_return = sub { $mainwindow -> messageBox( -message=>"Delete User", -title=> "DELETE", -type=>"ok", -icon=>"info"); } }

      Dear Discipulus & Marshall,

      I appreciate your time and effort in reading and sharing some info. I have tried the script you two shared however I still could not achieve my two goal. maybe I rephrase it again hope I can explain it clearly.

      -------

      Item-A.) What I want to do is when I click the option in GUI TK window form " Menu->Add user " it will load 3 objects one for each (Label, Entry, & Button) inside my MainWindow form.

      Item-B.) When I click again the option in my GUI TK window form " Menu-> Reset User " It will clear the old form from Item-A and load new 3 objects again one for each Label, Entry and Button) in my MainWindow.

      This means that before I select new option Menu it will clear my MainWindow form and load option that I have selected. Just like the normal GUI behavior when using some application when clicking other options menu it will clear the previous(old) view and load again the next option that was just selected or click.

      Thank you in advance

        You obviously didn't understand my first point. You need to use more frames. Frames are like invisible boundaries which are packed just like any other object. You have 3 menu choices. I would make 3 frames, one for each choice. Each choice has 3 objects, a label, entry window, button. To display a frame, pack it into Mainwindow or perhaps another frame. To remove a frame from view, unpack it. I don't have time to write the code right now, but that should work. At any time, you will have zero or one of the 3 "choice frames" packed and view-able.

        To clear the entry window, set the -textvariable variable to a null string.

        Try the above and see what happens.

        Update: I used the wrong terminology, instead of "unpack()", use "packForget()". My idea was correct, but name was wrong. Use "packForget" to remove an object from being displayed. I did a quick hack to my previously posted code, only for the "reset password" menu. See Below.

        Click on Menu->password reset option, gives display of the reset objects, enter a user, hit ok on the confirmation pop-up, that will print to stdout and also clear the 3 reset objects in the window. Going through Menu->password reset option again will repeat this behavior. Note the reset to the $user variable.

        Homework for the OP: Make more Frames. Probably a MenuFrame and at perhaps even a "work frame" packed into the MainWindow. You can make a frame for each of the menu options. Then pack() or packForget() those frames into either the "work frame" or the Mainwindow to show or not show them. In my hack I just directly packForget() each of the individual widgets, don't do that. Use a frame to group them together. My code is just "proof of concept", not finished code. There are hide and un-hide options for entire windows.

        #!/usr/local/bin/perl use strict; use warnings; use Tk; my $mainwindow = MainWindow->new(); $mainwindow->geometry("600x150"); $mainwindow->title("Add/Delete/Reset Password"); # Disable the window Resize # $mainwindow->resizable(0,0); # Why??? don't need it? my $main_menu = $mainwindow->Menu(); $mainwindow->configure(-menu => $main_menu); # File my $menu_menu = $main_menu->cascade(-label=>"Menu", -underline => 0, - +tearoff=>0); $menu_menu->command(-label=>"Password Reset for users", -underline= +>0, -command=>\&Show_ResetPassword_menu); $menu_menu->command(-label=>"Add User", -underline=>0, -command=>\& +Show_AddUser_menu); $menu_menu->command(-label=>"Delete User", -underline=>0, -command= +>\&Show_DeleteUser_menu); # About $main_menu->command(-label=>"About", -command=>sub{$mainwindow->messageBox(-title=> "Ab +out", -message=>"Version 3.0.0", -type => "ok")}); my $label_resetp; my $entry_resetp; my $button_resetp; MainLoop(); my $user; #text vasriable sub password_reset { my $answer = $mainwindow -> messageBox( -message=>"Password Reset for user: $user", -title=> "Password", -type=>"YesNoCancel", -icon=>"info"); if ($answer =~ /yes/i) { # code to reset password goes here.... # whatever log messasges you want print "PASSWORD RESET SUCEEDED: $user\n"; # a log entry? } else { print "PASSWORD RESET ABORTED: $user\n"; # a log entry? } $user=''; # clear the user name entry field $label_resetp->packForget(); $entry_resetp->packForget(); $button_resetp->packForget(); } sub Show_ResetPassword_menu { $label_resetp = $mainwindow->Label(-text=>"Password Reset for user + ", -width => 40) -> pack ( -side=>'left'); $entry_resetp = $mainwindow->Entry(-width => 30, -textvariable =>\ +$user )->pack(-side => 'left'); $entry_resetp->bind("<Return>", \&password_reset); $button_resetp = $mainwindow->Button(-text=>"Click to reset", -com +mand => \&password_reset , -width => 15) -> pack ( -side=>'bottom' ); } sub add_user { my $answer = $mainwindow -> messageBox( -message=>"Add user: $user", -title=> "Password", -type=>"ok", -icon=>"info"); } sub Show_AddUser_menu { my $label_adduser = $mainwindow->Label(-text=>"Add user ", -width +=> 40) -> pack ( -side=>'left'); my $entry_adduser = $mainwindow->Entry(-width => 30)->pack(-side = +> 'left'); # $entry_adduser->bind("<Return>", \$adduser_handle_return); my $button = $mainwindow->Button(-text=>"Click to reset", -command + => \&adduser, -width => 15) -> pack ( -side=>'bottom' ); } sub Show_DeleteUser_menu { my $deleteuser_handle_return; my $label_deleteuser = $mainwindow->Label(-text=>"Delete User ", -widt +h => 40) -> pack ( -side=>'left'); my $entry_deleteuser = $mainwindow->Entry(-width => 30)->pack(-side => + 'left'); $entry_deleteuser ->bind("<Return>", \$deleteuser_handle_return); my $button = $mainwindow->Button(-text=>"Click to reset", -command => +\$deleteuser_handle_return, -width => 15) -> pack ( -side=>'bottom' ) +; $deleteuser_handle_return = sub { $mainwindow -> messageBox( -message=>"Delete User", -title=> "DELETE", -type=>"ok", -icon=>"info"); } }
        maybe Tk::NoteBook can be of interest?

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: tk widget - How to hide and unhide the forms in my script
by Discipulus (Canon) on Mar 01, 2017 at 10:07 UTC
    Hello fsmendoza

    first i'm not sure to understand your goal description; maybe you can rephrase it with shorter sentences; english is not my native language and I suspect nor your.

    If you want some form entry to be cleared given some action destroy and forget are not the right way: they are methods related to the GUI composition, not about Entry content.

    You have buttons and entries: rigth? text inside Entries are bound to variables. Like in Entry(-textvariable => \$var,..)

    You must (in the Delete button callback) clear the variable $var

    You can also enable/disable widgets upon some action.

    If this sounds similar with your goal i'll suggest you to try the behaviour of my picwoodpecker Tk program on github: launch the application, click on advanced in the main window (center rigth side of the pane) and play the behaviour of the enable multiple copies part of the advanced new window.

    The multi copies pattern is disabled and will activate only if you check the enable multi copies checkbox: click the checkbox and write some text into the (now enabled) Entry. If you deselect the enable multi copies checkbox the text inside the Entry will disappear. It is this the baheavior you want?

    look at the source code around line 1184 (in the advanced_options sub) and to the following lines. Note that $enable_multiple_copies is the variable bound to the checkbox; here the code (lines 1273-1286) that enable or disable and clear the variable containing the text put in the entry $multi_pattern

    # enable multi copies options if necessary if ($enable_multiple_copies){ map{ $_->configure(-state => 'normal') }($skip_orig_lbl,$skip_orig_chk,$multi_pattern_lbl,$multi_pa +ttern_ent ); } # or disable them and clean values else{ map{ $_->configure(-state => 'disabled') }($skip_orig_lbl,$skip_orig_chk,$multi_pattern_lbl,$multi_pa +ttern_ent ); $skip_orig = 0; $multi_pattern = ''; }

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: tk widget - How to hide and unhide the forms in my script
by fsmendoza (Novice) on Mar 11, 2017 at 05:18 UTC

    Dear Marshall,

    Thank you my code is now working and would like to share to community for reference too. Now when I click the Menu-> reset user or Menu->add the form is doing the clear all window now.

    I can now integrate this script in my version 3 tool and its cool doing in perl TK instead of Visual studio.

    #!/usr/local/bin/perl # Author fsmendoza 2017-March-11 use strict; use warnings; use Tk; my $mainwindow = MainWindow->new(); $mainwindow->geometry("600x150"); $mainwindow->title("Add/Delete/Reset Password"); # Disable the window Resize $mainwindow->resizable(0,0); my $main_menu = $mainwindow->Menu(); $mainwindow->configure(-menu => $main_menu); # Reset user text variable my $label_resetp; my $entry_resetp; my $button_resetp; # Add user text variable my $label_adduser; my $entry_adduser; my $button_adduser; # delete user text variable my $label_deleteuser; my $entry_deleteuser; my $button_deleteuser; #clear all my $clearpass = 0; my $clearadd = 0; my $cleardel = 0; # File my $menu_menu = $main_menu->cascade(-label=>"Menu", -underline => 0, - +tearoff=>0); $menu_menu->command(-label=>"Password Reset for users", -underline= +>0, -command=>\&Show_ResetPassword_menu); $menu_menu->command(-label=>"Add User", -underline=>0, -command=>\& +Show_AddUser_menu); $menu_menu->command(-label=>"Delete User", -underline=>0, -command= +>\&Show_DeleteUser_menu); $menu_menu->command(-label=>"Exit", -underline=>0, -command=>sub{ex +it}); # About $main_menu->command(-label=>"About", -command=>sub{$mainwindow->messag +eBox(-title=> "About", -message=>"Version 3.0.0", -type => "ok")}); MainLoop(); #text variable my $user; #Passwowrd Reset sub password_reset { my $answer = $mainwindow -> messageBox( -message=>"Password Reset for user: $user", -title=> "Password", -type=>"YesNoCancel", -icon=>"info"); if ($answer =~ /yes/i) { # code to reset password goes here.... # whatever log messasges you want print "PASSWORD RESET SUCEEDED: $user\n"; # a log entry? } else { print "PASSWORD RESET ABORTED: $user\n"; # a log entry? } $user=''; # clear the user name entry field } # ADD new user sub adduser { # your code here print "adduser"; } # Delete User sub deleteuser { # your code here print "deleteuser"; } sub clearall { if ($clearpass == 1) { $label_resetp->packForget(); $entry_resetp->packForget(); $button_resetp->packForget(); $clearpass = 0; } if ($clearadd == 1) { $label_adduser->packForget(); $entry_adduser->packForget(); $button_adduser->packForget(); $clearadd = 0; } if ($cleardel == 1) { $label_deleteuser->packForget(); $entry_deleteuser->packForget(); $button_deleteuser->packForget(); $cleardel = 0; } } sub Show_ResetPassword_menu { clearall(); $label_resetp = $mainwindow->Label(-text=>"Password Reset for user + ", -width => 40) -> pack ( -side=>'left'); $entry_resetp = $mainwindow->Entry(-width => 30, -textvariable =>\ +$user )->pack(-side => 'left'); $entry_resetp->bind("<Return>", \&password_reset); $button_resetp = $mainwindow->Button(-text=>"Click to reset", -com +mand => \&password_reset , -width => 15) -> pack ( -side=>'bottom' ); # Enable Password Reset tracking $clearpass = 1; } sub Show_AddUser_menu { clearall(); $label_adduser = $mainwindow->Label(-text=>"Add user ", -width => +40) -> pack ( -side=>'left'); $entry_adduser = $mainwindow->Entry(-width => 30,)->pack(-side => +'left'); $entry_adduser->bind("<Return>", \&adduser); $button_adduser = $mainwindow->Button(-text=>"Click to Add user", +-command => \&adduser, -width => 15) -> pack ( -side=>'bottom' ); # Enable AddUser Reset tracking $clearadd = 1; } sub Show_DeleteUser_menu { clearall(); $label_deleteuser = $mainwindow->Label(-text=>"Delete user ", -wid +th => 40) -> pack ( -side=>'left'); $entry_deleteuser = $mainwindow->Entry(-width => 30)->pack(-side = +> 'left'); $entry_deleteuser->bind("<Return>", \&deleteuser); $button_deleteuser = $mainwindow->Button(-text=>"Click to Delete", + -command => \&deleteuser, -width => 15) -> pack ( -side=>'bottom' ); # Enable Delete Reset tracking $cleardel = 1; }