Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 25, 2013 19:58:17

MarkHammer
Зарегистрирован: 2013-02-24
Сообщения: 97
Репутация: +  0  -
Профиль   Отправить e-mail  

сообщение в трее

Подскажите пожалуйста - нашел в инете код для вывода сообщений в трее, использующий 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_())

Помогите пожалуйста разобраться - очень уж необходимо выводить сообщения в трее винды…

Офлайн

#2 Июнь 25, 2013 20:40:05

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

сообщение в трее

Причина в том, что QSystemTrayIcon не задан родитель. Возможно связано только с Python'ом.
Фикс:

from PyQt4 import QtCore
dummy_parent = QtCore.QObject()
# ...
tray = QSystemTrayIcon(sicon, parent=dummy_parent)
В реальной программе родителем будет главное окно или что-то похожее.

Офлайн

#3 Июнь 25, 2013 21:04:05

MarkHammer
Зарегистрирован: 2013-02-24
Сообщения: 97
Репутация: +  0  -
Профиль   Отправить e-mail  

сообщение в трее

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

Офлайн

#4 Июнь 25, 2013 21:11:15

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

сообщение в трее

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

У меня первый код, до добавления parent, при нажатии на quit вообще вылетал с ошибкой в QtCore. Думал вопрос об этом.

Офлайн

#5 Июнь 25, 2013 21:37:50

sanodin
От:
Зарегистрирован: 2011-06-16
Сообщения: 515
Репутация: +  31  -
Профиль   Отправить e-mail  

сообщение в трее

у меня работает,в трее нажав quit завершается
windows7 python2.7.4

Офлайн

#6 Июнь 25, 2013 21:52:35

MarkHammer
Зарегистрирован: 2013-02-24
Сообщения: 97
Репутация: +  0  -
Профиль   Отправить e-mail  

сообщение в трее

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

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

Отредактировано MarkHammer (Июнь 25, 2013 21:55:58)

Офлайн

#7 Июнь 26, 2013 17:48:21

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

сообщение в трее

Если уже есть 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(), иначе не будет показано и обработано меню.

Офлайн

#8 Июнь 26, 2013 20:20:59

sanodin
От:
Зарегистрирован: 2011-06-16
Сообщения: 515
Репутация: +  31  -
Профиль   Отправить e-mail  

сообщение в трее

Не получается сделать проверку на изменение в буфере обмена(выводить сообщение только при изменении инфо в буфере)…
скрипт переводит на русский язык

#!/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_()
или надо было новую тему создать?

Отредактировано sanodin (Июнь 26, 2013 20:21:39)

Офлайн

#9 Июнь 26, 2013 21:11:34

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

сообщение в трее

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
или надо было новую тему создать?
Наверное.

Офлайн

#10 Июнь 26, 2013 21:15:43

sanodin
От:
Зарегистрирован: 2011-06-16
Сообщения: 515
Репутация: +  31  -
Профиль   Отправить e-mail  

сообщение в трее

reclosedev
sanodinЗачем вы смешиваете PyQt и Tkinter? В PyQt за буфером можно следить: QClipboard.dataChanged
Спасибо

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version