So I'm working on a rhythm trainer, and using wxpython as the UI Toolkit. I was wondering if anyone knew how to bind keyboard presses to play sounds? So to put it simply, users can use the keyboard to play a drum beat. Example "Pressing the A key will play the bass drum"
Now I've come across a tutorial -
http://www.blog.pythonlibrary.org/2009/08/29/wxpython-catching-key-and-char-events/
But this seems like it needs the button to successfully play the sound. I've got a bit of the functionality working using this example. But I was wondering if there's another way to do it without the need of a button?
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Key Press Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
btn = wx.Button(panel, label="OK")
btn.Bind(wx.EVT_KEY_DOWN, self.onKeyPress)
def onKeyPress(self, event):
keycode = event.GetKeyCode()
print keycode
if keycode == ord('A'):
print "you pressed the spacebar!"
sound_file = "notation1.wav"
sound=wx.Sound(sound_file)
print(sound_file)
sound.Play(wx.SOUND_ASYNC)
event.Skip()
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm()
frame.Show()
app.MainLoop()
This is my example using the tutorial.
Cheers!
My tutorial is about catching keystrokes on the widget that's in focus. In the case of the tutorial, that was the button that was in focus and that was why it was bound to EVT_KEY_DOWN. Sadly, panels don't really accept focus very easily, so you'll be better off to set the focus on the panel manually using SetFocus() or bind the key event to most of the widgets.
You might be able to use an AcceleratorTable, but I'm not sure if that will work in your situation. Here's a link to a tutorial on that topic though:
http://www.blog.pythonlibrary.org/2010/12/02/wxpython-keyboard-shortcuts-accelerators/
Related
I am trying to add a feature to a calculator i have made with wxpython, i want there to be a button , that when clicked changes the background colour (the panel). To show you my code i have made a smaller program, that should only change colour, and even in this one i get the same outcome:
the background colour doesn't change, nothing happens when i click the button, and i dont even receive any errormessahe.Actually, the calculator does change colour, but not in the way i want it to, it only changes the colour of the text (a wx.StaticText), and it's not really meant to do that.
Anyway, here is the code :
import wx
class calc(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Calculator",size=(400,400))
global panel
panel=wx.Panel(self)
a=wx.Button(panel,label="GO",pos=(100,100),size=(50,50))
self.Bind(wx.EVT_BUTTON, self.change, a)
def change(self,event):
panel.SetBackgroundColour("red")
if __name__=="__main__":
app=wx.App(False)
frame=calc(parent=None,id=-1)
frame.Show()
app.MainLoop()
when i run this, the frame with the button show up, and when i click on the button, nothing happens!! Does anybody know what is wrong with this?
Thanks in advice!!!
While your code worked for me on Xubuntu 14.04, wxPython 2.8.12 and Python 2.7, I went ahead and rewrote it slightly to remove the global and clean it up a bit:
import wx
class calc(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Calculator", size=(400,400))
self.panel = wx.Panel(self)
a = wx.Button(self.panel, label="GO", pos=(100,100), size=(50,50))
self.Bind(wx.EVT_BUTTON, self.change, a)
def change(self,event):
self.panel.SetBackgroundColour("red")
self.Refresh() # for windows
if __name__=="__main__":
app = wx.App(False)
frame = calc()
frame.Show()
app.MainLoop()
This also works for me.
I have a simple wxPython application. It basically has a image and a text-entry field (a wx.TextCtrl).
I want to be able to immediately be able to start entering text as soon as the window opens. Right now, I have to first click in the text control, and then I can start entering text.
Here is a minimal app that demonstrates the issue:
import wx
class MyFrame(wx.Frame):
""" We simply derive a new class of Frame. """
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(200, 100))
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
mainSizer.Add(self.control, 1, wx.EXPAND)
self.SetSizer(mainSizer)
self.Show(True)
app = wx.App(False)
frame = MyFrame(None, 'Small editor')
app.MainLoop()
I've poked around with wx.SetInsertionPoint, but that does not seem to have any effect.
Ah, derp. I had to look further up the inheritance chain.
You can simply call SetFocus() on the control (in this case, self.control.SetFocus()).
SetFocus() is a member function of wxWindow. I was only looking at the docs for wxTextCtrl.
Of course, I didn't think to look up the inheritance chain until I had already asked the question.
I'm leaving this here, as this is a pretty hard to google issue. Hopefully this will help someone else.
Consider this:
import wx, time
# STEP 1: Setup Window
class Window(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Bobby the Window', size=(300,200))
panel = wx.Panel(self)
self.Bind(wx.EVT_CLOSE, self.closewindow)
wx.StaticText(panel, -1, "Yo user, the program is busy doing stuff!", (50,100), (200,100))
def closewindow(self, event):
self.Destroy()
# STEP 2: Show Window (run in background, probably with threading, if that is the best way)
if __name__=='__main__':
app = wx.PySimpleApp()
frame = Window(parent=None,id=-1)
frame.Show()
app.MainLoop()
# STEP 3: Do work
time.sleep(5)
# STEP 4: Close Window, and show user evidence of work
## *Update window to say: "I am done, heres what I got for you: ^blah blah info!^"*
exit()
My questions are:
In step 4, how do I change the text in the window (esp. if it is in a thread)?
And in step 2, how do I run the window in the background, but still be able to communicate with it? (to update the text and such)
This is similar to my question about how to run a cli progress bar and work at the same time, except with gui windows.
I know that to change StaticText, I would do 'text.SetLabel("BLAH!")', but how would I communicate that with the window class if it is running in the background?
Update:
This thread was also some help.
If you need to execute a long running process, then you will have to use some type of threading or perhaps the multiprocessing module. Otherwise you will block the GUI's main loop and make it unresponsive. You will also need to use wxPython's threadsafe methods to communicate with the GUI from the thread. They are wx.CallAfter, wx.CallLater and wx.PostEvent.
You can read more about wxPython and threads at the following:
http://wiki.wxpython.org/LongRunningTasks
http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
It's very overwhelming coming from something that helps you create applications straight forward to something with somewhat convoluted documentation.
Can someone please share a tutorial on how to create a simple Hello World application using Python. No, I don't mean command line. I mean a physical window.
I'm trying to learn how to program in Python and so far all I find is command line applications, and I don't really find use for them unless I can visually show off my skills.
So, where can I learn some Python GUI development. People have suggested wxWidgets, PyQT, etc. but once again, that means nothing to me, because I know diddly squat about them.
I need an up to date tutorial. :S
Here's a great tutorial for wxPython (my GUI API of choice: extremely powerful, good community/mailing list, and cross-platform (it wraps the native platform's widgets))
http://wiki.wxpython.org/Getting%20Started
Installing wxpython can be done through a simple setup.exe :
http://downloads.sourceforge.net/wxpython/wxPython2.8-win32-unicode-2.8.10.1-py26.exe or
http://downloads.sourceforge.net/wxpython/wxPython2.8-win32-unicode-2.8.10.1-py25.exe
(depending on python version)
Here's a simple hello world, with a simple event bound to the button.
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
text = wx.StaticText(self, label="hello, world!")
button = wx.Button(self, label="press me")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(text, flag=wx.ALL, border=20)
sizer.Add(button, flag=wx.ALL, border=20)
self.SetSizer(sizer)
self.Layout()
self.Show(True)
self.Bind(wx.EVT_BUTTON, self.on_button, button)
def on_button(self, event):
wx.MessageBox("Hey!")
if __name__ == "__main__":
app = wx.App(False)
f = MyFrame()
or, an even simpler example:
import wx
app = wx.PySimpleApp()
frame = wx.Frame(None, wx.ID_ANY, "Hello World")
frame.Show(True)
app.MainLoop()
app.MainLoop()
I'm designing an application that I want to run in the background. There isn't any user interaction necessary, so I want the app to run invisibly save for a systray icon. I want that icon to have a menu that just opens the config/help files in notepad. Could someone point me in the right direction or provide an example?
You can probably do this more cleanly but I have using some samples a while back I was able to create myself a class to handle the basic contruction of a taskbar icon.
TaskBarIcon.py
import wx
ID_SHOW_OPTION = wx.NewId()
ID_EDIT_OPTION = wx.NewId()
class Icon(wx.TaskBarIcon):
def __init__(self, parent, icon, tooltip):
wx.TaskBarIcon.__init__(self)
self.SetIcon(icon, tooltip)
self.parent = parent
self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnLeftDClick)
self.CreateMenu()
def CreateMenu(self):
self.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnPopup)
self.menu = wx.Menu()
self.menu.Append(ID_SHOW_OPTION, '&Show Option 1')
self.menu.Append(ID_EDIT_OPTION, '&Edit Option 2')
self.menu.AppendSeparator()
self.menu.Append(wx.ID_EXIT, 'E&xit')
def OnPopup(self, event):
self.PopupMenu(self.menu)
def OnLeftDClick(self, event):
if self.parent.IsIconized():
self.parent.Iconize(False)
if not self.parent.IsShown():
self.parent.Show(True)
self.parent.Raise()
Within your Frame's init(), add the two lines below:
self.TrayIcon = tbi.Icon(self, wx.Icon("C:\\YourIcon.png", wx.BITMAP_TYPE_PNG), "ToolTip Help Text Here")
self.Bind(wx.EVT_ICONIZE, self.OnIconify)
And now just add this function to your frame and you should be set:
def OnIconify(self, event):
self.Hide()
Just remember to edit the items in the Icon class to suit your needs.
Have you considered running this application as a windows service? Many users will consider a system tray icon with little to no functionality a nuisance. You could still provide links to help/config files as a start menu entry.
The python win32 extensions package should have support for python services.
Of course, there are still reasons why you may want to run this as a system tray icon. I'm sorry that I don't have any experience with that.
You want the wx.TaskBarIcon:
http://docs.wxwidgets.org/stable/wx_wxtaskbaricon.html
The wxPython Demo has example code you can look at.