http://qs321.pair.com?node_id=290475

I needed a simple login dialog from my main program, and decided to try WxPerl. Its mostly derived from Jouke's Tutorial examples, but I needed to figure out how to add a couple of other things to it. I require this module only if needed, since I know in advance some user/passwords, and the module portion of the code is installed somewhere in @INC as LoginDialog.pm.

TBD: I gather from mailing archives that since I'm setting the focus on a text control before the window is opened, that it might be better to set it in an EVT_UPDATE_UI handler (though it works as-is for me), but I'm not quite sure how to go about that...help is appreciated :-)

Updated w/PodMaster's comments as I understand them. The change in SetFocus and use of EVT_UPDATE_UI became necesssary after the change from a Frame to a Dialog. Also, it's interesting that I don't even have to call Wx's MainLoop now...

Update: Agghhh, EVT_UPDATE_UI broke it. I just don't understand how to use that event handler yet...

Update: I think it works now...they only other thing I'd like to do is replace that $done flag in the code with something so that the handler uninstalls itself...watch this space...

Changed EVT_UPDATE_UI to EVT_ACTIVATE. The former handler was being called over one hundred times, while the latter is only called ~3 times. Still it'd be nice if it were possible to have a handler uninstall itself...not sure if that's possible.

Final update(!): Found out how to disconnect event handler, but had to change back to EVT_UPDATE_UI, as the focus wouldn't get set in EVT_ACTIVATE if I disconnected it while executing the handler.

#!/usr/bin/perl # # For simple login dialog # See example at bottom of file # use strict; use Wx; ########################################################### # # Extend the Frame class to our needs # package Wx::Perl::LoginDialog; use Wx qw( wxTE_PASSWORD wxTE_PROCESS_ENTER ); use Wx::Event qw( EVT_BUTTON EVT_TEXT_ENTER EVT_UPDATE_UI ); use base qw/Wx::Dialog/; sub new { my $class = shift; my $user = shift; my $passwd = shift; my $self = $class->SUPER::new(@_); $self->{user_out} = $user; $self->{passwd_out} = $passwd; $self->{UserLabel} = Wx::StaticText->new( $self, # parent -1, # id "User:", # label [10, 30] # position ); $self->{PasswdLabel} = Wx::StaticText->new( $self, # parent -1, # id "Password:",# label [10, 50] # position ); $self->{User} = Wx::TextCtrl->new( $self, -1, ${$self->{user_out}} || "", [70,30], [70,20], wxTE_PROCESS_ENTER, ); $self->{Passwd} = Wx::TextCtrl->new( $self, 2, ${$self->{passwd_out}} || "", [70,50], [70,20], wxTE_PASSWORD | wxTE_PROCESS_ENTER, ); $self->{Login} = Wx::Button->new( $self, 1, "Login", [20,90], ); $self->{Cancel} = Wx::Button->new( $self, 2, "Cancel", [90,90], ); EVT_UPDATE_UI( $self, -1, sub { $self->{Passwd}->SetFocus if $$user; EVT_UPDATE_UI($self, -1, undef); } ); EVT_BUTTON( $self, # Object to bind to 1, # ButtonID \&Login ); EVT_BUTTON( $self, # Object to bind to 2, # ButtonID \&CancelLogin # Subroutine to execute ); EVT_TEXT_ENTER( $self, -1, \&Login ); $self->{Passwd}->SetFocus if $$user; return $self; } sub Login { my $self = shift; ${$self->{user_out}} = $self->{User}->GetValue; ${$self->{passwd_out}} = $self->{Passwd}->GetValue; $self->EndModal(1); } sub CancelLogin { my $self = shift; $self->EndModal(0); } ########################################################### # package Wx::Perl::LoginWindow; use base qw(Wx::App); # Inherit from Wx::App use Wx qw(wxCAPTION wxSYSTEM_MENU); our ($user, $passwd, $ok); sub BindVars { my $self = shift; ($user, $passwd, $ok) = @_; $self; } sub OnInit { my $self = shift; $$ok = Wx::Perl::LoginDialog->new( $user, $passwd, undef, # Parent window -1, # Window id 'Login', # Title [200,200], # position X, Y [200,150], # size X, Y wxCAPTION | wxSYSTEM_MENU )->ShowModal; 0; } package LoginDialog; sub get_login { shift; my $ok; my $app = eval { Wx::Perl::LoginWindow->BindVars(@_, \$ok)->new }; die $@ unless $@ =~ "OnInit must return a true return value"; $ok; } 1; ########################################################### # # The main program # package main; unless( caller ){ if( @ARGV ) { LoginDialog->get_login(\my ($user, $passwd)); die "USER $user\n\nPASS $passwd\n\n"; } else { # Use defaults if available: my ($user, $passwd) = @ARGV; # Default either one if desired $user = 'username'; unless ($user and $passwd) { # require LoginDialog; LoginDialog->get_login(\($user, $passwd)); } } }

Replies are listed 'Best First'.
Re: WxPerl Login Dialog
by PodMaster (Abbot) on Sep 10, 2003 at 21:32 UTC
    Since you're using a wxFrame, and subsequently on Show(1)ing, simply SetFocus after you show (if you're concerned, but I wouldn't worry about it).

    On the other hand, it seems to me like you should be subclassing wxDialog, and you using ->ShowModal(). Also, you may wish to pass style along the lines of wxCAPTION|wxSYSTEM_MENU and maybe add a cancel button (goes along with the whole dialog idea).

    Also, a good name for this baby would be Wx::Perl::LoginWindow (in the tradition of Wx::Perl::Carp,Wx::Perl::TreeChecker ... it's Mattia approved ;D)

    And on a final note, instead of those comments at the bottom, I think code might be better (:

    package main; unless( caller ){ if( @ARGV ) { LoginDialog->get_login(\my ($user, $passwd)); die "USER $user\n\nPASS $passwd\n\n"; } else { # Use defaults if available: my ($user, $passwd); # Default either one if desired $user = 'username'; unless ($user and $passwd) { # require LoginDialog LoginDialog->get_login(\($user, $passwd)); } } }

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

      Thanks for your comments. As you may guess, I've barely started with Wx, so I didn't even notice Wx::Dialog yet :-) Now that I've tried it, there seems to be a problem with not creating any top level window within Wx::App::OnInit. I have this:
      sub OnInit { my $self = shift; $$cancel = LoginWindow->new( $user, $passwd, undef, # Parent window -1, # Window id 'Login', # Title [200,200], # position X, Y [200,150], # size X, Y wxCAPTION | wxSYSTEM_MENU )->ShowModal; }
      If ShowModal returns true, the app hangs, if it returns false, then I get this error from this code within Wx::App:
      my $ret = Wx::_App::Start($this,$this->can('OnInit')); Wx::_croak( 'OnInit must return a true return value' ) unless $ret || Wx::wxMAC(); # why does OnInit always return 0 on M +ac?
      In the WxWindows documentation, it says to return a false value from OnInit to exit the application. I don't know why WxPerl would require a true value; it seems like a bug to me. I think I would like to just set $$cancel and then return false from OnInit unconditionally.

      Update: Ahh, if I wrap the call to the App constructor in an eval, I don't get the error message, and I can filter for that particular message in $@, but I still think returning false from OnInit should be perfectly valid.

        If ShowModal returns true, the app hangs...
        That's because you've turned control over to wxWindows, but there is nothing telling the app to die (basically, you need to $app->SetTopWindow($dialog) if you want the application to exit when the window is destroyed).

        but I still think returning false from OnInit should be perfectly valid.
        I'd say I agree with you (even though I've never had the need/urge to do that), but I suspect there might be a real good reason for this (a carp would be fine with me -- you should definetly inquire on the list).

        update: I almost forgot, it's called wxPerl, not WxPerl ;)

        MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
        I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
        ** The third rule of perl club is a statement of fact: pod is sexy.