Button pointing to another function after Hiding one panel and showing another - python

I have the a situation here .
My motive : Hiding one panel and showing another.
Whats Working :Layout wise , my app is behaving like i want it to .
The Problem : After the I hide one panel and show another , the button in this panel (process button) is still pointing to the function binded with "OUT" button .
Steps to be followed :
Run the program .
Press "Process" button. Then press "Out" Button .
U will see old panel come back. Again press "Process" button .
Observe that the button is running the function binded with the "OUT" Button.
Here is the complete program :
import wx
class Panels(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title,size=(500,-1))
#Font
#__init__(self, pointSize, family, style, weight, underline=False, face=EmptyString, encoding=FONTENCODING_DEFAULT)
self.font1 = wx.Font(12, wx.DECORATIVE, wx.ITALIC,wx.FONTWEIGHT_BOLD, underline = True )
self.font2 = wx.Font(10, wx.DECORATIVE, wx.NORMAL,wx.FONTWEIGHT_BOLD, underline = False )
self.font3 = wx.Font(10, wx.DECORATIVE, wx.ITALIC,wx.FONTWEIGHT_BOLD, underline = True )
favicon = wx.Icon('icon.ico', wx.BITMAP_TYPE_ICO)
wx.Frame.SetIcon(self, favicon)
list_choice = ['ALL','UnSeen','DRAFT']
self.vbox = wx.BoxSizer(wx.VERTICAL)
#Launch panel Defined
panel_launch = wx.Panel(self,-1,style=wx.SUNKEN_BORDER)
#Layout Defination
hbox= wx.BoxSizer(wx.HORIZONTAL)
lbl_Username = wx.StaticText(panel_launch,0, "Username:")
lbl_Username.SetFont(self.font3)
self.txt_Username = wx.TextCtrl(panel_launch,0)#wx.Size(self,w,h)
lbl_Password = wx.StaticText(panel_launch,0, "Password:")
lbl_Password.SetFont(self.font3)
self.txt_Password = wx.TextCtrl(panel_launch,0,style=wx.TE_PASSWORD)
btn_Process = wx.Button(panel_launch,0, "Process")
hbox.Add(lbl_Username,0,wx.LEFT|wx.TOP,10)
hbox.Add(self.txt_Username,0,wx.LEFT|wx.TOP,10)
hbox.Add(lbl_Password,0,wx.LEFT|wx.TOP,10)
hbox.Add(self.txt_Password,0,wx.LEFT|wx.TOP,10)
hbox.Add(btn_Process,0,wx.LEFT|wx.TOP,10)
panel_launch.SetSizer(hbox)
#Menu section
menubar=wx.MenuBar()
pehla=wx.Menu()
doosra=wx.Menu()
teesra =wx.Menu()
option_menu=wx.Menu()
info=wx.Menu()
#Menu Items
self.item1_1=pehla.Append(wx.ID_OPEN,"&Add Mail\tAlt-A","This is to add a mail account") #Sub-Items of First menu pull down list
item1_2=pehla.Append(wx.ID_EXIT,"&Quit\tAlt-Q","This will exit app") #The last comment will show on status bar when mouse is on that option
item3_2=teesra.Append(wx.ID_ABOUT,"A&bout\tAlt-B","About Section")
menu_1=menubar.Append(pehla,'&File') #Naming of Menu items
menu_2=menubar.Append(doosra,'&Edit')
menu_3=menubar.Append(teesra,'&Info')
item2_1=option_menu.Append(wx.ID_ANY,'Export File Location')
doosra.AppendMenu(wx.ID_ANY,"&Options\tAlt-O",option_menu)
self.item1_1.Enable(False)
self.SetMenuBar(menubar)
self.vbox.Add(panel_launch,-1,wx.EXPAND,10)
self.SetSizer(self.vbox)
self.Layout()
self.Centre()
self.Show(True)
#Event Bindings
self.Bind(wx.EVT_BUTTON,self.OnSignIn,btn_Process)
self.Bind(wx.EVT_MENU,self.OnAddMail,self.item1_1)
self.Bind(wx.EVT_MENU, self.OnFileExit,item1_2)
#+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-
#--------------------------Frame Related Function Zone--------------------------------------
def OnSignIn(self,event):
print "We are in default"
mymail = self.txt_Username.GetValue()
mypwd = self.txt_Password.GetValue()
self.tstremove(event) #Hiding the old panel items
panel_signedin = wx.Panel(self,-1)
lbl_email = wx.StaticText(panel_signedin,0, "Email:")
lbl_email.SetFont(self.font3)
txt_mymail = wx.StaticText(panel_signedin,0,mymail)
txt_mymail.SetFont(self.font2)
btn_OUT = wx.Button(panel_signedin,0, "OUT")
self.Bind(wx.EVT_BUTTON,self.OnSignOut,btn_OUT)
hbox3= wx.BoxSizer(wx.HORIZONTAL)
hbox3.Add(lbl_email,0,wx.ALL,10)
hbox3.Add(txt_mymail,0,wx.ALL,10)
hbox3.Add(btn_OUT,0,wx.ALL,10)
panel_signedin.SetSizer(hbox3)
self.vbox.Add(panel_signedin,-1,wx.EXPAND,10)
self.SetSizer(self.vbox)
self.Layout()
self.item1_1.Enable(True) #Enable 'Add' menu item
def OnSignOut(self,event):
print "We are out"
event.GetEventObject().GetParent().Hide()
self.txt_Username.GetParent().Show(True)
self.Layout()
return
def OnSignInNew(self,event):
print "We are in New"
self.item1_1.Enable(True)
mymail1 = self.txt1_Username.GetValue()
mypwd1 = self.txt_Password.GetValue()
self.tstremove(event)
panel_signedin1 = wx.Panel(self,-1)
lbl_email1 = wx.StaticText(panel_signedin1,0, "Email:")
lbl_email1.SetFont(self.font3)
txt_mymail1 = wx.StaticText(panel_signedin1,0,mymail1)
txt_mymail1.SetFont(self.font2)
btn1_OUT = wx.Button(panel_signedin1,0, "OUT")
self.Bind(wx.EVT_BUTTON,self.OnSignOut,btn1_OUT)
hbox31= wx.BoxSizer(wx.HORIZONTAL)
hbox31.Add(lbl_email1,0,wx.ALL,10)
hbox31.Add(txt_mymail1,0,wx.ALL,10)
hbox31.Add(btn1_OUT,0,wx.ALL,10)
panel_signedin1.SetSizer(hbox31)
self.vbox.Add(panel_signedin1,-1,wx.EXPAND,10)
self.SetSizer(self.vbox)
self.Layout()
def tstremove(self,event):
event.GetEventObject().GetParent().Hide()
self.Layout()
return
def tstrecall(self,event):
event.GetEventObject().GetParent().UnHide()
self.Layout()
return
def OnAddMail(self,eventdef):
self.item1_1.Enable(False)
self.vbox.Add((-1,5))
panel_new = wx.Panel(self,0,style=wx.SUNKEN_BORDER)
hbox1= wx.BoxSizer(wx.HORIZONTAL)
lbl1_Username = wx.StaticText(panel_new,-1, "Username:")
lbl1_Username.SetFont(self.font3)
self.txt1_Username = wx.TextCtrl(panel_new,-1)#wx.Size(self,w,h)
lbl1_Password = wx.StaticText(panel_new,-1, "Password:")
lbl1_Password.SetFont(self.font3)
self.txt1_Password = wx.TextCtrl(panel_new,-1,style=wx.TE_PASSWORD)
btn1_Process = wx.Button(panel_new,-1, "Process")
self.Bind(wx.EVT_BUTTON,self.OnSignInNew,btn1_Process)
hbox1.Add(lbl1_Username,0,wx.LEFT|wx.TOP,10)
hbox1.Add(self.txt1_Username,0,wx.LEFT|wx.TOP,10)
hbox1.Add(lbl1_Password,0,wx.LEFT|wx.TOP,10)
hbox1.Add(self.txt1_Password,0,wx.LEFT|wx.TOP,10)
hbox1.Add(btn1_Process,0,wx.LEFT|wx.TOP,10)
panel_new.SetSizer(hbox1)
self.vbox.Add(panel_new,-1,wx.EXPAND,10)
self.SetSizer(self.vbox)
self.Layout()
self.Bind(wx.EVT_BUTTON,self.OnSignInNew,btn1_Process)
return
#+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-+-()-
#--------------------------Process Related Function Zone--------------------------------------
def OnFileExit(self, event):
""" File|Exit event """
self.Close()
app = wx.App()
Panels(None, -1, 'Test')
app.MainLoop()
I just can't get, how one button is pointing to another function?
Is hiding and showing not enough?

The problem is that you are giving BOTH buttons the same ID. Actually, you're giving almost ALL your widgets the same ID. You should NEVER do that. If you change the id parameter in all your widgets to wx.ID_ANY or just -1, you'll get randomly assigned ids and your program will work.

Related

wxPython's wx.grid.Grid() won't come fully into view

Issue:
I'm experiencing an issue where a function that simply creates a Grid() works when called in one place, but not another place. When it is called from the "other," non-working place, it does create a very small square in the corner of the window. At this time, I don't understand why, and I'm hoping someone can help.
Code: (feel free to copy paste this into a text editor and give it a go!)
import wx
import wx.grid as gridlib
class MainFrame(wx.Frame):
def __init__(self, parent, title):
super(MainFrame, self).__init__(parent, title=title,
size=(350, 250))
self.init_ux()
self.main_grid = None
def init_ux(self):
menu_bar = wx.MenuBar()
file_menu = wx.Menu()
file_menu.AppendSeparator()
menu_bar.Append(file_menu, '&File')
# add open file menu
open_menu = wx.Menu()
my_btn = open_menu.Append(wx.ID_ANY, 'button description')
# append open_menu to the file_menu
file_menu.Append(wx.ID_OPEN, '&Open', open_menu)
self.SetMenuBar(menu_bar)
self.Bind(wx.EVT_MENU, lambda event: self.open_dialog(data="i love string literals."), my_btn)
self.SetSize((300, 200))
self.Centre()
# the create_grid_view() below DOES work when uncommented
#self.create_grid_view(10, 10)
def create_grid_view(self, row_count, col_count):
print("Creating grid view!")
# set up grid panel
panel = wx.Panel(self)
self.main_grid = gridlib.Grid(panel)
self.main_grid.CreateGrid(row_count, col_count)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.main_grid, 1, wx.EXPAND)
panel.SetSizer(sizer)
def open_dialog(self, data):
# data is being used for populating wildcard, etc
with wx.FileDialog(self, "Open a file!",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
file_path = fileDialog.GetPath()
try:
# here, I do some fun data "things" with the file_path
# open it, use other functions, etc.
# afterwards, I need to create a grid
self.create_grid_view(10, 10)
# ^^ This creates a small square instead of a grid.
except IOError:
wx.LogError("Cannot open file '%s'." % file_path)
if __name__ == "__main__":
app = wx.App()
frame = MainFrame(None, title='Window Title :)')
frame.Show()
app.MainLoop()
Expectation:
Actual Results:
Summary:
Why does the create_grid_view() function display a proper grid when called from the init_ux() function, but not the open_dialog() function?
Thanks in advance!
Where you have panel.SetSizer(sizer) either use:
panel.SetSizerAndFit(sizer)
or use:
panel.SetSizer(sizer)
panel.Fit()

WxPython Web Browser Set Title

I have created a web browser in python using WxPython. I've been able to get everything to function, go forward/back, reload, ect. My only problem is I'd like to be able to set the title at the top of the program to the title of the web page. I understand how to set the title with self.SetTitle(title), I also know from some of the research I've done that you can get the tile of the page using self.browser.GetCurrentTitle(). Only problem with using that is that it's a one time thing that doesn't refresh it's self, when a user clicks a new link. I'm assuming there is some sort of function or something I can catch when a new page is loaded and tell python to do something like this:
def OnLoad(self, event):
self.webtitle = self.browser.GetCurrentTitle()
self.browser.SetTitle(self.webtitle)
Or something along those lines I'm just not sure where or how I can connect or "catch" that function. I have read through the documentation of wx.html2.WebView, but I'm not able to make sense of how to do this, I have also looked through this site as well as a few mailing lists but I can't seem to find anything that would explain how to do this.
Here is the main code that will run my browser (obviously I've shortened it).
class PyBrowser(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.SetTitle('PyBrowser')
sizer = wx.BoxSizer(wx.VERTICAL)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
#Element Variables
self.browser = wx.html2.WebView.New(self)
self.address = wx.TextCtrl(self, value="http://",size=(500, 26))
self.go = wx.Button(self, label="Go", id=wx.ID_OK)
self.back = wx.BitmapButton(self, -1, wx.Bitmap('img/Back Button.png', wx.BITMAP_TYPE_PNG), size=(26,26) ,style=wx.NO_BORDER)#wx.Button(self, label="Back")
self.forward = wx.BitmapButton(self, -1, wx.Bitmap('img/Forward Button.png', wx.BITMAP_TYPE_PNG), size=(26,26) ,style=wx.NO_BORDER)#wx.Button(self, label="Forward")
self.reload = wx.BitmapButton(self, -1, wx.Bitmap('img/Reload Button.png', wx.BITMAP_TYPE_PNG), size=(26,26) ,style=wx.NO_BORDER)#wx.Button(self, label = "Refresh")
self.result = None
#Nav area
addressarea = wx.BoxSizer()
addressarea.Add(self.address, proportion = 1, border = 0)
...
#Adding elements
sizer.Add(addressarea, proportion = 0, flag = wx.EXPAND, border = 0)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
#Button binding
self.Bind(wx.EVT_BUTTON, self.OnGo, id=wx.ID_OK)
...
#Menu bar stuff
#File Menu
self.fileMenu = wx.Menu()
self.New = self.fileMenu.Append(wx.ID_ANY, 'New Window')
...
#Help Menu
self.helpMenu = wx.Menu()
self.Help = self.helpMenu.Append(wx.ID_ANY, 'Help')
...
self.Bind(wx.EVT_MENU,self.OnHelp,self.Help)
...
#Adding the actual Menu Bar
self.menuBar = wx.MenuBar()
self.menuBar.Append(self.fileMenu, 'File')
self.menuBar.Append(self.helpMenu, 'Help')
self.SetMenuBar(self.menuBar)
self.SetSizer(sizer)
self.SetSize((1000, 700))
def OnGo(self, event):
self.result = self.address.GetValue()
self.browser.LoadURL(self.result)
if __name__ == '__main__':
app = wx.App()
dialog = PyBrowser(None, -1)
dialog.browser.LoadURL("http://www.google.com")
dialog.Show()
app.MainLoop()
To summarize what I'm asking is how to I set the title of a wx.Frame to the current title of a web page inside of wx.html2.WebView and change the name every time a new link is clicked?
The webview events that you require are listed here
I would catch the EVT_WEBVIEW_LOADED event and update the title in the event handler. I believe you could do something like this:
def onLoaded(self, event):
title = self.browser.GetCurrentTitle()
self.SetTitle(title)
What may be even better is to catch EVT_WEBVIEW_TITLE_CHANGED as that actually detects when the page title changes.
I figured out that from what Mike said, using an event to catch it would work. So instead of EVT_WEBVIEW_TITLE_CHANGED I used EVT_WEBVIEW_LOADED, I then binded the event to my function to handle changing the title. It looked like this:
#Binding the function the event to the function.
self.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.OnPageLoad, self.browser)
#Function binding to the page loading
def OnPageLoad(self, event):
self.WebTitle = self.browser.GetCurrentTitle()
self.SetTitle(self.WebTitle)

Continuously check for radio button status [WxPython]

I have a listbox with a set of strings. The set of strings I want to display depends on which radio button is selected. I would like it such that while the user is interacting with the Form, if they ever change the radio button it will update the list box.
Here is my code (I'm leaving the array for t87 and t89 out because they are very long (assume they exist):
def OnBtnSuperTesting(self, event):
class MainWindow(wx.Frame):
def __init__(self, parent, title):
self.dirname=''
wx.Frame.__init__(self, parent, title=title, size=(320,440))
self.SetBackgroundColour(wx.WHITE)
self.CenterOnScreen()
self.CreateStatusBar()
self.radioT89 = wx.RadioButton(self, -1, 'T89 only', pos = (2,0), style = wx.RB_GROUP)
self.radioT87 = wx.RadioButton(self, -1, 'T87 only', pos = (154, 0))
self.radioKeySort = wx.RadioButton(self, -1, 'Sort by Key', pos = (2,40), style = wx.RB_GROUP)
self.radioAtoZ = wx.RadioButton(self, -1, 'Sort Name A-Z', pos = (2,60))
self.radioZtoA = wx.RadioButton(self, -1, 'Sort Name Z-A', pos = (2,80))
self.checkCode = wx.CheckBox(self, -1, 'Generate Code', pos = (154,40))
self.checkBuild = wx.CheckBox(self, -1, 'Generate Build Report', pos = (154, 60))
self.ln = wx.StaticLine(self, -1, pos = (0,15), size = (300,3), style = wx.LI_HORIZONTAL)
self.ln2 = wx.StaticLine(self, -1, pos = (150,15), size = (3,100), style = wx.LI_VERTICAL)
self.radioT87.Bind(wx.EVT_RADIOBUTTON, self.updateList)
#self.Bind(wx.EVT_RADIOBUTTON, self.radioT89, self.updateList())
self.listbox = wx.ListBox(self, -1, pos = (0,120), size = (300,200), choices = T89, style = (wx.LB_SINGLE|wx.LB_HSCROLL))
self.go = wx.Button(self,-1, label = 'Go!', pos = (110, 325))
# Setting up the menu.
filemenu= wx.Menu()
menuAbout= filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File")
self.SetMenuBar(menuBar)
# Events.
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
self.SetAutoLayout(1)
self.Show()
def OnExit(self,e):
self.Close(True) # Close the frame.
def updateList(self):
if self.radioT87.GetValue() == True:
choices = T87
self.listbox.Set(choices)
else:
choices = T89
self.listbox.Set(choices)
app = wx.App(False)
frame = MainWindow(None, "Supervisory Testing")
app.MainLoop()
When you create each radiobutton you can create a bind event. What this does (as you have implemented later on in your code) is execute a command function when the bind event occurs. In your case it would look like this:
self.Bind(wx.EVT_RADIOBUTTON,self.RadioButton,self.DoSomething)
Explanation:
wx.EVT_RADIOBUTTON
This is the event that is triggered when the user changes the Radiobutton's status. It may or may not have attributes.
self.RadioButton
This is the radiobutton which you would like to bind. In your case "self.radioAtoZ" or similar.
self.DoSomething
THis is the callback function. You can make it whatever you want such as:
def DoSomething(self):
if self.radioAtoZ.getStatus():
rearrangeNumbersFromAtoZ
print 'Re-arranged numbers from A to Z'
else:
etc.
EDIT:
self.RadioButton.Bind(EVT_RADIOBUTTON, self.DoSomething)
Your structure for self.DoSomething should be like this:
Class MainWindow:
def __init_(self, parent):
def DoSomething(self):
#dostuff
Also in response to your other comment:
when a function is called within a Bind event, it passes the event to the function by default. In addition, all functions have the "self" arg, thus 2 given args. You need to change the following:
def DoSomething(self, event):
#dostuff
I decided to rewrite the OP's code to demonstrate how to bind 2 RadioButton's to 2 different event handlers and update the ListBox:
import wx
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Radios!")
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.radioAtoZ = wx.RadioButton(panel, label='Sort Name A-Z',
style = wx.RB_GROUP)
self.radioAtoZ.Bind(wx.EVT_RADIOBUTTON, self.sortAZ)
sizer.Add(self.radioAtoZ, 0, wx.ALL|wx.EXPAND, 5)
self.radioZtoA = wx.RadioButton(panel, label='Sort Name Z-A')
self.radioZtoA.Bind(wx.EVT_RADIOBUTTON, self.sortZA)
sizer.Add(self.radioZtoA, 0, wx.ALL|wx.EXPAND, 5)
choices = ["aardvark", "zebra", "bat", "giraffe"]
self.listbox = wx.ListBox(panel, choices=choices)
sizer.Add(self.listbox, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.Show()
#----------------------------------------------------------------------
def sortAZ(self, event):
""""""
choices = self.listbox.GetStrings()
choices.sort()
self.listbox.SetItems(choices)
#----------------------------------------------------------------------
def sortZA(self, event):
""""""
choices = self.listbox.GetStrings()
choices.sort()
choices.reverse()
self.listbox.SetItems(choices)
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
You will want to take a look at the following wiki article on the differences of binding it this way versus the other:
http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind
Most of the time when you create a group of widgets that do different things, you bind them to different event handlers. If you want to bind all the RadioButtons to the same handler, then you'll probably need to name each widget with a unique name so that when they come to the handler, you can tell which button was pressed. Then you can use a series of if statements to decide what to do to the list box. Here's a tutorial that talks about that sort of thing:
http://www.blog.pythonlibrary.org/2011/09/20/wxpython-binding-multiple-widgets-to-the-same-handler/

How can I add and remove controls in the page of a Notebook in wxPython?

Based on user interaction, I would like to dynamically add and remove controls to a panel in a wxPython notebook. The approach I've tried most thoroughly is to call .Clear() on the panel's sizer and add all new controls. However, on both Windows 7 and Linux desktops, rendering artifacts and stale controls remain visible under the new contents. How can I completely remove the old controls and add new controls without these artifacts?
Below is a sample program that reproduces the issue on Windows 7. Note the two different .update() methods of StaticPanel and DynamicPanel:
#!/usr/bin/python
import wx
import sys
class StaticPane(wx.Panel):
"""A panel that contains simple text that is updated
when the .update() method is called. The text is updated
using .SetText(), and the text control sticks around
between calls to .update()."""
def __init__(self, *args, **kwargs):
super(StaticPane, self).__init__(*args, **kwargs)
self._sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self._sizer)
self._counter = 0
self._base_text = "Some Text"
self._text = wx.TextCtrl(self, -1,
self._base_text + "!" * self._counter,
style=wx.TE_READONLY)
self._sizer.Add(self._text, -1, wx.EXPAND)
def update(self):
self._counter += 1
self._text.SetValue(self._base_text + "!" * self._counter)
class DynamicPane(wx.Panel):
"""A panel that contains simple text that is updated
when the .update() method is called. The text is updated
by removing the existing text control, and adding a new one
with the updated text string."""
def __init__(self, *args, **kwargs):
super(DynamicPane, self).__init__(*args, **kwargs)
self._sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self._sizer)
self._counter = 0
self._base_text = "Some Text"
self._text = wx.TextCtrl(self, -1,
self._base_text + "!" * self._counter,
style=wx.TE_READONLY)
self._sizer.Add(self._text, -1, wx.EXPAND)
def update(self):
self._counter += 1
self._sizer.Clear()
self._text = wx.TextCtrl(self, -1,
self._base_text + "!" * self._counter,
style=wx.TE_READONLY)
self._sizer.Add(self._text, -1, wx.EXPAND)
self.Layout()
class TestViewer(wx.Frame):
"""A Frame with a button and a notebook. When the button is pressed,
each of the two pages in the notebook recieve a call to .update().
"""
def __init__(self, parent):
super(TestViewer, self).__init__(parent, -1, "Test Viewer")
self.Bind(wx.EVT_CLOSE, self.OnClose)
self._panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
self._panel.SetSizer(vbox)
update_button = wx.Button(self._panel, wx.ID_CLOSE, "Update")
update_button.Bind(wx.EVT_BUTTON, self.update)
vbox.Add(update_button, 0, wx.EXPAND)
self._nb = wx.Notebook(self._panel)
self._view_one = StaticPane(self._nb, -1)
self._view_two = DynamicPane(self._nb, -1)
self._nb.AddPage(self._view_one, "One")
self._nb.AddPage(self._view_two, "Two")
vbox.Add(self._nb, 1, wx.EXPAND | wx.ALL)
self.Layout()
def update(self, e):
self._view_one.update()
self._view_two.update()
def OnClose(self, event):
sys.exit(0)
if __name__ == "__main__":
app = wx.App(False)
frame = TestViewer(None)
frame.Show()
app.MainLoop()
Click the button "Update" to update the text in the two panels. The first panel updates the text control by using .SetText(), while the second panel replaces the TextCtrl with a new one. Note that as you resize the window or mouseover the second panel after a few button clicks, there are overlapping controls and other artifacts.
Here are screenshots showing the stacked controls. Both images were taken after the same number of button clicks, they just show the two different panels at the same state. I expected the text to be exactly the same.
Simply clearing the sizer will only remove the references to its contents, not the widgets. When you create a widget, it will register with the parent window you supplied. Consider the following code:
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
self.textCtrl = wx.TextCtrl(self) # create with Frame as parent
self.textCtrl = None # has no effect on the TextCtrl
The parent window (Frame in this example) will take ownership of the TextCtrl and even if you set it to None, the Frame will keep it alive until it's is destroyed. To remove the TextCtrl, you have to destroy it explicitly:
self.textCtrl.Destroy()
If you want to remove all child widgets at once, you can use:
self.DestroyChildren()

How to link multiple wx.Dialogs in wxPython

I want to make a game in wxPython (no other modules) and I want to make it so that you can enter some values in popup screens before the game starts, and then the game will be drawn on a canvas which in turn is drawn on a panel, which is bound to the main game.
I made the gamescreen with all fancy stuff (works solo)
I made the input screens
But I cannot link them.
How do I start the game so it will open a dialog box, then on the closure of it open another one, and then open the game ?
I tried the following, but it will not open my canvas:
# makes a game by showing 2 dialogs
# after dialogs have been answered, starts the game by drawing the canvas.
# imports
import wx
import Speelveld3
# globals
SCRWIDTH = 950
SCRHEIGHT = 700
# dialogbox class
class MyDialog1(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent)
self.username = wx.TextCtrl(self)
self.okButton = wx.Button(self, wx.ID_OK, "OK")
class MyDialog2(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent)
self.canvasWidth = wx.TextCtrl(self)
self.okButton = wx.Button(self, wx.ID_OK, "OK")
# main class
class Game(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, title='My game', size=(SCRWIDTH, SCRHEIGHT))
self.username = ""
self.canvasWidth = 10
# hide the frame for now
self.Hide()
def OnInit(self):
#Make your dialogs
dlg1 = MyDialog1(self)
#if the user pressed "OK" (i.e. NOT "Cancel" or any other button you might add)
if dlg1.ShowModal() == wx.ID_OK:
#get the username from the dialog
self.username = dlg1.username.GetValue()
#clean up the dialog (AFTER you get the username)
dlg1.Destroy()
dlg2 = MyDialog2(self)
#if the user pressed "OK" (i.e. NOT "Cancel" or any other button you might add)
if dlg2.ShowModal() == wx.ID_OK:
#get the username from the dialog
self.canvasWidth = dlg2.canvasWidth.GetValue()
#clean up the dialog (AFTER you get the username)
dlg2.Destroy()
# Now that you have your settings, Make the gameboard
# THIS PART IS STILL BROKEN!
# I can paste the whole board class (structure of it is taken from the tetris tutorial)
# but that seems a bit much tbh...
self.gameBoard = Board.Board(self)
self.gameBoard = SetFocus()
self.gameBoard.start()
self.Centre()
self.Show(True) #show the frame
if __name__ == '__main__':
# how can I start the game here?
app = wx.App()
frame = Game()
board = Speelveld3.Speelveld(frame)
board.start()
frame.Show()
app.MainLoop()
You've double posted, and the lack of any wx.Dialog in your sample code suggests to me that you haven't even looked at a tutorial yet, but I will give you the benefit of the doubt.
First, if you want to return information from a dialog, the easiest way is to define a custom dialog. Define a new class that inherits from wx.Dialog and then set it up just like you would a normal panel or a frame. It seems to me that you will need two of these. They'll look something like this:
class MyDialog1(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent)
self.username = wx.TextCtrl(self) #this is where users will enter their username
self.okButton = wx.Button(self, wx.ID_OK, "OK") #Note that I'm using wx.ID_OK. This is important
Now, for the logic you want. Pretty much every object in wxPython that you actually see has the functions Show() and Hide() (API here). You don't want to show your frame until AFTER the dialogs are finished, so in your __init__(), call Hide(). I'm also initializing a variable, username, which is where I will store the data from my dialog.
class Game(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(SCRWIDTH, SCRHEIGHT))
self.username = ""
self.Hide() #don't show the frame just yet
#self.Hide() is the exact same as self.Show(False)
Now, for your dialogs. Like Mike Driscoll suggested, you call your dialogs BEFORE making your canvas. wx.Dialogs are launched using ShowModal(). By setting the ID of self.okButton to the constant wx.ID_OK, wxPython recognizes that the dialog should be closed after the button in clicked. You should also be aware of wx.ID_CANCEL.
def OnInit(self):
#Make your dialogs
dlg1 = MyDialog1(self)
if dlg1.ShowModal() == wx.ID_OK:
#if the user pressed "OK" (i.e. NOT "Cancel" or any other button you might add)
self.username = dlg1.username.GetValue() #get the username from the dialog
dlg1.Destroy() #clean up the dialog (AFTER you get the username)
#do this again for your second dialog
#Now that you have your settings, Make the gameboard
self.gameBoard = Board.Board(self)
self.gameBoard = SetFocus()
self.gameBoard.start()
self.Centre()
self.Show(True) #show the frame
In your OnInit you just need to call your dialogs and show them modally BEFORE you create your Board instance. Then it should work correctly.
EDIT (6-28-12): Here's some code:
import wx
########################################################################
class MyDlg(wx.Dialog):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Dialog.__init__(self, None, title="I'm a dialog!")
lbl = wx.StaticText(self, label="Hi from the panel's init!")
btn = wx.Button(self, id=wx.ID_OK, label="Close me")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(lbl, 0, wx.ALL, 5)
sizer.Add(btn, 0, wx.ALL, 5)
self.SetSizer(sizer)
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
# show a custom dialog
dlg = MyDlg()
dlg.ShowModal()
dlg.Destroy()
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
pdc = wx.PaintDC(self)
try:
dc = wx.GCDC(pdc)
except:
dc = pdc
rect = wx.Rect(0,0, 100, 100)
for RGB, pos in [((178, 34, 34), ( 50, 90)),
(( 35, 142, 35), (110, 150)),
(( 0, 0, 139), (170, 90))
]:
r, g, b = RGB
penclr = wx.Colour(r, g, b, wx.ALPHA_OPAQUE)
brushclr = wx.Colour(r, g, b, 128) # half transparent
dc.SetPen(wx.Pen(penclr))
dc.SetBrush(wx.Brush(brushclr))
rect.SetPosition(pos)
dc.DrawRoundedRectangleRect(rect, 8)
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Example frame")
# show a MessageDialog
style = wx.OK|wx.ICON_INFORMATION
dlg = wx.MessageDialog(parent=None,
message="Hello from the frame's init",
caption="Information", style=style)
dlg.ShowModal()
dlg.Destroy()
# create panel
panel = MyPanel(self)
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
frame.Show()
app.MainLoop()

Categories