I have written a wxPython GUI which assigns some variables upon a button click.
def OnGo(self, event):
inputdatadirectory = self.txtbx1.GetValue()
outputsavedirectory = self.txtbx2.GetValue()
mcadata = self.txtbx3.GetValue()
current_dir = os.getcwd()
execfile(current_dir+"\\aEDXD.py")
I then run execfile, and the executed file imports and runs a class from another file.
How can I make the variables I've defined through my GUI available to the imported class?
Yes you can, although it will probably be difficult to debug. Here is a silly example:
import wx
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Test")
panel = wx.Panel(self)
btn = wx.Button(panel, label="Go")
btn.Bind(wx.EVT_BUTTON, self.onGo)
self.Show()
#----------------------------------------------------------------------
def onGo(self, event):
""""""
foobar = "This is a test!"
execfile("foo.py")
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
And here is the foo.py file.
print foobar
If you run the wxPython script, it will execute foo.py which has access to the locals and globals in the wxPython script. You won't be able to run foo.py by itself though. See the following:
Execute a file with arguments in Python shell
https://docs.python.org/2/library/functions.html#execfile
Related
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Test")
panel = wx.Panel(self, wx.ID_ANY)
#Button is created; binded to onButton
button = wx.Button(panel, id=wx.ID_ANY, label="Press Me")
button.Bind(wx.EVT_BUTTON, self.onButton)
def onButton(self,EVT_BUTTON):
print("Hello world!")
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
#Runs Button command on startup
MyForm.onButton()
I want onButton() to run at startup, and have it be able to run when the
wx.Button is pressed. Unfortunetly, it comes up with this error:
>TypeError: onButton() missing 2 required positional arguments: 'self' and 'EVT_BUTTON'
It is slightly more difficult. I am guessing you are a beginner to programming. If so, I suggest, you learn some more basics. Doing GUI applications is a bit more advanced topic.
So, firstly, for your wxPython program to run, you must start an event loop, so your program should have something like this:
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
You defined your function onButton with 2 parameters. Therefore you must supply them when calling the function. The first one is instead of the self, and that is the frame. The second is named EVT_BUTTON (and giving the variable this name suggests that you actually do not understand these concepts, and that's the reason why I suggested that you start with studying basics).
So you could call
frame.OnButton(None)
before calling app.MainLoop() and the code will run. But that's probably not enough.
I'm building a menu for a frame with wxPython (python3).
I want to separate the main.py from the menus.py - have these two separated files so the code is organized into smaller pieces.
I need to be able to pass control back to the main.py from menus.py.
In particular, I need that the handlers for the events I bind for menu items (in menus.py) will reside in main.py, or, alternatively, have the handlers in menus.py, but reference objects in main.py (for example, to Close() the application for the "Exit" menu item.
This is what I have so far, and I tried both ways with no success. How is this achieved?
main.py
import wx
import menus
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "My App Title", size=(1200, 800))
self.panel = wx.Panel(self, wx.ID_ANY)
mainMenu = menus.MainMenu()
mainMenu.build_main_menu(self)
def onExit(self):
self.Close()
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
frame.Show()
app.MainLoop()
menus.py
from wx import Menu, MenuBar, MenuEvent, MenuItem, Frame, EVT_MENU
class MainMenu(object):
def build_main_menu(self, frame):
self.fileMenu = Menu()
exitMenuItem = self.fileMenu.Append(101, "E&xit", "Close the application")
menuBar = MenuBar()
menuBar.Append(self.fileMenu, "&File")
frame.Bind(EVT_MENU, MainFrame.onExit(frame), exitMenuItem)
frame.SetMenuBar(menuBar)
return self
You are really close, but just not quite there. For this sort of thing, there is no need to wrap the menu creation code inside a class, so I changed that to just a function. Here's menu.py:
from wx import Menu, MenuBar, MenuEvent, MenuItem, Frame, EVT_MENU
def build_main_menu(frame):
fileMenu = Menu()
exitMenuItem = fileMenu.Append(101, "E&xit", "Close the application")
menuBar = MenuBar()
menuBar.Append(fileMenu, "&File")
frame.Bind(EVT_MENU, frame.onExit, exitMenuItem)
frame.SetMenuBar(menuBar)
Note that you need to call the onExit using the frame instance, not by trying to call it via a class (MainFrame) that you haven't even imported. Also you do not call an event handler in the bind operation. It will get called when the button is pressed.
Next I updated your main.py:
import wx
import menus
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "My App Title", size=(1200, 800))
self.panel = wx.Panel(self, wx.ID_ANY)
mainMenu = menus.build_main_menu(self)
def onExit(self, event):
self.Close()
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
frame.Show()
app.MainLoop()
There are two changes here. First we don't need to create an instance of the menu module's class as there is no class any longer. Secondly event handlers take two arguments: self and event.
Now it works!
So I am a complete beginner at python and usually code in C/C++ or Java. In the process of developing a GUI my events keep getting called at the start of the program running instead of when I click the button. (i know my indents are wrong because I needed to put it into a code block). How do I make my events only get called when I left click the button?
def __init__(self, parent, title):
super(QuadDash, self).__init__(parent, title=title, size=(1024, 780))
self.SetBackgroundColour("white")
pnl = wx.Panel(self)
cbtn = wx.Button(pnl, label='Start Quad', pos=(20,30))
self.Bind(wx.EVT_LEFT_DOWN, self.start_quad_event(), cbtn)
self.Show(True)
def start_quad_event(self):
dlg = wx.MessageDialog(self, "Test", "ABC", wx.YES_NO | wx.ICON_QUESTION)
dlg.ShowModal()
if __name__ == '__main__':
app = wx.App()
qd = QuadDash(None, title='QuadCopter Dashboard')
app.MainLoop()
The offending line is:
self.Bind(wx.EVT_LEFT_DOWN, self.start_quad_event(), cbtn)
You actually call start_quad_event() and pass the result to bind().
The correct line is:
self.Bind(wx.EVT_LEFT_DOWN, self.start_quad_event, cbtn)
Note: No parentheses. Here you actually pass the function to bind().
I am learning to use wxPython to build a dialogue based program.
I tried following code (simply copied from wxPython Demo):
import wx
#---------------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a DirDialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
# In this case we include a "New directory" button.
dlg = wx.DirDialog(self, "Choose a directory:",
style=wx.DD_DEFAULT_STYLE
#| wx.DD_DIR_MUST_EXIST
#| wx.DD_CHANGE_DIR
)
# If the user selects OK, then we process the dialog's data.
# This is done by getting the path data from the dialog - BEFORE
# we destroy it.
if dlg.ShowModal() == wx.ID_OK:
self.log.WriteText('You selected: %s\n' % dlg.GetPath())
# Only destroy a dialog after you're done with it.
dlg.Destroy()
#---------------------------------------------------------------------------
def runTest(frame, nb, log):
win = TestPanel(nb, log)
return win
#---------------------------------------------------------------------------
overview = """\
This class represents the directory chooser dialog. It is used when all you
need from the user is the name of a directory. Data is retrieved via utility
methods; see the <code>DirDialog</code> documentation for specifics.
"""
if __name__ == '__main__':
import sys,os
import run
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
I ran above code both in Python IDLE and Apatana Studio 3. Here is what I got.
In Python IDLE, I've got:
IDLE Subprocess: no IP port passed in sys.argv.
And in Apatana Studio 3, I've got:
Traceback (most recent call last):
File "C:\Users\User\My Documents\Aptana Studio 3 Workspace\Test Dialogue\main.py", line 61, in
import run ImportError: No module named run
May I know what am I wrong? Thanks a lot. :)
The ImportError is the Python interpreter (the program that runs your Python code) letting you know it cannot find the module (.py file) you are trying to import. Specifically, the error is saying it cannot find the module "run" which you have asked it to import on line 61.
When you do an import in Python, the interpreter searches a bunch of places for the module. One of those is the current directory, and the rest are standard places like where Python libraries are installed. This page has some info about it: http://docs.python.org/2/tutorial/modules.html#the-module-search-path. You'll actually get the same ImportError if you run the program from the command line. It's a Python error, not an Apatana Studio 3 error.
So if you copy "run.py" into the directory with your Python file, the Python interpreter will be able to easily find it when you asks it to import. Another way is to leave the run.py module where it is and change the sys.path at runtime, or add the module location to the PYTHONPATH variable (see link above for more info).
The run.py module isn't needed for what you are trying to achieve though. Here's an example of your code without the run.py module being imported. I'll warn that I'm new to wxPython myself so there may be better ways to do it ;-)
import wx
# This Log class is copied from the run module
class Log(object):
def WriteText(self, text):
if text[-1:] == '\n':
text = text[:-1]
wx.LogMessage(text)
write = WriteText
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = Log()
wx.Panel.__init__(self, parent, -1)
b = wx.Button(self, -1, "Create and Show a DirDialog", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
def OnButton(self, evt):
# In this case we include a "New directory" button.
dlg = wx.DirDialog(self, "Choose a directory:",
style=wx.DD_DEFAULT_STYLE
#| wx.DD_DIR_MUST_EXIST
#| wx.DD_CHANGE_DIR
)
# If the user selects OK, then we process the dialog's data.
# This is done by getting the path data from the dialog - BEFORE
# we destroy it.
if dlg.ShowModal() == wx.ID_OK:
self.log.WriteText('You selected: %s\n' % dlg.GetPath())
# Only destroy a dialog after you're done with it.
dlg.Destroy()
class Frame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__(self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size(300, 150))
panel = TestPanel(self, -1)
class App(wx.App):
def OnInit(self):
self.frame = Frame(parent=None)
self.frame.Show()
self.SetTopWindow(self.frame)
return True
if __name__ == '__main__':
app = App()
app.MainLoop()
I'm not sure what's happening with the error in IDLE though. That's weird!
I am building a Python program that searches things on a remote website.
Sometimes the operation takes many seconds and I believe that the user will not notice the status bar message "Search Operation in progress".
Therefore, I would like to change the mouse cursor to highlight that the program is still waiting for a result.
This is the method I am using:
def OnButtonSearchClick( self, event ):
"""
If there is text in the search text, launch a SearchOperation.
"""
searched_value = self.m_search_text.GetValue()
if not searched_value:
return
# clean eventual previous results
self.EnableButtons(False)
self.CleanSearchResults()
operations.SearchOperation(self.m_frame, searched_value)
I tried two different approaches, both before the last line:
wx.BeginBusyCursor()
self.m_frame.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
None of them are working.
I am using KDE under GNU/Linux. This does not work under Gnome, too
Any hints? Thank you
I asked Robin Dunn, the maker of wxPython about this, and it looks like this should work, but doesn't. However, if you call the panel's SetCursor(), it DOES work or so I'm told. Here's an example you can try:
import wx
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
# Add a self.panel so it looks the correct on all platforms
self.panel = wx.Panel(self, wx.ID_ANY)
btn = wx.Button(self.panel, label="Change Cursor")
btn.Bind(wx.EVT_BUTTON, self.changeCursor)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(btn)
self.panel.SetSizer(sizer)
#----------------------------------------------------------------------
def changeCursor(self, event):
""""""
myCursor= wx.StockCursor(wx.CURSOR_WAIT)
self.panel.SetCursor(myCursor)
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()