无法在wxPython中正确使用wx.NotificationMessage
我最近升级到了wxPython的开发版本(wxPython 2.9.2.4),因为我需要在我的应用程序中使用wx.NotificationMessage这个功能。我一直在尝试创建一些通知气泡,来响应用户的某些操作,但一直没有成功。我觉得这可能是个bug。在提交这个bug之前,我想先问问邮件列表上的朋友们,看看他们觉得问题可能出在哪里,希望能在我的代码中找到解决方案。
这是我用的代码:
import wx, sys
app = wx.PySimpleApp()
class TestTaskBarIcon(wx.TaskBarIcon):
def __init__(self):
wx.TaskBarIcon.__init__(self)
# create a test icon
bmp = wx.EmptyBitmap(16, 16)
dc = wx.MemoryDC(bmp)
dc.SetBrush(wx.RED_BRUSH)
dc.Clear()
dc.SelectObject(wx.NullBitmap)
testicon = wx.EmptyIcon()
testicon.CopyFromBitmap(bmp)
self.SetIcon(testicon)
self.Bind(wx.EVT_TASKBAR_LEFT_UP, lambda e: (self.RemoveIcon(),sys.exit()))
wx.NotificationMessage("", "Hello world!").Show()
icon = TestTaskBarIcon()
app.MainLoop()
在我的Windows 7电脑上,这段代码创建了一个小白色的任务栏图标,并弹出了一个写着“Hello World!”的提示框。问题是?消息并没有显示在我的图标上,而是创建了另一个图标,消息被放在那里。你可以看看这个图片:
http://www.pasteall.org/pic/18068
我认为这可能是因为我在第22行没有传递父参数:
wx.NotificationMessage("", "Hello world!").Show()
这是我修改后的代码:
wx.NotificationMessage("", "Hello world!", self).Show()
这里的'self'指的是任务栏图标。当我这样做时,我收到了一个错误:
Traceback (most recent call last):
File "C:\Python27\testnotificationmessage.py", line 24, in <module>
icon = TestTaskBarIcon()
File "C:\Python27\testnotificationmessage.py", line 22, in __init__
wx.NotificationMessage("", "Hello world!", self).Show()
File "C:\Python27\lib\site-packages\wx-2.9.2-msw\wx\_misc.py", line 1213, in __init__
_misc_.NotificationMessage_swiginit(self,_misc_.new_NotificationMessage(*args))
TypeError: in method 'new_NotificationMessage', expected argument 3 of type 'wxWindow *'
这是怎么回事?如果我去掉那个参数,我就得不到想要的结果;如果我加上那个参数,我又会出错!我该怎么用wx.NotificationMessage和wx.TaskBarIcon一起使用呢?
请帮帮我!我希望我提供的信息足够了。如果你需要更多,请评论!
2 个回答
7
在TaskBarIcon
里,有一个没有文档说明的隐藏方法,叫做ShowBalloon
,这个方法只在Windows系统上能用。
来自源代码:
def ShowBalloon(*args, **kwargs):
"""
ShowBalloon(self, String title, String text, unsigned int msec=0, int flags=0) -> bool
Show a balloon notification (the icon must have been already
initialized using SetIcon). Only implemented for Windows.
title and text are limited to 63 and 255 characters respectively, msec
is the timeout, in milliseconds, before the balloon disappears (will
be clamped down to the allowed 10-30s range by Windows if it's outside
it) and flags can include wxICON_ERROR/INFO/WARNING to show a
corresponding icon
Returns True if balloon was shown, False on error (incorrect parameters
or function unsupported by OS)
"""
return _windows_.TaskBarIcon_ShowBalloon(*args, **kwargs)
我在Windows上用wxPython 2.9.4.0测试过这个方法,效果很好。
11
我不太建议现在就使用2.9版本。我在试用的时候遇到了一些奇怪的bug。
其实在2.8版本中也能实现相同的功能。我现在用的是我之前找到的一些稍微修改过的代码。
import wx, sys
try:
import win32gui #, win32con
WIN32 = True
except:
WIN32 = False
class BalloonTaskBarIcon(wx.TaskBarIcon):
"""
Base Taskbar Icon Class
"""
def __init__(self):
wx.TaskBarIcon.__init__(self)
self.icon = None
self.tooltip = ""
def ShowBalloon(self, title, text, msec = 0, flags = 0):
"""
Show Balloon tooltip
@param title - Title for balloon tooltip
@param msg - Balloon tooltip text
@param msec - Timeout for balloon tooltip, in milliseconds
@param flags - one of wx.ICON_INFORMATION, wx.ICON_WARNING, wx.ICON_ERROR
"""
if WIN32 and self.IsIconInstalled():
try:
self.__SetBalloonTip(self.icon.GetHandle(), title, text, msec, flags)
except Exception:
pass # print(e) Silent error
def __SetBalloonTip(self, hicon, title, msg, msec, flags):
# translate flags
infoFlags = 0
if flags & wx.ICON_INFORMATION:
infoFlags |= win32gui.NIIF_INFO
elif flags & wx.ICON_WARNING:
infoFlags |= win32gui.NIIF_WARNING
elif flags & wx.ICON_ERROR:
infoFlags |= win32gui.NIIF_ERROR
# Show balloon
lpdata = (self.__GetIconHandle(), # hWnd
99, # ID
win32gui.NIF_MESSAGE|win32gui.NIF_INFO|win32gui.NIF_ICON, # flags: Combination of NIF_* flags
0, # CallbackMessage: Message id to be pass to hWnd when processing messages
hicon, # hIcon: Handle to the icon to be displayed
'', # Tip: Tooltip text
msg, # Info: Balloon tooltip text
msec, # Timeout: Timeout for balloon tooltip, in milliseconds
title, # InfoTitle: Title for balloon tooltip
infoFlags # InfoFlags: Combination of NIIF_* flags
)
win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY, lpdata)
self.SetIcon(self.icon, self.tooltip) # Hack: because we have no access to the real CallbackMessage value
def __GetIconHandle(self):
"""
Find the icon window.
This is ugly but for now there is no way to find this window directly from wx
"""
if not hasattr(self, "_chwnd"):
try:
for handle in wx.GetTopLevelWindows():
if handle.GetWindowStyle():
continue
handle = handle.GetHandle()
if len(win32gui.GetWindowText(handle)) == 0:
self._chwnd = handle
break
if not hasattr(self, "_chwnd"):
raise Exception
except:
raise Exception, "Icon window not found"
return self._chwnd
def SetIcon(self, icon, tooltip = ""):
self.icon = icon
self.tooltip = tooltip
wx.TaskBarIcon.SetIcon(self, icon, tooltip)
def RemoveIcon(self):
self.icon = None
self.tooltip = ""
wx.TaskBarIcon.RemoveIcon(self)
# ===================================================================
app = wx.PySimpleApp()
class TestTaskBarIcon(BalloonTaskBarIcon):
def __init__(self):
wx.TaskBarIcon.__init__(self)
# create a test icon
bmp = wx.EmptyBitmap(16, 16)
dc = wx.MemoryDC(bmp)
dc.SetBrush(wx.RED_BRUSH)
dc.Clear()
dc.SelectObject(wx.NullBitmap)
testicon = wx.EmptyIcon()
testicon.CopyFromBitmap(bmp)
self.SetIcon(testicon)
self.Bind(wx.EVT_TASKBAR_LEFT_UP, lambda e: (self.RemoveIcon(),sys.exit()))
self.ShowBalloon("", "Hello world!")
icon = TestTaskBarIcon()
app.MainLoop()