【问题标题】:How to create a TaskBarIcon-only application in wxpython?如何在 wxpython 中创建仅包含 TaskBarIcon 的应用程序?
【发布时间】:2019-09-16 17:18:37
【问题描述】:

我正在尝试在 wxpython 中创建一个仅使用 TaskBarIcon 而没有框架的应用程序。

关于这个here 有一个问题,但是那个例子对我不起作用;它只是没有错误地退出。

我在下面编写的代码是我正在使用的代码的简化版本:

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()

我收到以下错误:

$ 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 *'

所以,我的问题:

1: 为什么 SetIcon 不接受我的课程?我已经尝试将 SetIcon 调用移动到我链接的问题中的函数,但它仍然不起作用。我可以摆弄它,可能会得到一些工作,但我想知道它不起作用的原因。

2:我链接到的问题运行,但立即退出。那是因为 TaskBarIcon 不会保持 MainLoop() 打开吗?我该怎么办?

【问题讨论】:

  • 我知道如何让 TaskBarIcon 保持 MainLoop() 现在打开:请参阅 stackoverflow.com/questions/13069452/… 。还是不知道图标是怎么回事。
  • 您是正确的,因为 TaskBarIcon 并不是真正的顶级窗口,因此它不会保持 MainLoop 运行。我看到你已经添加了一个框架,这是要走的路。

标签: python wxpython


【解决方案1】:

这是一个在 Linux 上使用 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()

编辑:
对于任何仍然感到悲伤的人,这是一个基本上使用虚拟框架的版本。

2019 年编辑:针对 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()

【讨论】:

  • 这不适用于独立的托盘应用程序 - TaskBarIcon 不会保持 App.MainLoop() 处于打开状态。请参阅我的自我回答,了解如何解决这个问题。
  • @JeffSpaulding 定义“独立托盘应用程序”,因为这段代码显然对我有用。它将从桌面启动器或命令行运行并继续运行。 (python 2.7, wx 2.8, Linux)
  • 通过“独立托盘应用程序”我的意思是它可以在没有关联框架的情况下工作。这段代码对我来说立即退出。我可以看到系统托盘受到干扰,但仅此而已。我必须继承 wx.App 并从那里调用它以使其保持打开状态。
  • @JeffSpaulding 现在我很感兴趣。你确定这不是因为你使用 python2.7 和 wxpython 3 而不是 2.8?我认为你真的应该将 python3 与 wxpython 3 一起使用。当然,我可能会说我的阴暗区域;)
  • 我下载了“wxPython3.0-win64-py27 for 64-bit Python 2.7”。 wxPython 好像分为classic 和phoenix,增加了对3.x 的支持。我没有phoenix,因为该网站给人的印象是它还没有准备好用于生产。
【解决方案2】:

好的,经过 30 分钟的折腾,第二天就搞定了。

SetIcon 不接受我的课程,因为我需要添加以下内容:

super(TaskBarIcon, self).__init__()

__init__

我怀疑是鸭子打字在这里咬我;如果没有运行 wx.TaskBarIcon 构造函数,python 不会将其视为 wx.TaskBarIcon 对象。

要仅使用 TaskBarIcon 保持应用程序打开,请从 wx.App 创建派生类并覆盖 OnInit 函数,如下所示:

class App(wx.App):
    def OnInit(self):
        self.SetTopWindow(wx.Frame(None, -1))
        TaskBarIcon()
        return True

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多