1

I am new to wxpython and working on my first app. I know there is a lot about this topic but I haven't seen anything helpful specificaly to my issue. I want to have more then two panels and switch like this

def switch(self, newactpanel) 
 self.actpanel.Hide()
 self.actpanel=newactpanel
 self.actpanel.Show()

So far this does not work. The app starts, the buttons appear but both panel views appear at once, or only one appears and I can not switch. How to build a def to switch between more panels?

Thank a lot for answers.

Here is my code:

import wx
ID_EXIT=200
ID_ADDKEYWORDS = 301
ID_WRITEINTERP = 302
h_frame = 750
w_frame = 325
class SubPanel(wx.Panel):
 """"""
 def __init__(self, parent):
 """Constructor"""
 wx.Panel.__init__(self, parent=parent)
class AddKeyWordsPanel(wx.Panel):
 def __init__(self, parent,size):
 wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = size)
 panel1 = SubPanel(self)
 some_val = "Add KeyWords"
 something = wx.TextCtrl(panel1, -1,some_val, size=(h_frame,24), style=wx.TE_READONLY|wx.SIMPLE_BORDER|wx.TE_CENTRE)
 box = wx.BoxSizer(wx.VERTICAL)
 box.Add(panel1, 1, wx.EXPAND)
 self.SetAutoLayout(True)
 self.SetSizer(box)
class WritePanel(wx.Panel):
 def __init__(self, parent,size):
 wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = size)
 panel1 = SubPanel(self)
 panel2 = SubPanel(self)
 panel3 = SubPanel(self)
 keys_val = self.GetKeyNames()
 keys = wx.TextCtrl(panel1, -1,keys_val, size=(h_frame,24), style=wx.TE_READONLY|wx.SIMPLE_BORDER|wx.TE_CENTRE)
 font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
 keys.SetFont(font)
 keywords1_val = self.GetKeyWords(keys_val)
 keywords1 = wx.TextCtrl(panel2, -1,keywords1_val, size=(h_frame,100), style=wx.TE_READONLY|wx.BORDER_NONE)
 txtentry_val = ""
 txtentry = wx.TextCtrl(panel3, -1, txtentry_val, size=(h_frame, 200))
 txtentry.SetBackgroundColour("WHITE")
 txtentry.SetInsertionPoint(0)
 box = wx.BoxSizer(wx.VERTICAL)
 box.Add(panel1, 3, wx.EXPAND)
 box.Add(panel2, 2, wx.EXPAND)
 box.Add(panel3, 1, wx.EXPAND)
 self.SetAutoLayout(True)
 self.SetSizer(box)
 def GetKeyNames(self):
 return "Blabla1"
 def GetKeyWords(self,keys):
 return "Blabla2"
class MainFrame(wx.Frame):
 def __init__(self, parent, ID, title):
 wx.Frame.__init__(self, parent, ID, title, size=(h_frame, w_frame))
 self.CreateStatusBar()
 menu= wx.Menu()
 menu.Append(ID_ADDKEYWORDS,"&Add KeyWords"," Add Keywords")
 menu.Append(ID_WRITEINTERP,"&Write Interpretations"," Write Interpretations")
 menu.Append(ID_EXIT,"E&xit"," Terminate the program")
 menuBar = wx.MenuBar()
 menuBar.Append(menu,"&Menu")
 self.SetMenuBar(menuBar)
 self.wrtpnl = WritePanel(self,(h_frame,w_frame))
 self.addkeywpnl = AddKeyWordsPanel(self,(h_frame,w_frame))
 self.panel = self.wrtpnl
 self.panel.Layout()
 wx.EVT_MENU(self, ID_ADDKEYWORDS, self.SwitchPanel(self.addkeywpnl))
 wx.EVT_MENU(self, ID_WRITEINTERP, self.SwitchPanel(self.wrtpnl))
 wx.EVT_MENU(self, ID_EXIT, self.OnExit)
 self.doiexit = wx.MessageDialog( self, " Exit - R U Sure? \n","GOING away ...", wx.YES_NO)
 def SwitchPanel(self,show_pnl):
 self.panel.Hide()
 self.panel = show_pnl
 self.panel.Layout()
 self.panel.Show()
 self.Layout()
 def OnExit(self,e):
 igot = self.doiexit.ShowModal()
 if igot == wx.ID_YES:
 self.Close(True)
app = None
app = wx.App()
frame = MainFrame(None, -1, "KeyWordTool")
frame.Show()
app.MainLoop()
asked Jun 30, 2015 at 12:15

4 Answers 4

3

I actually wrote a tutorial on the topic some time ago. Here's the code:

import wx
import wx.grid as gridlib
########################################################################
class PanelOne(wx.Panel):
 """"""
 #----------------------------------------------------------------------
 def __init__(self, parent):
 """Constructor"""
 wx.Panel.__init__(self, parent=parent)
 txt = wx.TextCtrl(self)
########################################################################
class PanelTwo(wx.Panel):
 """"""
 #----------------------------------------------------------------------
 def __init__(self, parent):
 """Constructor"""
 wx.Panel.__init__(self, parent=parent)
 grid = gridlib.Grid(self)
 grid.CreateGrid(25,12)
 sizer = wx.BoxSizer(wx.VERTICAL)
 sizer.Add(grid, 0, wx.EXPAND)
 self.SetSizer(sizer)
########################################################################
class MyForm(wx.Frame):
 #----------------------------------------------------------------------
 def __init__(self):
 wx.Frame.__init__(self, None, wx.ID_ANY, 
 "Panel Switcher Tutorial")
 self.panel_one = PanelOne(self)
 self.panel_two = PanelTwo(self)
 self.panel_two.Hide()
 self.sizer = wx.BoxSizer(wx.VERTICAL)
 self.sizer.Add(self.panel_one, 1, wx.EXPAND)
 self.sizer.Add(self.panel_two, 1, wx.EXPAND)
 self.SetSizer(self.sizer)
 menubar = wx.MenuBar()
 fileMenu = wx.Menu()
 switch_panels_menu_item = fileMenu.Append(wx.ID_ANY, 
 "Switch Panels", 
 "Some text")
 self.Bind(wx.EVT_MENU, self.onSwitchPanels, 
 switch_panels_menu_item)
 menubar.Append(fileMenu, '&File')
 self.SetMenuBar(menubar)
 #----------------------------------------------------------------------
 def onSwitchPanels(self, event):
 """"""
 if self.panel_one.IsShown():
 self.SetTitle("Panel Two Showing")
 self.panel_one.Hide()
 self.panel_two.Show()
 else:
 self.SetTitle("Panel One Showing")
 self.panel_one.Show()
 self.panel_two.Hide()
 self.Layout()
# Run the program
if __name__ == "__main__":
 app = wx.App(False)
 frame = MyForm()
 frame.Show()
 app.MainLoop()

You might also want to take a look at using one of wxPython's "Book" controls, such as the wx.Notebook.

answered Jun 30, 2015 at 13:52
Sign up to request clarification or add additional context in comments.

2 Comments

Hi, thanks for the reply. I know your tutorial but I have an issue with this approach. Lets say I have 20 panels and want to switch between them. Do I need to write an if self.panel_one, elif self.panel_two ... elif self.panel_twenty? I am searching for a dynamic, clean nice way, if such is possible.
I would just use a dictionary of panels. Then when you want to switch, you just pass the key to that panel and switch to it. Or just instantiate the new panel and destroy the old one so you don't have all those panels in memory all the time.
1

The trouble is that on the lines:

 wx.EVT_MENU(self, ID_ADDKEYWORDS, self.SwitchPanel(self.addkeywpnl))
 wx.EVT_MENU(self, ID_WRITEINTERP, self.SwitchPanel(self.wrtpnl))

you are calling the function SwitchPanel already. The result of the call is None (SwitchPanel does not return anything), so it is the same thing as if you did:

 wx.EVT_MENU(self, ID_ADDKEYWORDS, None)
 wx.EVT_MENU(self, ID_WRITEINTERP, None)

Probably the most understandable solution is:

 wx.EVT_MENU(self, ID_ADDKEYWORDS, self.SwitchPanel1)
 wx.EVT_MENU(self, ID_WRITEINTERP, self.SwitchPanel2)
 # [...]
def SwitchPanel1(self, evt):
 evt.Skip()
 self.SwitchPanel(self.addkeywpnl)
def SwitchPanel2(self, evt):
 evt.Skip()
 self.SwitchPanel(self.wrtpnl)
answered Jun 30, 2015 at 12:48

Comments

1

You do not require to pass both panel object while creating event for menu item.

wx.EVT_MENU(self, ID_ADDKEYWORDS, self.SwitchPanel)
wx.EVT_MENU(self, ID_WRITEINTERP, self.SwitchPanel)

Get menu item ID by using event.GetId() method to identify which panel to hide and show.

def SwitchPanel(self,event):
 self.panel.Hide()
 if event.GetId() == ID_ADDKEYWORDS:
 self.panel = self.addkeywpnl
 elif event.GetId() == ID_WRITEINTERP:
 self.panel = self.wrtpnl
 self.panel.Layout()
 self.panel.Show()
 self.Layout()
answered Jun 30, 2015 at 13:56

3 Comments

Hi, thanks for the reply. I have seen this approach, but what if I need to switch between 20 panels? Do I write if, elif for 20 cases? I am actualy looking for a cleaner solution, if such exists.
@Stefan You could create a dictionary of the panels, keyed with the IDs. then you can look up the panel in the dict instead of a series of if statements
@GP89: I didn't see your comment until now. But a dictionary is exactly what I did and it works. Great idea. Thanks!
0

Ok, I think I solved it with a combination of all three suggestions. It's not exactly what I wanted but very close. It works and this way I don't need to have a specific switch function for each button/panel. My solution is this:

 self.wrtpnl = WritePanel(self,(h_frame,w_frame))
 self.addkeywpnl = AddKeyWordsPanel(self,(h_frame,w_frame))
 self.pnldic = {ID_ADDKEYWORDS:self.addkeywpnl, ID_WRITEINTERP:self.wrtpnl}
 wx.EVT_MENU(self, ID_ADDKEYWORDS, self.SwitchPanel)
 wx.EVT_MENU(self, ID_WRITEINTERP, self.SwitchPanel)
 wx.EVT_MENU(self, ID_EXIT, self.OnExit)
def SwitchPanel(self,event):
 self.panel.Hide()
 self.panel = self.pnldic[event.GetId()]
 self.panel.Layout()
 self.panel.Show()
 self.Layout()

Thanks a lot for the ideas!

answered Jun 30, 2015 at 16:55

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.