Application Start-up Sequencing

Context: Python-2.7.5 and wxPython-3.0.0.0.

   When the application is invoked the main module (pw.py) imports the module
login.py ("from login import LoginDialog") and calls "class
PwSplashScreen(wx.SplashScreen)" (modifed from that of the demo's Main.py).

   PwSplashScreen()'s ShowMain() method calls LoginDialog:

     def ShowMain(self):
         frame = LoginDialog(None, -1, "")
         frame.Show()
         if self.fc.IsRunning():
             self.Raise()

   This all works as intended. However, I'm having difficulty displaying the
MainFrame(wx.Frame) when LoginDialog()'s 'OK' button is selected:

     def Login(self, event):
         frame = MainFrame(None, -1, "")

does not work. How do I correctly reference MainFrame from an imported
module/class?

Rich

Hard to tell what you’re doing without seeing some code… either upload as a file or pasted to something like pastebin.com

···

On Thursday, July 10, 2014 12:26:48 PM UTC-7, fuzzydoc wrote:

Context: Python-2.7.5 and wxPython-3.0.0.0.

When the application is invoked the main module (pw.py) imports the module

login.py (“from login import LoginDialog”) and calls "class

PwSplashScreen(wx.SplashScreen)" (modifed from that of the demo’s Main.py).

PwSplashScreen()'s ShowMain() method calls LoginDialog:

 def ShowMain(self):

     frame = LoginDialog(None, -1, "")

     frame.Show()

     if self.fc.IsRunning():

         self.Raise()

This all works as intended. However, I’m having difficulty displaying the

MainFrame(wx.Frame) when LoginDialog()'s ‘OK’ button is selected:

 def Login(self, event):

     frame = MainFrame(None, -1, "")

does not work. How do I correctly reference MainFrame from an imported

module/class?

Rich

Yep; thought it would be difficult to explain. Code's attached in a .zip
file in case you can't un-tar a file.

Rich

code.zip (99.1 KB)

···

On Thu, 10 Jul 2014, Nathan McCorkle wrote:

Hard to tell what you're doing without seeing some code... either upload as
a file or pasted to something like pastebin.com

When asking about why something is not working, definitely provide the
error message you get, or, if you didn't get an error, the behavior you
observe. "Does not work" doesn't tell us anything.

Did you call frame.Show() on this? or did it say it does not know what
MainFrame is?

···

On Thu, Jul 10, 2014 at 3:26 PM, Rich Shepard <rshepard@appl-ecosys.com> wrote:

    def Login(self, event):
        frame = MainFrame(None, -1, "")

does not work.

When asking about why something is not working, definitely provide the
error message you get, or, if you didn't get an error, the behavior you
observe. "Does not work" doesn't tell us anything.

Che,

   Sorry. The message is:

Traceback (most recent call last):
   File "/home/rshepard/development/permitwatch/src/login.py", line 67, in
Login
     frame = MainFrame(None, -1, "")
NameError: global name 'MainFrame' is not defined

Did you call frame.Show() on this? or did it say it does not know what
MainFrame is?

   Yes, frame.Show() is in the code. Python cannot find MainFrame called from
the imported module's class LoginDialog().

Rich

···

On Thu, 10 Jul 2014, C M wrote:

First of all, I had to change your splash screen bitmap loading line to this (your code assumed the user was running pw.py from the same directory):
bmp = wx.Image(opj(os.path.abspath(os.path.join(os.path.split(file)[0],“bitmaps”,“splash.png”)))).ConvertToBitmap()

Also, the splashscreen calls ShowMain, but you haven’t instantiated MainFrame so you can’t pass the object along when you instantiate LoginDialog.

Either provide a callback function to LoginDialog that will be run on successful user/password entry… or pass a MainFrame object (that hasn’t been shown) to LoginDialog init… then save that as a class variable, and call Show on that class variable in the Login method in login.py

···

On Thursday, July 10, 2014 1:25:15 PM UTC-7, fuzzydoc wrote:

On Thu, 10 Jul 2014, Nathan McCorkle wrote:

Hard to tell what you’re doing without seeing some code… either upload as

a file or pasted to something like pastebin.com

Yep; thought it would be difficult to explain. Code’s attached in a .zip

file in case you can’t un-tar a file.

Rich

First of all, I had to change your splash screen bitmap loading line to
this (your code assumed the user was running pw.py from the same directory):
bmp =
wx.Image(opj(os.path.abspath(os.path.join(os.path.split(__file__)[0],"bitmaps","splash.png")))).ConvertToBitmap()

Nathan,

   Thank you.

Also, the splashscreen calls ShowMain, but you haven't instantiated
MainFrame so you can't pass the object along when you instantiate
LoginDialog.

Either provide a callback function to LoginDialog that will be run on
successful user/password entry.

   When I have the splash screen ShowMain() call the main frame, e.g.,

     def ShowMain(self):
         frame = MainFrame(None, -1, "")
         frame.Show()
         if self.fc.IsRunning():
             self.Raise()

that's what is displayed when the splash screen times out or is closed by
clicking on it. If I correctly understand what you're telling me, I need to
call LoginDialog() from within MainFrame() with the dialog box in modal
mode. That's what I tried earlier without success. I'll try again.

Thanks,

Rich

···

On Thu, 10 Jul 2014, Nathan McCorkle wrote:

This is what I'm trying to do from within MainFrame():

dlg = LoginDialog(self, -1, "")
         dlg.ShowModal()
         dlg.EndModal(0)

   When the 'OK' button is pressed, python reports '*** Error in ython':
corrupted double-linked list: 0x095eb2c0 ***' regardless of the last line's
method (EndModal, Destroy).

Rich

···

On Thu, 10 Jul 2014, Nathan McCorkle wrote:

Either provide a callback function to LoginDialog that will be run on
successful user/password entry ...

Nathan/Che:

   Previous applications I wrote with wxPython did not require user access
control; the main frames were wx.Notebooks and each tab was imported from an
external module.

   So, adding the access control dialog is a learning experience for me. I've
been looking for examples but have not found any. The demo, Main.py, is
great; I'm learning a lot from it. But, it does not provide me with an
example of how to invoke the application with a login dialog which then
opens the MainFrame upon success. (The login 'OK' method is empty now and
will have the access control code added after I get the display working
correctly.)

   Pointers to code examples would be much appreciated.

Rich

···

On Thu, 10 Jul 2014, Nathan McCorkle wrote:

Either provide a callback function to LoginDialog that will be run on
successful user/password entry... or pass a MainFrame object (that hasn't
been shown) to LoginDialog init... then save that as a class variable, and
call Show on that class variable in the Login method in login.py

Rich, I don't know any examples offhand, but you might have success
Googling around for it, but I sort of doubt you will, but who knows.

That said, possibly what Nathan was suggesting, and something that seems
reasonable to me, though you should test it to see this works, is this:

1. Start the main frame (MainFrame) as the top level app, but don't yet
call .Show() on it. It now exists, but is not shown

2. In the MainFrame's __init__ method you would call the LoginDialog and
show it modally. When you do that, you will should pass in "self" as the
parent for the LoginDialog; this will mean parent = MainFrame in the
LoginDialog.

3. You can also make a class-wide reference to the MainFrame within
LoginDialog's init method by doing:

self.mainFrame = parent

And now you can refer to the MainFrame from any method within LoginDialog.
(that is just one way to do this. You could also use .GetTopLevelWindow(),
or GetParent(), etc.)

At this point the user should just see the LoginDialog shown (modally)..

4. On the LoginDialog's OK handler, if the password/etc are correct, then
you can call self.mainFrame.Show(), and then, voila, the MainFrame will be
visible. You can then also Destroy() the dialog.

The basic idea here, to refresh you memory, is that windows on screen often
need to refer to or affect other windows on screen, but if they are in
different classes there needs to be some way to do that, to "refer to" each
other. Ways I've seen are:

1. Pass in "self" as an argument such as suggested above, when creating a
new instance of a window.
2. Go right to the top: use .GetParent() or wx.GetTopLevelParent() or
maybe GetApp()
3. Use the PubSub module to "broadcast" messages into the air for other
objects to "listen for".

I get the sense that (3) is the most decoupled and therefore most correct,
good coding practices-wise, but I often find it easier to use something
more like (1) or (2), though you don't want to ever get into anything that
looks like:

target_object = self.GetParent().GetParent().GetParent().GetParent()

(though I may have a few almost that bad in some of my code, but it's not
good).

Che

···

On Thu, Jul 10, 2014 at 7:26 PM, Rich Shepard <rshepard@appl-ecosys.com> wrote:

On Thu, 10 Jul 2014, Nathan McCorkle wrote:

Either provide a callback function to LoginDialog that will be run on

successful user/password entry... or pass a MainFrame object (that hasn't
been shown) to LoginDialog init... then save that as a class variable, and
call Show on that class variable in the Login method in login.py

Nathan/Che:

  Previous applications I wrote with wxPython did not require user access
control; the main frames were wx.Notebooks and each tab was imported from
an
external module.

  So, adding the access control dialog is a learning experience for me.
I've
been looking for examples but have not found any. The demo, Main.py, is
great; I'm learning a lot from it. But, it does not provide me with an
example of how to invoke the application with a login dialog which then
opens the MainFrame upon success. (The login 'OK' method is empty now and
will have the access control code added after I get the display working
correctly.)

  Pointers to code examples would be much appreciated.

Rich, I don't know any examples offhand, but you might have success
Googling around for it, but I sort of doubt you will, but who knows.

   Been there, done that. Found nothing despite trying different search term
strings.

That said, possibly what Nathan was suggesting, and something that seems
reasonable to me, though you should test it to see this works, is this:

   Ah, ha! I was not seeing the details. Thank you for that!

The basic idea here, to refresh you memory, is that windows on screen
often need to refer to or affect other windows on screen, but if they are
in different classes there needs to be some way to do that, to "refer to"
each other. Ways I've seen are:

1. Pass in "self" as an argument such as suggested above, when creating a
new instance of a window.
2. Go right to the top: use .GetParent() or wx.GetTopLevelParent() or
maybe GetApp()
3. Use the PubSub module to "broadcast" messages into the air for other
objects to "listen for".

I get the sense that (3) is the most decoupled and therefore most correct,
good coding practices-wise, but I often find it easier to use something
more like (1) or (2), though you don't want to ever get into anything that
looks like:

   I used (3) in a previous application but would agree that (1) would be
simpler and more certain for me to implement.

Much appreciated,

Rich

···

On Thu, 10 Jul 2014, C M wrote:

Hi Rich,

Didn't read the full thread, but in my app I use a login dialog.

I call my doLogin method from within the my wxApp.OnInit method.

In the doLogin method I do:

             with dlogin.Login(None) as dlg:
                 if dlg.ShowModal() == wx.ID_OK:
                     self.loggedInUser = c.loggedInUser
                     # etc etc
                 else:
                     msg = _(u"You canceled the login!")
                     pub.sendMessage(pTopics.infoBar.showMsg,
                                     msg=msg)

                 # if login o.k. continue with OnInit which in turn will show the mainframe
                 # if not o.k. I show a message and sys.exit

Note that I use 'with' for all my dialogs (available since 2.8.11), this way you don't have to worry about destroying them.

Hope this helps
Werner

Werner,

   Thank you.

Rich

···

On Fri, 11 Jul 2014, Werner wrote:

I call my doLogin method from within the my wxApp.OnInit method.

In the doLogin method I do:

           with dlogin.Login(None) as dlg:
               if dlg.ShowModal() == wx.ID_OK:
                   self.loggedInUser = c.loggedInUser
                   # etc etc
               else:
                   msg = _(u"You canceled the login!")
                   pub.sendMessage(pTopics.infoBar.showMsg,
                                   msg=msg)

               # if login o.k. continue with OnInit which in turn will show the mainframe
               # if not o.k. I show a message and sys.exit

Hope this helps

Hi Rich,

I thought I had written about this sort of thing long ago on my blog, but it seems that was just one of my ideas that never got done. So I whipped up a really simple example that is attached. It shows how to show a login dialog that checks against a really dumb password. You will have to add some additional smarts to it, such as actually checking a password hash and perhaps locking the user out after too many bad logins.

Hope that helps.
Mike

wx_login.py (2.94 KB)

Mike,

   Thank you!

   I had assumed that many wxPython applications needed access control so not
finding examples in tutorials, demos, or multiple Web search terms surprised
me.

   Of course I'll add the middleware checking that the username and password
match what are in the Users table of the database. My focus is on creating
the necessary wxPython UI components. Once they all display correctly and
navigation works as intended I'll start connecting the widgets to the
database tables using SQLAlchemy.

Much appreciated,

Rich

···

On Fri, 11 Jul 2014, Mike Driscoll wrote:

I thought I had written about this sort of thing long ago on my blog, but
it seems that was just one of my ideas that never got done. So I whipped
up a really simple example that is attached. It shows how to show a login
dialog that checks against a really dumb password. You will have to add
some additional smarts to it, such as actually checking a password hash
and perhaps locking the user out after too many bad logins.

Something similar using a splash, login, registration wizard posted not too
long ago. https://mail.google.com/mail/u/0/#inbox/1459ecae039365f1

That post got me motivated to mess around with a login framework like
Mike's but with more of the stuff the OP had. I should look at that again.

Nathan, Che, Werner, Mike, Dev Player:

   Thank you all for your suggestions and other comments. I have it working
correctly now. Briefly, PwApp(wx.App) calls the splash screen, the login
dialog, then the main frame.

Much appreciated gentlemen,

Rich

···

On Thu, 10 Jul 2014, Rich Shepard wrote:

When the application is invoked the main module (pw.py) imports the module
login.py ("from login import LoginDialog") and calls "class
PwSplashScreen(wx.SplashScreen)" (modifed from that of the demo's Main.py).