I'm trying to create an application in wxpython that only uses a TaskBarIcon and no frames.
There is a question on this here, but that example doesn't work for me; it just exits with no error.
The code I've written below is a much simplified version of the code I'm working with:
import wx
class Systray_Icon(wx.TaskBarIcon):
def __init__(self):
icon = wx.Icon('yellow.ico', wx.BITMAP_TYPE_ICO)
self.SetIcon(icon, "Test")
self.Bind(wx.EVT_MENU, self.Destroy(), id=wx.ID_EXIT)
def CreatePopupMenu(self):
menu = wx.Menu()
menu.Append(wx.ID_EXIT, "Quit")
return menu
app = wx.App()
sysicon = Systray_Icon()
app.MainLoop()
I'm getting the following error:
$ python2 systray.py
Traceback (most recent call last):
File "systray.py", line 15, in <module>
sysicon = TaskBarIcon()
File "systray.py", line 6, in __init__
self.SetIcon(icon, "Test")
File "/usr/lib/python2.7/dist-packages/wx-3.0-gtk2/wx/_windows.py", line 2841, in SetIcon
return _windows_.TaskBarIcon_SetIcon(*args, **kwargs)
TypeError: in method 'TaskBarIcon_SetIcon', expected argument 1 of type 'wxPyTaskBarIcon *'
So, my questions:
1: Why won't SetIcon accept my class? I've tried moving the SetIcon call to a function like in the question I linked, but it still doesn't work. I can fiddle around with it and probably get something to work, but I'd like to know the reason it won't work.
2: The question I linked to runs, but exits immediately. Is that because a TaskBarIcon won't hold MainLoop() open? What can I do about this?
Here is a working sample on Linux with python 2.7 wxpython 2.8:
import wx
TRAY_TOOLTIP = 'System Tray Demo'
TRAY_ICON = '/usr/share/pixmaps/thunderbird.xpm'
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.AppendItem(item)
return item
class TaskBarIcon(wx.TaskBarIcon):
def __init__(self):
wx.TaskBarIcon.__init__(self)
self.set_icon(TRAY_ICON)
self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, 'Say Hello', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, 'Exit', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.IconFromBitmap(wx.Bitmap(path))
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print 'Tray icon was left-clicked.'
def on_hello(self, event):
print 'Hello, world!'
def on_exit(self, event):
wx.CallAfter(self.Destroy)
def main():
app = wx.App()
TaskBarIcon()
app.MainLoop()
if __name__ == '__main__':
main()
EDIT:
For anyone still getting grief this is a version that essentially uses a dummy frame.
Edit 2019: Updated for python3/wxpython 4+
import wx
import wx.adv
TRAY_TOOLTIP = 'System Tray Demo'
TRAY_ICON = '/usr/share/pixmaps/python.xpm'
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.Append(item)
return item
class TaskBarIcon(wx.adv.TaskBarIcon):
def __init__(self,frame):
wx.adv.TaskBarIcon.__init__(self)
self.myapp_frame = frame
self.set_icon(TRAY_ICON)
self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, 'Say Hello', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, 'Exit', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.Icon(wx.Bitmap(path))
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print ('Tray icon was left-clicked.')
def on_hello(self, event):
print ('Hello, world!')
def on_exit(self, event):
self.myapp_frame.Close()
class My_Application(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "", size=(1,1))
panel = wx.Panel(self)
self.myapp = TaskBarIcon(self)
self.Bind(wx.EVT_CLOSE, self.onClose)
#----------------------------------------------------------------------
def onClose(self, evt):
"""
Destroy the taskbar icon and the frame
"""
self.myapp.RemoveIcon()
self.myapp.Destroy()
self.Destroy()
if __name__ == "__main__":
MyApp = wx.App()
My_Application()
MyApp.MainLoop()
OK, figured it out the next day, after 30 minutes of messing about.
SetIcon wasn't accepting my class because I needed to add the following:
super(TaskBarIcon, self).__init__()
to __init__.
I suspect it's duck typing biting me here; without the wx.TaskBarIcon constructor running, python doesn't see it as a wx.TaskBarIcon object.
To keep the application open with only a TaskBarIcon, create a derived class from wx.App and override the OnInit function, like so:
class App(wx.App):
def OnInit(self):
self.SetTopWindow(wx.Frame(None, -1))
TaskBarIcon()
return True
Related
I want to open a TextEntryDialog, when user clicks the button. So if i have a button in the parent frame which i am going to bind this way:
self.Bind(wx.EVT_BUTTON, self.OnAddNew, self.add_new_btn)
Now i have to open a TextEntryDialog when user clicks the button add_new. I want to make textentrydialog somewthing like this
Python, Using wxPython to get multiple input from user
How can i do that? Do i need to just paste that code in ` def OnAddNew(self, event):
Here is the pastebin link to my code: https://pastebin.com/UEYscgFa
I have created class inside a function, so is it possible to do in that way?
NO!
GetData is a class in its own right.
That code already provides you with the method.
The MyFrame is all fluff, to create a standalone working example.
def OnButton(self,event):
dlg = GetData(parent = self.panel)
dlg.ShowModal()
if dlg.result_name:
self.log.AppendText("Name: "+dlg.result_name+"\n")
self.log.AppendText("Surname: "+dlg.result_surname+"\n")
self.log.AppendText("Nickname: "+dlg.result_nickname+"\n")
else:
self.log.AppendText("No Input found\n")
dlg.Destroy()
Edit: I don't understand where the instructions in my comments eluded you but for my sins, here is your code cleaned up and edited as in the comments.
import sqlite3
import wx
import os
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title, size=(1000,800))
self.inter_list = list()
self.plot_list = list()
self.InitUI()
self.Layout()
self.Centre()
self.Show()
def InitUI(self):
self.p = wx.Panel(self)
bs = wx.BoxSizer(wx.VERTICAL)
gs = wx.GridSizer(10, 18, 5, 5)
bs.Add(gs, 1, wx.EXPAND)
self.search_btn=wx.Button(self.p,-1,"Search!")
self.search_btn.Bind(wx.EVT_BUTTON, self.OnSearch, self.search_btn)
bs.Add(self.search_btn,0,wx.ALIGN_CENTER)
self.p.SetSizer(bs)
def OnSearch(self, event):
dlg = GetData(parent = self.p)
dlg.ShowModal()
if dlg.result_name:
print "Name: "+dlg.result_name+"\n"
print "Surname: "+dlg.result_surname+"\n"
print "Nickname: "+dlg.result_nickname+"\n"
else:
print "No Input found\n"
dlg.Destroy()
class GetData(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, wx.ID_ANY, "Name Input", size= (650,220))
self.p = wx.Panel(self,wx.ID_ANY)
self.lblname = wx.StaticText(self.p, label="Name", pos=(20,20))
self.name = wx.TextCtrl(self.p, value="", pos=(110,20), size=(500,-1))
self.lblsur = wx.StaticText(self.p, label="Surname", pos=(20,60))
self.surname = wx.TextCtrl(self.p, value="", pos=(110,60), size=(500,-1))
self.lblnick = wx.StaticText(self.p, label="Nickname", pos=(20,100))
self.nickname = wx.TextCtrl(self.p, value="", pos=(110,100), size=(500,-1))
self.saveButton =wx.Button(self.p, label="Save", pos=(110,160))
self.closeButton =wx.Button(self.p, label="Cancel", pos=(210,160))
self.saveButton.Bind(wx.EVT_BUTTON, self.SaveConnString)
self.closeButton.Bind(wx.EVT_BUTTON, self.OnQuit)
self.Bind(wx.EVT_CLOSE, self.OnQuit)
self.Show()
def OnQuit(self, event):
self.result_name = None
self.Destroy()
def SaveConnString(self, event):
self.result_name = self.name.GetValue()
self.result_surname = self.surname.GetValue()
self.result_nickname = self.nickname.GetValue()
self.Destroy()
app = wx.App()
Example(None, title = 'Raman Spectroscopy Database')
app.MainLoop()
Python 2.7, WxPython 3.0.2
We are trying to automatically close an entire program under certain conditions. For various reasons, we can't just kill the process. We've had some level of success with it. We can close it if there's no modal dialogs, or a single modal dialog. Once we introduce the second modal dialog (nested), it fails to stop properly.
The actual error received appears to be:
wx._core.PyAssertionError: C++ assertion "IsRunning()" failed at ..\..\src\common\evtloopcmn.cpp(83) in wxEventLoopBase::Exit(): Use ScheduleExit() on not running loop
Here's a working example of our issue. The frame will automatically close after 5 seconds. Clicking the button will load a dialog. Clicking the button on the dialog will open another dialog. It works fine until the last dialog is opened.
from threading import Thread
from time import sleep
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="TEST", size=(400, 400))
self.Show()
self.__someDialog = None
self.__myThread = None
self.__okButton = wx.Button(self, -1, "Press me")
self.Bind(wx.EVT_BUTTON, self.__onOK)
self.__myThread = Thread(target=self.__waitThenClose, name="Closer")
self.__myThread.setDaemon(True)
self.__myThread.start()
def __onOK(self, evt):
self.__someDialog = SomeDialog(self)
self.__someDialog.ShowModal()
def closeOpenDialogs(self):
lst = wx.GetTopLevelWindows()
for i in range(len(lst) - 1, 0, -1):
if isinstance(lst[i], wx.Dialog):
print "Closing " + str(lst[i])
lst[i].Close(True)
#lst[i].Destroy()
def __waitThenClose(self):
for x in range(0, 5):
print "Sleeping..."
sleep(1)
self.closeOpenDialogs()
wx.CallAfter(self.Close, True)
class SomeDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, id=-1, title='Some Dialog')
self.SetSize((300, 300))
self.__anotherDialog = None
self.__okButton = wx.Button(self, -1, "Press me")
self.Bind(wx.EVT_BUTTON, self.__onOK)
wx.EVT_CLOSE(self, self.__on_btn_cancel)
def __onOK(self, evt):
self.__anotherDialog = AnotherDialog(self)
self.__anotherDialog.ShowModal()
def __on_btn_cancel(self, event):
self.EndModal(wx.ID_CANCEL)
class AnotherDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, None, id=-1, title='Another Dialog')
self.SetSize((200, 200))
wx.EVT_CLOSE(self, self.__on_btn_cancel)
def __on_btn_cancel(self, event):
self.EndModal(wx.ID_CANCEL)
if __name__ == "__main__":
app = wx.App()
mainFrame = MainFrame()
app.MainLoop()
I think what is happening here is that the first call to ShowModal() blocks the at the app level (not just the frame level) which is preventing the second dialog from becoming fully initialized. To work around this issue I would call Show() instead of ShowModal() and add wx.FRAME_FLOAT_ON_PARENT to the dialog style flags. You can also call Disable() on the parts of the program you don't want the user to interact with while the dialogs are open.
EDIT: Here is a working example:
from threading import Thread
from time import sleep
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="TEST", size=(400, 400))
self.Show()
self.__someDialog = None
self.__okButton = wx.Button(self, -1, "Press me")
self.Bind(wx.EVT_BUTTON, self.__onOK)
self.__myThread = Thread(target=self.__waitThenClose, name="Closer")
self.__myThread.setDaemon(True)
self.__myThread.start()
def __onOK(self, evt):
self.__someDialog = SomeDialog(self)
self.__someDialog.ShowModal()
def closeOpenDialogs(self, evt=None):
lst = wx.GetTopLevelWindows()
for i in range(len(lst) - 1, 0, -1):
dialog = lst[i]
if isinstance(dialog, wx.Dialog):
print "Closing " + str(dialog)
# dialog.Close(True)
wx.CallAfter(dialog.Close)
# sleep(1)
# dialog.Destroy()
def __waitThenClose(self):
for x in range(0, 10):
print "Sleeping..."
sleep(1)
wx.CallAfter(self.closeOpenDialogs)
wx.CallAfter(self.Close, True)
class SomeDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, id=-1, title='Some Dialog')
self.SetSize((300, 300))
self.__anotherDialog = None
self.__okButton = wx.Button(self, -1, "Press me")
self.Bind(wx.EVT_BUTTON, self.__onOK)
wx.EVT_CLOSE(self, self.__on_btn_cancel)
def __onOK(self, evt):
self.__anotherDialog = AnotherDialog(self)
self.__anotherDialog.SetWindowStyleFlag(
wx.FRAME_FLOAT_ON_PARENT|wx.DEFAULT_DIALOG_STYLE)
self.__anotherDialog.Show()
def __on_btn_cancel(self, event):
event.Skip()
self.EndModal(wx.ID_CANCEL)
class AnotherDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, id=-1, title='Another Dialog')
self.SetSize((200, 200))
wx.EVT_CLOSE(self, self.__on_btn_cancel)
parent.Disable()
def __on_btn_cancel(self, event):
event.Skip()
self.GetParent().Enable()
# self.EndModal(wx.ID_CANCEL)
if __name__ == "__main__":
app = wx.App()
mainFrame = MainFrame()
app.MainLoop()
The only way to reliably gracefully close all the modal dialogs, whether they were explicitly opened by your own code or not, is to use wxModalDialogHook to remember all the opened dialogs and then close them all, in the reverse (i.e. LIFO) order, before quitting the application.
Unfortunately I don't know if wxModalDialogHook is available in Python.
I'd just need a quick example on how to easily put an icon with python on my systray. This means: I run the program, no window shows up, just a tray icon (I've got a png file) shows up in the systray and when I right-click on it a menu appears with some options (and when I click on an option, a function is run).
Is that possible? I don't need any window at all...
Examples / code snippets are REALLY appreciated! :D
For Windows & Gnome
Here ya go! wxPython is the bomb. Adapted from the source of my Feed Notifier application.
import wx
TRAY_TOOLTIP = 'System Tray Demo'
TRAY_ICON = 'icon.png'
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.AppendItem(item)
return item
class TaskBarIcon(wx.TaskBarIcon):
def __init__(self):
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, 'Say Hello', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, 'Exit', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.IconFromBitmap(wx.Bitmap(path))
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print 'Tray icon was left-clicked.'
def on_hello(self, event):
print 'Hello, world!'
def on_exit(self, event):
wx.CallAfter(self.Destroy)
def main():
app = wx.PySimpleApp()
TaskBarIcon()
app.MainLoop()
if __name__ == '__main__':
main()
2018 version
import wx.adv
import wx
TRAY_TOOLTIP = 'Name'
TRAY_ICON = 'icon.png'
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.Append(item)
return item
class TaskBarIcon(wx.adv.TaskBarIcon):
def __init__(self, frame):
self.frame = frame
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, 'Site', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, 'Exit', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.Icon(path)
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print ('Tray icon was left-clicked.')
def on_hello(self, event):
print ('Hello, world!')
def on_exit(self, event):
wx.CallAfter(self.Destroy)
self.frame.Close()
class App(wx.App):
def OnInit(self):
frame=wx.Frame(None)
self.SetTopWindow(frame)
TaskBarIcon(frame)
return True
def main():
app = App(False)
app.MainLoop()
if __name__ == '__main__':
main()
wx.PySimpleApp deprecated, here's how to use wx.App instead
Took me while to figure this out so I thought I'd share. wx.PySimpleApp is deprecated in wxPython 2.9 and beyond. Here's FogleBird's original script using wx.App instead.
import wx
TRAY_TOOLTIP = 'System Tray Demo'
TRAY_ICON = 'icon.png'
def create_menu_item(menu, label, func):
item = wx.MenuItem(menu, -1, label)
menu.Bind(wx.EVT_MENU, func, id=item.GetId())
menu.AppendItem(item)
return item
class TaskBarIcon(wx.TaskBarIcon):
def __init__(self, frame):
self.frame = frame
super(TaskBarIcon, self).__init__()
self.set_icon(TRAY_ICON)
self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
def CreatePopupMenu(self):
menu = wx.Menu()
create_menu_item(menu, 'Say Hello', self.on_hello)
menu.AppendSeparator()
create_menu_item(menu, 'Exit', self.on_exit)
return menu
def set_icon(self, path):
icon = wx.IconFromBitmap(wx.Bitmap(path))
self.SetIcon(icon, TRAY_TOOLTIP)
def on_left_down(self, event):
print 'Tray icon was left-clicked.'
def on_hello(self, event):
print 'Hello, world!'
def on_exit(self, event):
wx.CallAfter(self.Destroy)
self.frame.Close()
class App(wx.App):
def OnInit(self):
frame=wx.Frame(None)
self.SetTopWindow(frame)
TaskBarIcon(frame)
return True
def main():
app = App(False)
app.MainLoop()
if __name__ == '__main__':
main()
If you can guarantee windows and you do not want to introduce the heavy dependencies of wx, you can do this with the pywin32 extensions.
Also see this question.
For Ubuntu
class TrayIcon:
def init():
iconPath = {"Windows":os.path.expandvars("%PROGRAMFILES%/MyProgram/icon.png"),
"Linux":"/usr/share/icons/myprogramicon.png"}
if platform.system()=="Linux":
import gtk
import appindicator # Ubuntu apt-get install python-appindicator
# Create an application indicator
try:
gtk.gdk.threads_init()
gtk.threads_enter()
icon = iconPath[platform.system()]
indicator = appindicator.Indicator("example-simple-client", "indicator-messages", appindicator.CATEGORY_APPLICATION_STATUS)
indicator.set_icon(icon)
indicator.set_status (appindicator.STATUS_ACTIVE)
indicator.set_attention_icon ("indicator-messages-new")
menu = gtk.Menu()
menuTitle = "Quit"
menu_items = gtk.MenuItem(menuTitle)
menu.append(menu_items)
menu_items.connect("activate", TrayIcon.QuitApp, menuTitle)
menu_items.show()
menuTitle = "About My Program"
menu_items = gtk.MenuItem(menuTitle)
menu.append(menu_items)
menu_items.connect("activate", TrayIcon.AboutApp, menuTitle)
menu_items.show()
indicator.set_menu(menu)
except:
pass
# Run the app indicator on the main thread.
try:
t = threading.Thread(target=gtk.main)
t.daemon = True # this means it'll die when the program dies.
t.start()
#gtk.main()
except:
pass
finally:
gtk.threads_leave()
#staticmethod
def AboutApp(a1,a2):
gtk.threads_enter()
dialog = gtk.Dialog("About",
None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
label = gtk.Label("My Program v0.0.1, (C)opyright ME 2015. All rights reserved.")
dialog.vbox.pack_start(label)
label.show()
label2 = gtk.Label("example.com\n\nFor more support contact me#gmail.com")
label2.show()
dialog.action_area.pack_end(label2)
response = dialog.run()
dialog.destroy()
gtk.threads_leave()
#staticmethod
def QuitApp(a1, a2):
sys.exit(0)
Cross-Platform
See PyQt: Show menu in a system tray application
There is a package called pystray (bad name, just say it out loud) but works like a charm and is more lightweight than wx or Qt. These are the links:
https://pystray.readthedocs.io/en/latest/index.html
https://pypi.org/project/pystray/
Yes. There is a cross-platform example on wiki.wxpython.org that I've tested with python 2.7 (minconda install) on macOS High Sierra (10.13.3), Windows 7, and gnome 3/centos7. It is here (ignore the page title):
https://wiki.wxpython.org/Custom%20Mac%20OsX%20Dock%20Bar%20Icon
Small mods are needed for python 3.6:
you must import wx.adv
wx.TaskBarIcon becomes wx.adv.TaskBarIcon
wx.IconFromBitmap becomes wx.Icon
Gnome 3 required installation of TopIcons Plus.
Since you don't want to have the window display (" no window shows up, just a tray icon"), simply comment out the following line (though you still want to keep the wx.Frame parent):
frame.Show(True)
And since you want to use your own .png icon, remove the WXPdemo image and embeddedimage stuff and replace
icon = self.MakeIcon(WXPdemo.GetImage())
with, for example
icon = wx.Icon('icon.png')
In my experience, this will provide a good start for adapting or extending further.
An alternative if you are trying to run a python based program in the background you can run it as a service. Check out this active state recipe its pretty useful. I believe one of the options is to convert your application to exe with py2exe or pyinstall.
http://code.activestate.com/recipes/551780/
For an example, refer to this thread -> wx question.
wxPython "classic" -> [new API] wxPython 'Phoenix' (Py3)
I am trying to write a simple custom button in wx.Python. My code is as follows, an error is thrown on line 19 of my "Custom_Button.py" - What is going on? I can find no help online for this error and have a suspicion that it has to do with the Polymorphism. (As a side note: I am relatively new to python having come from C++ and C# any help on syntax and function of the code would be great! - knowing that, it could be a simple error. thanks!)
Error
def __init__(self, parent, id=-1, NORM_BMP, PUSH_BMP, MOUSE_OVER_BMP, **kwargs):
SyntaxError: non-default argument follows default argument
Main.py
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition, wxSize(400, 400))
self.CreateStatusBar()
self.SetStatusText("Program testing custom button overlays")
menu = wxMenu()
menu.Append(ID_ABOUT, "&About", "More information about this program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")
menuBar = wxMenuBar()
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
self.Button1 = Custom_Button(self, parent, -1,
"D:/Documents/Python/Normal.bmp",
"D:/Documents/Python/Clicked.bmp",
"D:/Documents/Python/Over.bmp",
"None", wx.Point(200,200), wx.Size(300,100))
EVT_MENU(self, ID_ABOUT, self.OnAbout)
EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def OnAbout(self, event):
dlg = wxMessageDialog(self, "Testing the functions of custom "
"buttons using pyDev and wxPython",
"About", wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def TimeToQuit(self, event):
self.Close(true)
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(NULL, -1, "wxPython | Buttons")
frame.Show(true)
self.SetTopWindow(frame)
return true
app = MyApp(0)
app.MainLoop()
Custom Button
import wx
from wxPython.wx import *
class Custom_Button(wx.PyControl):
############################################
##THE ERROR IS BEING THROWN SOME WHERE IN HERE ##
############################################
# The BMP's
Mouse_over_bmp = wx.Bitmap(0) # When the mouse is over
Norm_bmp = wx.Bitmap(0) # The normal BMP
Push_bmp = wx.Bitmap(0) # The down BMP
Pos_bmp = wx.Point(0,0) # The posisition of the button
def __init__(self, parent, NORM_BMP, PUSH_BMP, MOUSE_OVER_BMP, text="",
pos, size, id=-1, **kwargs):
wx.PyControl.__init__(self,parent, id, **kwargs)
# Set the BMP's to the ones given in the constructor
self.Mouse_over_bmp = wx.Bitmap(MOUSE_OVER_BMP)
self.Norm_bmp = wx.Bitmap(NORM_BMP)
self.Push_bmp = wx.Bitmap(PUSH_BMP)
self.Pos_bmp = pos
############################################
##THE ERROR IS BEING THROWN SOME WHERE IN HERE ##
############################################
self.Bind(wx.EVT_LEFT_DOWN, self._onMouseDown)
self.Bind(wx.EVT_LEFT_UP, self._onMouseUp)
self.Bind(wx.EVT_LEAVE_WINDOW, self._onMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self._onMouseEnter)
self.Bind(wx.EVT_ERASE_BACKGROUND,self._onEraseBackground)
self.Bind(wx.EVT_PAINT,self._onPaint)
self._mouseIn = self._mouseDown = False
def _onMouseEnter(self, event):
self._mouseIn = True
def _onMouseLeave(self, event):
self._mouseIn = False
def _onMouseDown(self, event):
self._mouseDown = True
def _onMouseUp(self, event):
self._mouseDown = False
self.sendButtonEvent()
def sendButtonEvent(self):
event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
event.SetInt(0)
event.SetEventObject(self)
self.GetEventHandler().ProcessEvent(event)
def _onEraseBackground(self,event):
# reduce flicker
pass
def _onPaint(self, event):
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(self.Norm_bmp)
# draw whatever you want to draw
# draw glossy bitmaps e.g. dc.DrawBitmap
if self._mouseIn: # If the Mouse is over the button
dc.DrawBitmap(self, self.Mouse_over_bmp, self.Pos_bmp, useMask=False)
if self._mouseDown: # If the Mouse clicks the button
dc.DrawBitmap(self, self.Push_bmp, self.Pos_bmp, useMask=False)
In function definitions, arguments with default values need to be listed after arguments without defaults, but before *args and **kwargs expansions
Before:
def __init__(self, parent, id=-1, NORM_BMP, PUSH_BMP, MOUSE_OVER_BMP, text="",
pos, size, **kwargs)
Corrected:
def __init__(self, parent, NORM_BMP, PUSH_BMP, MOUSE_OVER_BMP,
pos, size, id=-1, text="", **kwargs)
I would like to add an icon to the OSX menu bar at the top of the screen using wxPython. I have tried wx.TaskBarIcon, which adds a System Tray icon in Windows, but this doesn't work - it changes the Dock icon for the app instead. Does anyone know how to do this?
It seems that with wxPython2.9-osx-cocoa-py2.7 you can in fact put up a menubar icon. It looks like you can also call PopupMenu() on TaskBarIcon to attach a menu, which you should be able to use to create a full blown OSX menu bar application.
import wx
class TaskBarFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, style=wx.FRAME_NO_TASKBAR |
wx.NO_FULL_REPAINT_ON_RESIZE)
self.tbicon = wx.TaskBarIcon()
icon = wx.Icon('myicon.ico', wx.BITMAP_TYPE_ICO)
self.tbicon.SetIcon(icon, '')
app = wx.App(False)
frame = TaskBarFrame(None)
frame.Show(False)
app.MainLoop()
Answer provided here on Google Groups - in summary, you can't do it.
It seems now you can:
http://wiki.wxpython.org/Custom%20Mac%20OsX%20Dock%20Bar%20Icon?highlight=%28wx%5C.TaskBarIcon%29
just copy and paste the code and run it ;)
#!/usr/bin/env pythonw
import wx
import wx.lib.embeddedimage
WXPdemo = wx.lib.embeddedimage.PyEmbeddedImage(
"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAWlJ"
"REFUWIW1V1sSwjAIBMebeBU9db2KZ8EPmxbCI4TUnXGskWaXDQktwhjErjERP4XRhER08iPi"
"5SKiyQR5JyI7xxB3j7wn5GI6V2hFxM0gJtjYANFBiIjQu7L/1lYlwR0QxLDZhE0II1+CtwRC"
"RI8riBva7DL7CC9VAwDbbxwKtdDXwBi7K+1zCP99T1vDFedd8FBwYd6BCAUXuACEF7QsbET/"
"FaHs+gDQw4vOLNHkMojAnTw8nlNipIiwmR0DCXJbjCXkFCAL23BnpQgRWt1EMbyujCK9AZzZ"
"f+b3sX0oSqJQ6EorFeT4NiL6Wtj0+LXnQAzThYoAAsN6ehqR3sHExmcEqGeFApQLcTvm5Kt9"
"wkHGgb+RZwSkyc1dwOcpCtCoNKSz6FRCUQ3o7Nn+5Y+Lg+y5CIXlcyAk99ziiQS32+svz/UY"
"vClJoLpIC8gi+VwwfDecEiEtT/WZTJDf94uk1Ru8vbz0cvoF7S2DnpeVL9UAAAAASUVORK5C"
"YII=")
class DemoTaskBarIcon(wx.TaskBarIcon):
TBMENU_RESTORE = wx.NewId()
TBMENU_CLOSE = wx.NewId()
TBMENU_CHANGE = wx.NewId()
TBMENU_REMOVE = wx.NewId()
def __init__(self, frame):
wx.TaskBarIcon.__init__(self)
self.frame = frame
# Set the image
icon = self.MakeIcon(WXPdemo.GetImage())
self.SetIcon(icon, "wxPython Demo")
self.imgidx = 1
# bind some events
self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
def CreatePopupMenu(self):
"""
This method is called by the base class when it needs to popup
the menu for the default EVT_RIGHT_DOWN event. Just create
the menu how you want it and return it from this function,
the base class takes care of the rest.
"""
menu = wx.Menu()
menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
menu.Append(self.TBMENU_CLOSE, "Close wxPython Demo")
return menu
def MakeIcon(self, img):
"""
The various platforms have different requirements for the
icon size...
"""
if "wxMSW" in wx.PlatformInfo:
img = img.Scale(16, 16)
elif "wxGTK" in wx.PlatformInfo:
img = img.Scale(22, 22)
# wxMac can be any size upto 128x128, so leave the source img alone....
icon = wx.IconFromBitmap(img.ConvertToBitmap() )
return icon
def OnTaskBarActivate(self, evt):
if self.frame.IsIconized():
self.frame.Iconize(False)
if not self.frame.IsShown():
self.frame.Show(True)
self.frame.Raise()
def OnTaskBarClose(self, evt):
wx.CallAfter(self.frame.Close)
class MainFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="Hello World")
self.tbicon = DemoTaskBarIcon(self)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def OnCloseWindow(self, evt):
self.tbicon.Destroy()
evt.Skip()
app = wx.App(redirect=False)
frame = MainFrame(None)
frame.Show(True)
app.MainLoop()