954,525 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

wxPython Events help

Hey guys,

I have made a small program called 'Py-mailer' which allows you to login with your Gmail credentials and send text-only messages to anyone. I uploaded it on SourceForge( http://www.tinyurl.com/m4ans4 ).

The next step I had to take was to make a GUI for it. So, I started with wxPython:

import wx

window=wx.App()

class pymailer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Pymailer",size=(500,500))

        panel=wx.Panel(self,-1)

        menu=wx.MenuBar()
        items=wx.Menu()
        
        items.Append(201,"Quit")
        self.Bind(wx.EVT_LEFT_DOWN,self.Quit,id=201)

        menu.Append(items,"File")
        self.SetMenuBar(menu)

        wx.StaticText(panel,-1,"Please enter your Gmail login ID: ",pos=(10,10))
        wx.StaticText(panel,-1,"Please enter your Gmail login password:\n(will not be stored)",pos=(10,40))

        username=wx.TextCtrl(panel,101,"Login ID",pos=(220,10))
        password=wx.TextCtrl(panel,102,"Password",pos=(220,40))

        self.Centre()
        self.Show()

    def Quit(self,event):
        self.Close()    

pymailer()
window.MainLoop()


But, on clicking 'Quit' in the 'File' menu, nothing happens! I think it is because in line 29, I have not passed the ID of the event, so how do I pass the ID? Or, is because of some thing else?

Thanks

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

You need to bind the event to the menu, not left_click. Try self.Bind(wx.EVT_MENU,self.Quit,id=201) instead of
self.Bind(wx.EVT_LEFT_DOWN,self.Quit,id=201)

winmic
Light Poster
33 posts since Jun 2009
Reputation Points: 26
Solved Threads: 8
 

Change to this.

items.Append(201,"Quit")
self.Bind(wx.EVT_MENU,self.Quit,id=201)
snippsat
Practically a Posting Shark
808 posts since Aug 2008
Reputation Points: 353
Solved Threads: 294
 
You need to bind the event to the menu, not left_click. Try self.Bind(wx.EVT_MENU,self.Quit,id=201) instead of self.Bind(wx.EVT_LEFT_DOWN,self.Quit,id=201)

Thanks mate, it worked! ;)

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

Thanks snippsat, it worked! ;)

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

I have advanced till here:

import smtplib
import time
import os
import wx

window=wx.App()

class pymailer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Pymailer",size=(500,500))

        panel=wx.Panel(self,-1)

        menu=wx.MenuBar()
        items=wx.Menu()
        
        items.Append(201,"Quit")
        self.Bind(wx.EVT_MENU,self.Quit)

        menu.Append(items,"File")
        self.SetMenuBar(menu)

        wx.StaticText(panel,-1,"Welcome to Py-mailer.\nLogin with your Gmail credentials and you can send a text-only email to anyone quickly and easily.",pos=(10,10))
        wx.StaticText(panel,-1,"Please enter your Gmail login ID: ",pos=(10,100))
        wx.StaticText(panel,-1,"Please enter your Gmail login password:\n(will not be stored)",pos=(10,130))

        username=wx.TextCtrl(panel,101,"Login ID",pos=(220,100))
        password=wx.TextCtrl(panel,102,"Password",pos=(220,130))

        login=wx.Button(panel,103,label="Login",pos=(10,170))
        self.Bind(wx.EVT_LEFT_DOWN,self.login)

        self.Centre()
        self.Show()

    def Quit(self,event):
        self.Close()

    def login(self,event):
        s=smtplib.SMTP("smtp.gmail.com",587)
        s.starttls()

        try:
            wx.StaticText(panel,-1,"Logging in...",pos=(10,200))
            s.login(user,passw)
        except:
            wx.StaticText(panel,-1,"Failed",pos=(10,220))

pymailer()
window.MainLoop()


But, after entering the login details and clicking on 'Login', nothing happens. Any help?

Thank you

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

use self.Bind(wx.EVT_BUTTON, self.login) instead of self.Bind(wx.EVT_LEFT_DOWN,self.login)

also everywhere you put 'panel' put 'self.panel' instead so it can be accessed during login

winmic
Light Poster
33 posts since Jun 2009
Reputation Points: 26
Solved Threads: 8
 

What's the difference between EVT_BUTTON and EVT_LEFT_DOWN ?

Also, can you explain to me why I should use self.panel ?

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

EVT_LEFT_DOWN doesn't work because wx.Button doesn't propagate EVT_LEFT_DOWN, it will only propagate wx.EVT_BUTTON. The thing is that objects like Button and ListCtrl will only propagate certain events, not all events. Take a look at the wxpython docs to see what events are used. http://www.wxpython.org/docs/api/wx.Button-class.html

As for using self.panel, in the constructor the variable panel is created, but when the constructor is done, panel is also destroyed. So in the login function, when 'panel' is used it errors because panel was destroyed. Using self.panel will allow access to the variable throughout the class until the class is destroyed. I'm not sure if I'm explaining it well enough, but if there are lots of tutorials, ect. on class structure floating about the web that can help.

Good luck, and I'm looking forward to seeing this in action!

winmic
Light Poster
33 posts since Jun 2009
Reputation Points: 26
Solved Threads: 8
 

winmic, if I use panel , it gives this error:Traceback (most recent call last):
File "C:\Documents and Settings\Sravan\My Documents\Sravan\PYTHON\GUI.py", line 52, in Login
wx.StaticText(panel,-1,"Failed",pos=(10,220))
NameError: global name 'panel' is not defined

If I use self.panel , it gives this error:Traceback (most recent call last):
File "C:\Documents and Settings\Sravan\My Documents\Sravan\PYTHON\GUI.py", line 64, in
pymailer()
File "C:\Documents and Settings\Sravan\My Documents\Sravan\PYTHON\GUI.py", line 36, in __init__
login=wx.Button(self.panel,103,label="Login",pos=(10,170))
AttributeError: 'pymailer' object has no attribute 'panel

Anyways, this is the code till now:

import smtplib
import time
import os
import wx

window=wx.App()

class pymailer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Pymailer",size=(500,500))

        panel=wx.Panel(self,-1)
        
        menubar=wx.MenuBar()

        filem=wx.Menu()
        filem.Append(201,"Quit")
        self.Bind(wx.EVT_MENU,self.Quit)

        viewm=wx.Menu()
        viewm.Append(202,"About")
        self.Bind(wx.EVT_MENU,self.About)

        menubar.Append(filem,"File")
        menubar.Append(viewm,"Help")

        self.SetMenuBar(menubar)

        wx.StaticText(panel,-1,"Welcome to Py-mailer.\nLogin with your Gmail credentials and you can send a text-only email to anyone quickly and easily.",pos=(10,10))
        wx.StaticText(panel,-1,"Please enter your Gmail login ID: ",pos=(10,100))
        wx.StaticText(panel,-1,"Please enter your Gmail login password:\n(will not be stored)",pos=(10,130))

        username=wx.TextCtrl(panel,101,"Login ID",pos=(220,100))
        password=wx.TextCtrl(panel,102,"Password",pos=(220,130))

        login=wx.Button(self.panel,103,label="Login",pos=(10,170))
        self.Bind(wx.EVT_BUTTON,self.Login)

        self.Centre()
        self.Show()

    def Quit(self,event):
        self.Close()

    def Login(self,event):
        s=smtplib.SMTP("smtp.gmail.com",587)
        s.starttls()
        try:
            wx.StaticText(panel,-1,"Logging in...",pos=(10,200))
            s.login(user,passw)
        except:
            wx.StaticText(panel,-1,"Failed",pos=(10,220))

    def About(self,event):
        about=wx.AboutDialogInfo()

        about.SetName("Py-Mailer")
        about.SetCopyright("(c) 2009 Sravan")
        about.SetWebSite("http://www.uberpix.wordpress.com")
        about.AddDeveloper("Sravan\nDan")

        wx.AboutBox(about)

pymailer()
window.MainLoop()


Also, when I used self.panel , I replaced panel with self.panel everywhere, just thought I'd let you know!

Any other bugs in the code?

Thanks

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

This is the code that I have working, not exactly sure why self.panel wouldn't work for you.

import smtplib
import time
import os
import wx

window=wx.App()

class pymailer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Pymailer",size=(500,500))

        self.panel=wx.Panel(self,-1)
        
        menubar=wx.MenuBar()

        filem=wx.Menu()
        filem.Append(201,"Quit")
        self.Bind(wx.EVT_MENU,self.Quit)

        viewm=wx.Menu()
        viewm.Append(202,"About")
        self.Bind(wx.EVT_MENU,self.About)

        menubar.Append(filem,"File")
        menubar.Append(viewm,"Help")

        self.SetMenuBar(menubar)

        wx.StaticText(self.panel,-1,"Welcome to Py-mailer.\nLogin with your Gmail credentials and you can send a text-only email to anyone quickly and easily.",pos=(10,10))
        wx.StaticText(self.panel,-1,"Please enter your Gmail login ID: ",pos=(10,100))
        wx.StaticText(self.panel,-1,"Please enter your Gmail login password:\n(will not be stored)",pos=(10,130))

        username=wx.TextCtrl(self.panel,101,"Login ID",pos=(220,100))
        password=wx.TextCtrl(self.panel,102,"Password",pos=(220,130))

        login=wx.Button(self.panel,103,label="Login",pos=(10,170))
        self.Bind(wx.EVT_BUTTON,self.Login)

        self.Centre()
        self.Show()

    def Quit(self,event):
        self.Close()

    def Login(self,event):
        s=smtplib.SMTP("smtp.gmail.com",587)
        s.starttls()
        try:
            wx.StaticText(self.panel,-1,"Logging in...",pos=(10,200))
            s.login(user,passw)
        except:
            wx.StaticText(self.panel,-1,"Failed",pos=(10,220))

    def About(self,event):
        about=wx.AboutDialogInfo()

        about.SetName("Py-Mailer")
        about.SetCopyright("(c) 2009 Sravan")
        about.SetWebSite("http://www.uberpix.wordpress.com")
        about.AddDeveloper("Sravan\nDan")

        wx.AboutBox(about)

pymailer()
window.MainLoop()
winmic
Light Poster
33 posts since Jun 2009
Reputation Points: 26
Solved Threads: 8
 

Hmm...I too don't know why self.panel isn't working. I will get back to you about that.

Now, what should I do to make a button(called 'Next>'), which on being clicked will 'refresh' the screen and display some new contents? I hope you understand me!

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

So I forgot something with events, you can make them respond to a certain id. If you have tried to File->Quit recently you'll see that it will make the about:dialog appear. If you have objects that propagate the same event then you'll want them id specific. so self.Bind(wx.EVT_MENU,self.Quit) becomes self.Bind(wx.EVT_MENU,self.Quit, id=201). The same thing will need to be done for the about menu event, and if you add another button the button event will need to be id specific.

How to add new content really depends on specifically what you want to do. I'm guessing that you want to have completely new content where all old content is destroyed, then you would probably want to create a new wx.Panel and content. I could help a little more if you were a little more specific.

BTW, have you thought about how your going to get the username and password out of the TextCtrl?

winmic
Light Poster
33 posts since Jun 2009
Reputation Points: 26
Solved Threads: 8
 
BTW, have you thought about how your going to get the username and password out of the TextCtrl?

It shouldn't be to hard, have a look at the API for the wx.TextCTRL http://www.wxpython.org/docs/api/wx.TextCtrl-class.html
One of the functon is GetValue() that returns a string of the value in the textctrl, simple :)

Paul Thompson
Veteran Poster
1,119 posts since May 2008
Reputation Points: 264
Solved Threads: 183
 

I don't think getting the values will be a problem, because I've heard of GetValues() and Google it for help.

The problem is: the self.panel doesn't at all work...

One more question:

viewm=wx.Menu()
viewm.Append(202,"About")        self.Bind(wx.EVT_MENU,self.About,id=302)

def About(self,event,id=302):
    about=wx.AboutDialogInfo()

-but it doesn't work. How do I specify the ID when defining the function?

Thanks

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

I don't think getting the values will be a problem, because I've heard of GetValues() and Google it for help.

The problem is: the self.panel doesn't at all work...

One more question:

viewm=wx.Menu()
viewm.Append(202,"About")        self.Bind(wx.EVT_MENU,self.About,id=302)

def About(self,event,id=302):
    about=wx.AboutDialogInfo()

-but it doesn't work. How do I specify the ID when defining the function?

Thanks

You don't need the id as a method parameter, but at least try to match the id in the lines above, 202 is not the same as 302.self.panel will work if you use it throughout the class! Search for 'panel' with your editor.

Ene Uran
Posting Virtuoso
1,723 posts since Aug 2005
Reputation Points: 625
Solved Threads: 213
 

You don't need the id as a method parameter, but at least try to match the id in the lines above, 202 is not the same as 302.

self.panel will work if you use it throughout the class! Search for 'panel' with your editor.

I did what you told:

viewm=wx.Menu()
viewm.Append(202,"About")     self.Bind(wx.EVT_MENU,self.About,id=202)

def About(self,event):
about=wx.AboutDialogInfo()


But, only "Quit" works, and "About" doesn't.

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

Also, if I use [icode]self.panel[icode] throughout, it says:
Traceback (most recent call last):
File "C:\Documents and Settings\Sravan\My Documents\Sravan\PYTHON\GUI.py", line 72, in
pymailer()
File "C:\Documents and Settings\Sravan\My Documents\Sravan\PYTHON\GUI.py", line 29, in __init__
wx.StaticText(self.panel,-1,"Welcome to Py-mailer.\nLogin with your Gmail credentials and you can send a text-only email to anyone quickly and easily.",pos=(10,10))
AttributeError: 'pymailer' object has no attribute 'panel'

Here's the modified code including[icode]self.panel[icode]everywhere

import smtplib
import time
import os
import wx

window=wx.App()

class pymailer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Py-mailer",size=(500,500))

        panel=wx.Panel(self,-1)
        
        menubar=wx.MenuBar()

        filem=wx.Menu()
        filem.Append(201,"Quit")
        self.Bind(wx.EVT_MENU,self.Quit,id=201)

        viewm=wx.Menu()
        viewm.Append(202,"About")
        self.Bind(wx.EVT_MENU,self.About,id=202)

        menubar.Append(filem,"File")
        menubar.Append(viewm,"Help")

        self.SetMenuBar(menubar)

        wx.StaticText(self.panel,-1,"Welcome to Py-mailer.\nLogin with your Gmail credentials and you can send a text-only email to anyone quickly and easily.",pos=(10,10))
        wx.StaticText(self.panel,-1,"Please enter your Gmail login ID: ",pos=(10,100))
        wx.StaticText(self.panel,-1,"Please enter your Gmail login password:\n(will not be stored)",pos=(10,130))

        username=wx.TextCtrl(self.panel,101,"Login ID",pos=(220,100))
        password=wx.TextCtrl(self.panel,102,"Password",pos=(220,130))

        login=wx.Button(self.panel,103,label="Login",pos=(10,170))
        self.Bind(wx.EVT_BUTTON,self.Login,id=103)

        wx.StaticText(self.panel,-1,"To:",pos=(10,220))
        wx.StaticText(self.panel,-1,"Subject:",pos=(10,250))
        wx.StaticText(self.panel,-1,"Message:",pos=(10,280))

        to=wx.TextCtrl(self.panel,103,"<username@domain.server>",pos=(80,220),size=(240,20))
        subject=wx.TextCtrl(self.panel,104,pos=(80,250),size=(240,20))
        message=wx.TextCtrl(self.panel,105,pos=(80,280),size=(240,150))

        self.Centre()
        self.Show()

    def Quit(self,event):
        self.Close()
    
    def About(self,event):
        about=wx.AboutDialogInfo()

    def Login(self,event,):
        wx.StaticText(panel,-1,"Logging in...",pos=(10,200))
        s=smtplib.SMTP("smtp.gmail.com",587)
        s.starttls()
        try:
            s.login(user,passw)
        except:
            wx.StaticText(self.panel,-1,"Failed",pos=(10,200))

        about.SetName("Py-Mailer")
        about.SetCopyright("(c) 2009 Sravan")
        about.SetWebSite("http://www.uberpix.wordpress.com")
        about.AddDeveloper("Sravan\nDan")

        wx.AboutBox(about)

pymailer()
window.MainLoop()
sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

self.panel everywhere except the most important line 12

panel=wx.Panel(self,-1)
needs to be
self.panel=wx.Panel(self,-1)

Ene Uran
Posting Virtuoso
1,723 posts since Aug 2005
Reputation Points: 625
Solved Threads: 213
 

Till now:

import smtplib
import time
import os
import wx

window=wx.App()

s=smtplib.SMTP("smtp.gmail.com",587)
s.starttls()

class pymailer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Py-mailer",size=(500,700))

        self.panel=wx.Panel(self,-1)
        
        menubar=wx.MenuBar()

        filem=wx.Menu()
        filem.Append(201,"Quit")
        self.Bind(wx.EVT_MENU,self.Quit,id=201)

        viewm=wx.Menu()
        viewm.Append(202,"About")
        self.Bind(wx.EVT_MENU,self.About,id=202)

        menubar.Append(filem,"File")
        menubar.Append(viewm,"Help")

        self.SetMenuBar(menubar)

        wx.StaticText(self.panel,-1,"Welcome to Py-mailer.\nLogin with your Gmail credentials and you can send a text-only email to anyone quickly and easily.",pos=(10,10))
        wx.StaticText(self.panel,-1,"Please enter your Gmail login ID: ",pos=(10,100))
        wx.StaticText(self.panel,-1,"Please enter your Gmail login password:\n(will not be stored)",pos=(10,130))

        username=wx.TextCtrl(self.panel,101,"Login ID",pos=(220,100))
        user=username.GetValue()
        password=wx.TextCtrl(self.panel,102,"Password",pos=(220,130))
        passw=password.GetValue()

        login=wx.Button(self.panel,103,label="Login",pos=(10,170))
        self.Bind(wx.EVT_BUTTON,self.Login,id=103)
        
        wx.StaticText(self.panel,-1,"To:",pos=(10,250))
        wx.StaticText(self.panel,-1,"Subject:",pos=(10,280))
        wx.StaticText(self.panel,-1,"Message:",pos=(10,310))

        toadd=wx.TextCtrl(self.panel,104,"<username@domain.server>",pos=(80,250),size=(240,20))
        to=toadd.GetValue()
        subj=wx.TextCtrl(self.panel,105,pos=(80,280),size=(240,20))
        subject=subj.GetValue()
        mess=wx.TextCtrl(self.panel,106,pos=(80,310),size=(240,150))
        message=mess.GetValue()

        send=wx.Button(self.panel,107,"Send",pos=(245,470))
        self.Bind(wx.EVT_BUTTON,self.Send,id=107)

        self.Centre()
        self.Show()

    def Quit(self,event):
        self.Close()
    
    def About(self,event):
        about=wx.AboutDialogInfo()
        
        about.SetName("Py-Mailer")
        about.SetCopyright("(c) 2009 Sravan")
        about.SetWebSite("http://www.uberpix.wordpress.com")
        about.AddDeveloper("Sravan\nDan")

        wx.AboutBox(about)

    def Login(self,event):
        try:
            s.login(user,passw)
            wx.StaticText(self.panel,-1,"Logged in",pos=(10,200))
        except:
            wx.StaticText(self.panel,-1,"Failed",pos=(10,200))

    def Send(self,event):
        msg="To: "+to+"\nSubject: "+subject+"\n"+message
        s.sendmail(us,to,msg)
        s.quit()

pymailer()
window.MainLoop()


No matter what I enter, it doesn't login and says "Failed". Why?
Also, how do I mask the password input?

sravan953
Posting Whiz in Training
243 posts since May 2009
Reputation Points: 2
Solved Threads: 30
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You
View similar articles that have also been tagged: