wxPython в потоке не может быть выключен без ошибки - PullRequest
0 голосов
/ 02 июня 2018

Я новичок в wxPython, поэтому я просто скопировал что-то, что будет отображать иконку в трее, и сделал его потоком:

import wx
import wx.adv
from threading import Thread

TRAY_TOOLTIP = 'System Tray Demo'
TRAY_ICON = 'icon.png'


class Main(Thread):
    def __init__(self):
        Thread.__init__(self)

    def run(self):
        self.app = App()
        self.app.MainLoop()


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, '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_exit(self, event):
        wx.CallAfter(self.Destroy)
        self.frame.Close()


class App(wx.App):
    def __init__(self):
        wx.App.__init__(self, False)

    def OnInit(self):
        frame = wx.Frame(None)
        self.SetTopWindow(frame)
        TaskBarIcon(frame)
        return True

из моего основного потока, который очень долго работает, язапускаю поток графического интерфейса, активирую планировщик и проверяю, должен ли он работать следующим образом:

gui = trayIcon.Main()
gui.start()
schedule.every(60).minutes.do(main)

while gui.is_alive():
    schedule.run_pending()
    time.sleep(1)

# if this is reached the gui thread has terminated and the program should shut down
sys.exit()

Работает так, как должно быть: При нажатии на выходной элемент в меню значка на панели задач поток графического интерфейса закрываетсяdown, то больше не обнаруживается в цикле while основного потока, и вызывается sys.exit ().К сожалению, wxPython отображает диалоговое окно с сообщением об ошибке со следующим текстом:


wxWidgets Отладочное оповещение

.... \ src \ common \ socket.cpp (767):assert "wxIsMainThread ()" не удалось в wxSocketBase :: IsInitialized (): небезопасно вызывать из других потоков [в потоке 1284] Вы хотите остановить программу?Вы также можете выбрать [Отмена] для подавления дальнейших предупреждений.

Как правильно отключить графический интерфейс или хотя бы подавить это предупреждение?После этого программа завершает работу, как и должно быть, хотя я подозреваю, что подавление сообщения приведет к некоторой утечке памяти.

Заранее спасибо

Таксель

1 Ответ

0 голосов
/ 05 июня 2018

По сути, похоже, что вы настроили его задом наперед.Основной поток всегда должен быть wxPython.MainLoop не должен вызываться внутри потока.Вместо этого вы должны позволить wxPython контролировать и запускать внутри него ваш долго работающий поток.

Затем, когда ваше долгосрочное задание будет завершено, вы можете использовать безопасный для потока метод, такой как wx.CallAfter, чтобы сообщить wxPython, чтопора выходить.Так как wxPython контролирует, он может правильно закрыться.

Вот несколько статей, которые могут вам помочь:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...