call a Frame2 from a button in Frame1 - python

I'am a new bie in python,I have to call a frame "Frame2" when I clic on a button from Frame1,I have this error:
this I my code:
global Frame2 fr
def OnButton4Button(self, event):
fr.Show()
even.Skip()
NB:I work with wxpython,and boa constructor
thanks fro help

You have several typos in your code. Here's a corrected example:
from Frame2 import fr
def OnButton4Button(self, event):
fr.Show()
event.Skip() # you need to spell event correctly
This assumes that Frame2 is a module. Most of the time, you don't need to use globals in Python.
To make this a bit easier to follow, I wrote an example that has a MainFrame class and a Frame2 class in the same module so you don't have to import anything or use globals:
import wx
########################################################################
class Frame2(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Frame2")
panel = wx.Panel(self)
########################################################################
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Main Frame")
panel = wx.Panel(self)
button = wx.Button(panel, label="Open Frame2")
button.Bind(wx.EVT_BUTTON, self.onButton)
self.Show()
#----------------------------------------------------------------------
def onButton(self, event):
""""""
frame = Frame2()
frame.Show()
event.Skip()
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
app.MainLoop()

In your short code you have an indentation on the second line, this is an error, you must write it like:
from Frame2 import fr
def OnButton4Button(self, event):
fr.Show()
event.Skip()
You may respect the indentation in Python like following example:
global var
def function():
#indented block
#should be always on the same column
condition = 1
if condition:
#new indented block
#is also aligned on a column
print "something"
#this is out of the IF block
#call the function
function()
In the PEP8 recommendations you will find the rules to avoid indenting errors.

Related

What is the correct way to link a button to open an other py file?

I have a big doubt because my script is not performing as it should be. So I have a simple main file with a button that opens a blank grid (codes below). The problem with this code is that it opens reportWindow the first time it executes, but if I close the report and I try to open it again I receive the error :
NameError: name 'TestFrame' is not defined
I've also removed if __name__ == '__main__' from the last lines of reportWindow.py because the script wasn't working with it. I tried if __name__ == 'main' as it's imported from main.py but it didn't work either.
Please, can someone show me how it should have been done the correct way?
Thank you
main.py
import wx
class Test(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id, "Frame aka Window", size=(300, 200))
panel = wx.Panel(self)
button = wx.Button(panel, label = "Exit", pos=(80, 80), size = (120,30))
self.Bind(wx.EVT_BUTTON, self.closebutton, button)
def closebutton(self,event):
from reportWindow import SimpleGrid
SimpleGrid(TestFrame, -1)
if __name__ == '__main__':
app = wx.App()
frame = Test(parent=None, id=1)
frame.Show()
app.MainLoop()
reportWindow.py
import wx
import wx.grid as gridlib
class SimpleGrid(gridlib.Grid): ##, mixins.GridAutoEditMixin):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
#[...Some code...]
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, 0, "Title", size=(1400,800))
self.grid = SimpleGrid(self, log)
#[...Some code...]
#if __name__ == '__main__':
import sys
from wx.lib.mixins.inspection import InspectableApp
app = InspectableApp(False)
frame = TestFrame(None, sys.stdout)
frame.Show(True)
#import wx.lib.inspection
#wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
Your code has a few of issues.
1) The NameError is occurring because you're not importing TestFrame from reportWindow.
2) Without if __name__ == "__main__" in reportWindow.py your program will create another wx.App and start another MainLoop which will block the first loop from receiving events etc... You should only create 1 App/MainLoop. It will also create the TestFrame the first time you import reportWindow.
3) It looks like you want SimpleGrid to be a child of TestFrame, but then you try to create it by itself in closebutton.
4) When creating the SimpleGrid you pass the TestFrame class instead of an instance of the TestFrame class.
Here is the modified code
# main.py
import wx, sys
class Test(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, "Frame aka Window", size=(300, 200))
panel = wx.Panel(self)
button = wx.Button(panel, label="Exit", pos=(80, 80), size=(120, 30))
self.Bind(wx.EVT_BUTTON, self.closebutton, button)
def closebutton(self, event):
from reportWindow import TestFrame
frame = TestFrame(self, sys.stdout)
frame.Show()
if __name__ == '__main__':
app = wx.App()
frame = Test(parent=None, id=1)
frame.Show()
app.MainLoop()
# reportWindow.py
import wx
import wx.grid as gridlib
class SimpleGrid(gridlib.Grid): ##, mixins.GridAutoEditMixin):
def __init__(self, parent, log):
gridlib.Grid.__init__(self, parent, -1)
# [...Some code...]
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, 0, "Title", size=(1400, 800))
self.grid = SimpleGrid(self, log)
# [...Some code...]
if __name__ == '__main__':
import sys
from wx.lib.mixins.inspection import InspectableApp
app = InspectableApp(False)
frame = TestFrame(None, sys.stdout)
frame.Show(True)
import wx.lib.inspection
wx.lib.inspection.InspectionTool().Show()
app.MainLoop()

How to access from child to widget in parent window?

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/

Python attempting to create a simple gui, getting "AttributeError: 'MainMenu' object has no attribute 'intro_screen'"

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.

Embed Separate WX GUIs into Notebook Tabs

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!

how to bind 2 functions to a single event

I have this bind "self.Bind(wx.EVT_LISTBOX, self.selLoadFile, listbox)". How would I add another function, I guess thats what youd call it. Like the self.selLoadFile, how would I add another function to the same event? I am making a music player and want the file to automatically play after it is selected. The self.selLoadFile function loads the file, how would I add the "self.Play" function to the same evt?
Thanks in advance!!
I'm sorry, I am new to programming. Could you help me out alittle? So if my functions where:
def selLoadFile(self, event):
my_selection = self.myListBox.GetStringSelection()
file_path = os.path.join(os.getcwd(),"songs",my_selection)
self.doLoadFile2(file_path)
def doLoadFile2(self, file_path):
if not self.mc.Load(file_path):
wx.MessageBox("Unable to load %s: Unsupported format?" % file_path, "ERROR", wx.ICON_ERROR | wx.OK)
else:
folder, filename = os.path.split(file_path)
self.st_file.SetLabel('%s' % filename)
self.mc.SetBestFittingSize()
self.mc.Play()
def Play(self, event):
self.mc.Play()
self.playbackSlider.SetRange(0,self.mc.Length())
How would I include all 3 of the above functions in one function?
If you want to bind a widget to two event handlers, then just do it. That will work as long as you call event.Skip() at the end of the handler code. Without this line the event will be consumed by the first handler and will not be caught by any additional handlers. Here's a silly example:
import wx
########################################################################
class MyPanel(wx.Panel):
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
btn = wx.Button(self, label="Press Me")
btn.Bind(wx.EVT_BUTTON, self.HandlerOne)
btn.Bind(wx.EVT_BUTTON, self.HandlerTwo)
def HandlerOne(self, event):
print "handler one fired!"
event.Skip()
def HandlerTwo(self, event):
print "handler two fired!"
event.Skip()
########################################################################
class MyFrame(wx.Frame):
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Test")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()

Categories

Resources