Найти - Пользователи
Полная версия: сообщение в трее
Начало » Python для новичков » сообщение в трее
1
MarkHammer
Подскажите пожалуйста - нашел в инете код для вывода сообщений в трее, использующий pyqt4, сообщение в трее выводится, но программа при этом не завершается… завершается если выбрать в трее пункт меню quit - выводя :
Traceback (most recent call last):
File "C:\tmp2\testicontrey", line 28, in <module>
sys.exit(app.exec_())
SystemExit: 0

не реагирует даже на CTRL+C


Код программы:

import sys, os
from PyQt4.QtCore import SIGNAL
from PyQt4.QtGui import QApplication
from PyQt4.QtGui import QIcon
from PyQt4.QtGui import QMenu
from PyQt4.QtGui import QAction
from PyQt4.QtGui import QSystemTrayIcon
from PyQt4.QtCore import QString
from PyQt4.QtCore import SLOT
from PyQt4.QtCore import QTimer

if __name__ == "__main__":
app = QApplication(sys.argv)
plik = QString("/usr/share/icons/crystalsvg/16x16/apps/wine.png")
menu = QMenu()
quitAction = menu.addAction('Quit')
sicon = QIcon(plik)
tray = QSystemTrayIcon(sicon)
tray.setContextMenu(menu)
tray.show()
quitAction.connect(quitAction, SIGNAL("triggered()"), app, SLOT("quit()"))
tray.setToolTip("Ale czad!")

def show_message():
tray.showMessage("Title of the message", "Body of the message")

QTimer.singleShot(2000, show_message)
sys.exit(app.exec_())

Помогите пожалуйста разобраться - очень уж необходимо выводить сообщения в трее винды…
reclosedev
Причина в том, что QSystemTrayIcon не задан родитель. Возможно связано только с Python'ом.
Фикс:
from PyQt4 import QtCore
dummy_parent = QtCore.QObject()
# ...
tray = QSystemTrayIcon(sicon, parent=dummy_parent)
В реальной программе родителем будет главное окно или что-то похожее.
MarkHammer
reclosedev
tray = QSystemTrayIcon(sicon, parent=dummy_parent)

К сожалению после изменения кода, поведение программы осталось прежним - не завершается…
Вообщем-то планирую использовать вывод сообщений в трей в программе, которая будет работать в фоновом режиме (демон)… или так нельзя использовать pyqt библиотеку ? просто не нашел другого способа для вывода сообщений в трей, а этот без доработки к сожалению не пригоден…

import sys, os
from PyQt4 import QtCore
from PyQt4.QtCore import SIGNAL
from PyQt4.QtGui import QApplication
from PyQt4.QtGui import QIcon
from PyQt4.QtGui import QMenu
from PyQt4.QtGui import QAction
from PyQt4.QtGui import QSystemTrayIcon
from PyQt4.QtCore import QString
from PyQt4.QtCore import SLOT
from PyQt4.QtCore import QTimer

if __name__ == "__main__":
dummy_parent = QtCore.QObject()
app = QApplication(sys.argv)
plik = QString("/usr/share/icons/crystalsvg/16x16/apps/wine.png")
menu = QMenu()
quitAction = menu.addAction('Quit')
sicon = QIcon(plik)
tray = QSystemTrayIcon(sicon, parent=dummy_parent)
tray.setContextMenu(menu)
tray.show()
quitAction.connect(quitAction, SIGNAL("triggered()"), app, SLOT("quit()"))
tray.setToolTip("Ale czad!")

def show_message():
tray.showMessage("Title of the message", "Body of the message")

QTimer.singleShot(2000, show_message)
sys.exit(app.exec_())
reclosedev
Не понимаю что вы хотите? Чтобы программа завершилась, но потом как-то отправляла сообщения?
Или вы о том, что app.exec_() блокирует дальнейшее выполнение?

У меня первый код, до добавления parent, при нажатии на quit вообще вылетал с ошибкой в QtCore. Думал вопрос об этом.
sanodin
у меня работает,в трее нажав quit завершается
windows7 python2.7.4
MarkHammer
reclosedev
Не понимаю что вы хотите? Чтобы программа завершилась, но потом как-то отправляла сообщения?Или вы о том, что app.exec_() блокирует дальнейшее выполнение?У меня первый код, до добавления parent, при нажатии на quit вообще вылетал с ошибкой в QtCore. Думал вопрос об этом.

предполагается чтобы в трее выводилось сообщение и через допустим 10 секунд, если пользователь сам не выполнит quit в трее - программа автоматически закрывала иконку в трее и завершала свою работу (а точнее, когда это будет в реальной программе - продолжила выполнение по циклу… т.е. чтоб она не приостанавливала работу после вывода сообщения в трее и не собирала в трее иконки) , можно ли это реализовать ?

reclosedev
Если уже есть GUI приложение, проблем добавить иконку нет, примеров много в сети.

Если правильно понял, у вас не GUI приложение.
Для работы Qt нужен запущенный цикл обработки событий (app.exec_()), но он блокирует все дальнейшие действия. Поэтому работу нужно выполнять в отдельном потоке.

Примитивный пример:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import time
 
from PyQt4 import QtGui, QtCore
 
 
class WorkerThread(QtCore.QThread):
    def __init__(self, tray_icon):
        QtCore.QThread.__init__(self)
        self.tray_icon = tray_icon
        self._need_to_stop = False
 
    def run(self):
        counter = 0
        while not self._need_to_stop:
            print 'Doing work'
            self.tray_icon.showMessage('Test', 'Test message %s' % counter)
            counter += 1
            time.sleep(1)
        print 'exiting'
        QtGui.QApplication.quit()
 
    def stop(self):
        self._need_to_stop = True
 
 
app = QtGui.QApplication(sys.argv)
tray = QtGui.QSystemTrayIcon(
    QtGui.QIcon(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")
)
worker = WorkerThread(tray)
menu = QtGui.QMenu()
quit_action = menu.addAction('Quit')
quit_action.triggered.connect(worker.stop)
tray.setContextMenu(menu)
tray.show()
worker.start()
app.exec_()

Есть еще вариант без потока. Нужно до запуска app.exec_() запустить свой цикл работы через queued connection
QtCore.QTimer.singleShot(0, my_main_loop)
но тогда придется постоянно вызывать QtGui.QApplication.processEvents(), иначе не будет показано и обработано меню.
sanodin
Не получается сделать проверку на изменение в буфере обмена(выводить сообщение только при изменении инфо в буфере)…
скрипт переводит на русский язык
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import time
from Tkinter import *
import urllib2
import Tkinter
from PyQt4 import QtGui, QtCore
def translate(to_translate, to_langage="auto", langage="auto"):
        '''Return the translation using google translate
        you must shortcut the langage you define (French = fr, English = en, Spanish = es, etc...)
        if you don't define anything it will detect it or use english by default
        Example:
        print(translate("salut tu vas bien?", "en"))
        hello you alright?'''
        agents = {'User-Agent':"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)"}
        before_trans = 'class="t0">'
        link = "http://translate.google.com/m?hl=%s&sl=%s&q=%s" % (to_langage, langage, to_translate.replace(" ", "+"))
        request = urllib2.Request(link, headers=agents)
        page = urllib2.urlopen(request).read()
        result = page[page.find(before_trans)+len(before_trans):]
        result = result.split("<")[0]
        return result
tk = Tk()
class WorkerThread(QtCore.QThread):
    def __init__(self, tray_icon):
        QtCore.QThread.__init__(self)
        self.tray_icon = tray_icon
        self._need_to_stop = False
 
    def run(self):
        
        
        while not self._need_to_stop:
 
            
            try:
                #tk.withdraw()
                cb = tk.selection_get(selection = "CLIPBOARD")# извлечь из буфера обмена
                to_translate = cb
                #print("%s >> %s" % (to_translate, translate(to_translate)))
                tr= ("%s >> %s" % (to_translate, translate(to_translate, 'ru').decode("utf-8")))
                #tk.clipboard_clear()
                #tk.destroy()
                self.tray_icon.showMessage('Translate', tr)
                
                time.sleep(4)
            except: pass
            
        print 'exiting'
        QtGui.QApplication.quit()
 
    def stop(self):
        self._need_to_stop = True
 
 
app = QtGui.QApplication(sys.argv)
tray = QtGui.QSystemTrayIcon(
    QtGui.QIcon(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")
)
worker = WorkerThread(tray)
menu = QtGui.QMenu()
quit_action = menu.addAction('Quit')
quit_action.triggered.connect(worker.stop)
tray.setContextMenu(menu)
tray.show()
worker.start()
app.exec_()
или надо было новую тему создать?
reclosedev
sanodin
Зачем вы смешиваете PyQt и Tkinter?
В PyQt за буфером можно следить: QClipboard.dataChanged
import sys
from PyQt4 import QtGui
 
 
def on_clipboard_changed():
    text = app.clipboard().text()
    # ...
    tray.showMessage('Title', 'Translate: %s' % text)
 
app = QtGui.QApplication(sys.argv)
app.clipboard().dataChanged.connect(on_clipboard_changed)
tray = QtGui.QSystemTrayIcon(
    QtGui.QIcon(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")
)
menu = QtGui.QMenu()
quit_action = menu.addAction('Quit')
quit_action.triggered.connect(app.quit)
tray.setContextMenu(menu)
tray.show()
app.exec_()

sanodin
или надо было новую тему создать?
Наверное.
sanodin
reclosedev
sanodinЗачем вы смешиваете PyQt и Tkinter? В PyQt за буфером можно следить: QClipboard.dataChanged
Спасибо
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB