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.
Related
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 have been looking around the web since early morning and I can't seem to figure out how to get wxPython to show a dialogue box on my main frame.
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Window',size=(400,300))
panel = wx.Panel(self)
test = wx.TextEntryDialog(panel, 'Enter your word:',"New word","",
style=wx.OK|wx.CANCEL|wx.CENTRE,pos=(100,200))
def main():
pass
if __name__ == '__main__':
app = wx.App()
frame=MainWindow(parent=None,id=1)
frame.Show()
app.MainLoop()
It just opens a window without a text dialogue.
Use:
Dlg = wx.TextEntryDialog(panel, 'Enter your word:',"New word","",
style=wx.OK|wx.CANCEL|wx.CENTRE,pos=(100,200))
if Dlg.ShowModal() == wx.OK:
test = Dlg.GetValue()
del Dlg
As wx.TextEntryDialog is a dialogue class not one of the convenience dialogue functions you need to show it and get the value rather than just getting a reply.
I need to bind the EVT_CHAR event for a GUI application I am developing using wxPython. I tried the following and I cann understand the beahviour of the code.
import wx
import wx.lib.agw.flatnotebook as fnb
class DemoApp(wx.App):
def __init__(self):
wx.App.__init__(self, redirect=False)
self.mainFrame = DemoFrame()
self.mainFrame.Show()
def OnInit(self):
return True
class DemoFrame(wx.Frame):
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, wx.ID_ANY,
"FlatNotebook Tutorial",
size=(600,400)
)
panel = wx.Panel(self)
button = wx.Button(panel, label="Close", pos=(125, 10), size=(50, 50))
self.Bind(wx.EVT_CHAR, self.character)
def character(self, event):
print "Char keycode : {0}".format(event.GetKeyCode())
if __name__ == "__main__":
app = DemoApp()
app.MainLoop()
The character function never gets called. However, when I comment out the two lines call to the Frame constructor, I character function is called. Adding a panel to the frame seems to interfere with the binding of the frame's EVT_CHAR.
How do I address this problem? Am I doing something wrong in my code?
The problem is that you are catching events that happen to the frame, but the frame is not in focus. The button is. In wxPython, events are sent to the widget in focus. If you add this to the end of your init, it works:
self.SetFocus()
However, if you change the focus to the button, then it will stop working again. See also:
wxpython capture keyboard events in a wx.Frame
http://www.blog.pythonlibrary.org/2009/08/29/wxpython-catching-key-and-char-events/
http://wxpython-users.1045709.n5.nabble.com/Catching-key-events-from-a-panel-and-follow-up-to-stacked-panels-td2360109.html
I appreciate that this question was answered 2 years ago but this issue catches us all out at some point or other.
It is the classic binding to wx.Event or wx.CommandEvent problem.
In this case simply changing the self.Bind(wx.EVT_CHAR, self.character) line to read button.Bind(wx.EVT_CHAR, self.character) will solve the problem, detailed above.
The issue of wx.Event - wx.CommandEvent is covered in full here:
http://wiki.wxpython.org/EventPropagation
and here:
http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind
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()