I have parent class with panel (notebook) and combobox as follows:
class A(wx.aui.AuiMDIChildFrame):
def __init__(self,parent):
self.panel_1 = wx.Panel(self, -1)
self.NB = wx.Notebook(self.panel_1, -1, style=0)
self.NB_A= WindowFirst(self.NB)
self.ComboA= wx.ComboBox(self.panel_1, 500, 'Phase', (50, 150), (160,-1), phasesList, wx.CB_DROPDOWN)
and in another py file:
class WindowFirst(GeneralPanel):
def __init__(self,parent):
how do I access ComboA from here?
This isn't my complete code... Just want is relevent for the question.
How do I acess comboA from WindowFirst? I need to be able to set values to the ComboA from WindowFirst.
I can access from A to WindowFirst, but not the other way around.
Any suggestions?
This cannot be done as long as you are trying to access ComboA from WindowFirst.init(). The constructor for WindowFirst is called as NB_A gets created, at which time ComboA has not yet been created. So no matter how you try to access ComboA, it's not possible because it doesn't exist
However, if you want to access ComboA from another method of WindowFirst, that can be done. You have NB_A as a child of NB, NB as a child of panel_1, panel_1 as a child of A and ComboA as a child of A. You just need to make sure ComboA exists before you try to access it. So something like this.
def anotherFunction():
#how do I access ComboA from here?
nb = self.GetParent()
panel_1 = nb.GetParent()
a = panel_1.GetParent()
try:
#try to access ComboA and do what you gotta do
a.ComboA.doSomething()
except:
#something went wrong (like ComboA doesn't exist yet)
print "ComboA doesn't exist yet"
or for brevity
def anotherFunction():
#how do I access ComboA from here?
try:
self.GetParent().GetGrandParent().ComboA.doSomething()
except:
print "ComboA doesn't exist yet"
The recommended way to communicate between classes in wxPython is to use pubsub, which is included with wxPython. Basically you will want to create a listener in your class A and then publish messages to it from WindowFirst to tell it to update.
Here's an example:
import random
import wx
from wx.lib.pubsub import pub
########################################################################
class TabPanel(wx.Panel):
#----------------------------------------------------------------------
def __init__(self, parent):
""""""
wx.Panel.__init__(self, parent)
colors = ["red", "blue", "gray", "yellow", "green"]
self.color = random.choice(colors)
self.SetBackgroundColour(self.color)
self.Bind(wx.EVT_LEFT_DCLICK, self.update_button)
lbox = wx.ListBox(self, choices=colors)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(lbox, 0, wx.ALL, 10)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def update_button(self, event):
""""""
pub.sendMessage('button_listener', message=self.color)
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
########################################################################
class DemoFrame(wx.Frame):
"""
Frame that holds all other widgets
"""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, wx.ID_ANY,
"Notebook Tutorial",
size=(600,400)
)
panel = MyPanel(self)
self.tab_num = 3
self.notebook = wx.Notebook(panel)
tabOne = TabPanel(self.notebook)
self.notebook.AddPage(tabOne, "Tab 1")
tabTwo = TabPanel(self.notebook)
self.notebook.AddPage(tabTwo, "Tab 2")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5)
self.btn = wx.Button(panel, label="Get Color")
sizer.Add(self.btn)
panel.SetSizer(sizer)
self.Layout()
# create a listener
pub.subscribe(self.change_button, 'button_listener')
self.Show()
#----------------------------------------------------------------------
def change_button(self, message, arg2=None):
""""""
self.btn.SetLabel(message)
#----------------------------------------------------------------------
if __name__ == "__main__":
app = wx.App(False)
frame = DemoFrame()
app.MainLoop()
Note that the pubsub API changed slightly in wxPython 2.9 and above. If you're using an older version, then you'll need to change the code a bit. I have a tutorial illustrating the older API here.
For more information on the newer API, check out my updated article here:
http://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/
Related
I'm trying to create an App which allows the user to switch the information show using buttons. The basic idea of the code is that the user sees buttons on the left side of the screen and when the user presses "button 1", the code shows Panel1. I've made 2 buttons so far and the code for 2 panels is written as well but i can't figure out how to update my MainFrame so it show a different panel when one of the buttons is pressed.
Code:
import wx
TabNumber = 1
class ButtonPanel(wx.Panel):
def __init__(self, parent):
global TabNumber
super(ButtonPanel, self).__init__(parent, -1)
self.Tab1Button = wx.Button(self, label="TAB 1")
self.Tab1Button.Bind(wx.EVT_BUTTON, self.SwitchTab(1))
self.Tab2Button = wx.Button(self, label="TAB 2")
self.Tab2Button.Bind(wx.EVT_BUTTON, self.SwitchTab(2))
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.Tab1Button, wx.CENTER,0)
self.Sizer.Add(self.Tab2Button, wx.CENTER, 0)
self.SetSizer(self.Sizer)
def SwitchTab(self, tab):
def OnClick(event):
print(f"Switch to tab {tab} started")
TabNumber = tab
print(TabNumber)
return OnClick
class Panel1(wx.Panel):
def __init__(self, parent):
super(Panel1, self).__init__(parent, -1)
self.panel = wx.Panel(self)
self.text = wx.StaticText(self.panel, label="1")
class Panel2(wx.Panel):
def __init__(self, parent):
super(Panel2, self).__init__(parent, -1)
self.panel = wx.Panel(self)
self.text = wx.StaticText(self.panel, label="2")
class MainFrame(wx.Frame):
def __init__(self):
super(MainFrame, self).__init__(None, -1, "Test Application")
self.Panels = {
"Panel1": Panel1(self),
"Panel2": Panel2(self)
}
self.MySizer = wx.BoxSizer(wx.HORIZONTAL)
self.tabpanel = ButtonPanel(self)
self.MySizer.Add(self.tabpanel,wx.CENTER,0)
self.InfoPanel = self.Panels["Panel"+str(TabNumber)]
self.MySizer.Add(self.InfoPanel, wx.CENTER,0)
self.SetSizer(self.MySizer)
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
frame.Show()
app.MainLoop()
I was also wondering how I can adjust the ratio for the space that is given to my ButtonPanel and my InfoPanel.
As far as I can see, you are trying to do something that works like a Wizard... On the one hand, you can use wx.adv.Wizard. On the other hand, you can look at this tutorial that does something very similar and adapt it to what you need:
WXPython: How to create a generic wizard
Good luck!
i am using wxpython and trying to make an background to a sizer without any success, i searched in google without any results.
i try it with this boxsizer
wx.BoxSizer(wx.HORIZONTAL)
I just use panels for this sort of thing. You can set the color of the panel several different ways: you can use a named color, a wx.Color object, a predefined wx.Color object like wx.RED or a tuple of 3 integers.
Here's a simple example:
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.SetBackgroundColour('white')
main_sizer = wx.BoxSizer(wx.VERTICAL)
for number in range(5):
btn = wx.Button(self, label='Button {}'.format(number))
main_sizer.Add(btn, 0, wx.ALL, 5)
self.SetSizer(main_sizer)
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='Background colors')
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
I wrote a little about this topic here:
https://www.blog.pythonlibrary.org/2009/09/03/wxpython-resetting-the-background-color/
You might also the wxPython wiki helpful:
https://wiki.wxpython.org/GettingStarted
complete newbie here to Python as I only started learning the language a few days ago (with no programming experience beforehand).
I'm basically bashing my skull against the desk here, trying to create one menu with a button that will lead you to another menu, which is supposed to replace/hide/destroy the previous menu (either works, so long as the process can be reversed).
What I've come up with so far:
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.Centre()
self.main_menu = MainMenu(self)
self.intro_screen = IntroScreen(self)
self.intro_screen.Hide()
class MainMenu(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent=parent)
self.main_menu = MainMenu
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
nextscreen = wx.Button(panel, label='Next Screen', size=(150,30))
nextscreen.Bind(wx.EVT_BUTTON, self.NextScreen)
sizer.Add(nextscreen, 0, wx.CENTER|wx.ALL, 5)
self.Show()
self.Centre()
def NextScreen(self, event):
self.main_menu.Hide(self)
self.intro_screen.Show()
class IntroScreen(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent=parent)
self.intro_screen = IntroScreen
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
gobackscreen = wx.Button(panel, label='Go Back a Screen', size=(150,30))
gobackscreen.Bind(wx.EVT_BUTTON, self.GoBackScreen)
sizer.Add(gobackscreen, 0, wx.CENTER|wx.ALL, 5)
self.Show()
self.Centre()
def GoBackScreen(self, event):
self.intro_screen.Hide()
self.main_menu.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
#frame.Show()
app.MainLoop()
From what I can tell, the NextScreen button does not see the intro_screen class, and is therefore unable to show it. But I am clueless as to how to fix this.
Indeed, I have absolutely no idea if this is on the right way to do it. Any help is greatly appreciated
Using Python 2.7
intro_screen is an attribute of MainFrame instances; not of MainMenu instances.
Your MainMenu.__init__() method is passed in a MainFrame instance as parent. I am not certain if self.parent is set by the line wx.Frame.__init__(self, parent=parent), but if it is not, do add self.parent = parent in MainMenu.__init__(.
You can then refer to self.parent on MainMenu instances, and the following should work:
self.parent.intro_screen.Show()
I am not sure why you are setting the current class as an instance attribute:
self.main_menu = MainMenu
and
self.intro_screen = IntroScreen
Instead of self.main_menu.Hide(self) you can just call self.Hide(), the reference to the class is not needed.
I basically have 3 separate wxPython GUIs that I would like to combine into a single application, giving each GUI its own notebook tab. I'm not really sure how to do this though and am looking for some advice. I appreciate any comments or thoughts I can get.
My idea is that it should look something like this:
import wx
import OtherFrame
class PageOne(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
t = wx.StaticText(self, -1, "This is a PageOne object", (20,20))
panel=OtherFrame.Panel(parent)
box = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(self,box)
panel.Layout(self, parent)
class PageTwo(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
t = wx.StaticText(self, -1, "This is a PageTwo object", (40,40))
class PageThree(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
t = wx.StaticText(self, -1, "This is a PageThree object", (60,60))
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Simple Notebook Example")
p = wx.Panel(self)
nb = wx.Notebook(p)
page1 = PageOne(nb)
page2 = PageTwo(nb)
page3 = PageThree(nb)
nb.AddPage(page1, "Page 1")
nb.AddPage(page2, "Page 2")
nb.AddPage(page3, "Page 3")
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()
But this gives a few errors and crashes. Without the sizers under PageOne, it just puts a gray square in the top right corner, with them, it crashes.
Thanks in advance!
I assume each of your frame's have panels in them with the code you want. Just take the code for the widgets from each of those frames and put those in each of the Page classes. You'll probably have to change the parents of the widgets to "self" instead of "panel" or whatever you call them.
Then you won't be opening a frame in each of the page code base. You don't want to open a frame there. You want the page to be the parent of the widgets, not open something else up.
Thanks to your help, I got this to work for me. Since each of my other wx App had Panel classes with all the widgets I wanted, I didn't need to create classes for each page. Here's the code:
import wx
import OtherFrame1
import OtherFrame2
import OtherFrame3
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Simple Notebook Example")
p = wx.Panel(self)
nb = wx.Notebook(p)
page1 = OtherFrame1.Panel(nb)
page2 = OtherFrame2.Panel(nb)
page3 = OtherFrame3.Panel(nb)
nb.AddPage(page1, "Page 1")
nb.AddPage(page2, "Page 2")
nb.AddPage(page3, "Page 3")
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
if __name__ == "__main__":
app = wx.App(redirect=False)
MainFrame().Show()
app.MainLoop()
Thanks for the help!
This is a continuation from this question:
wxPython: Can a wx.PyControl contain a wx.Sizer?
The main topic here is using a wx.Sizer inside a wx.PyControl. I had problems Fit()ting my CustomWidget around its child widgets. That problem was solved by calling Layout() after Fit().
However, as far as I have experienced, the solution only works when the CustomWidget is a direct child of a wx.Frame. It breaks down when it becomes a child of a wx.Panel.
EDIT: Using the code below, the CustomWidget doesn't resize correctly to fit its children. I observed that this only happens when the CustomWidget (as a subclass of wx.PyControl) is a child of a wx.Panel; otherwise, if it is a direct child of a wx.Frame, it Fit()s perfectly.
Here is the code:
import wx
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None)
panel = Panel(parent=self)
custom = CustomWidget(parent=panel)
self.Show()
class Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.SetSize(parent.GetClientSize())
class CustomWidget(wx.PyControl):
def __init__(self, parent):
wx.PyControl.__init__(self, parent=parent)
# Create the sizer and make it work for the CustomWidget
sizer = wx.GridBagSizer()
self.SetSizer(sizer)
# Create the CustomWidget's children
text = wx.TextCtrl(parent=self)
spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
# Add the children to the sizer
sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
# Make sure that CustomWidget will auto-Layout() upon resize
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Fit()
def OnSize(self, event):
self.Layout()
app = wx.App(False)
frame = Frame()
app.MainLoop()
.SetSizerAndFit(sizer) does the job. I'm not sure why a .SetSizer(sizer) then a .Fit() won't work. Any ideas?
import wx
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None)
panel = Panel(parent=self)
custom = CustomWidget(parent=panel)
self.Show()
class Panel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.SetSize(parent.GetClientSize())
class CustomWidget(wx.PyControl):
def __init__(self, parent):
wx.PyControl.__init__(self, parent=parent)
# Create the sizer and make it work for the CustomWidget
sizer = wx.GridBagSizer()
self.SetSizer(sizer)
# Create the CustomWidget's children
text = wx.TextCtrl(parent=self)
spin = wx.SpinButton(parent=self, style=wx.SP_VERTICAL)
# Add the children to the sizer
sizer.Add(text, pos=(0, 0), flag=wx.ALIGN_CENTER)
sizer.Add(spin, pos=(0, 1), flag=wx.ALIGN_CENTER)
# Set sizer and fit, then layout
self.SetSizerAndFit(sizer)
self.Layout()
# ------------------------------------------------------------
# # Make sure that CustomWidget will auto-Layout() upon resize
# self.Bind(wx.EVT_SIZE, self.OnSize)
# self.Fit()
#
#def OnSize(self, event):
# self.Layout()
# ------------------------------------------------------------
app = wx.App(False)
frame = Frame()
app.MainLoop()