Python program with Notification in Gnome Shell doesn't work

独自空忆成欢 提交于 2019-12-09 01:43:46

问题


I'm writing a python program that takes info from a webpage and show it on Notification in Gnome Shell. I'm using Arch, so I want to start this program at startup and if there is any change on the webpage, it will notify me. Here is my code:

import time
import webbrowser
import requests
from bs4 import BeautifulSoup
from gi.repository import Notify, GLib


IPS = {'Mobifone': True, 'Viettel': False, 'Vinaphone': False}
LINK = "https://id.vtc.vn/tin-tuc/chuyen-muc-49/tin-khuyen-mai.html"


def set_ips_state(ips_name, state):
    global IPS
    for key in IPS.iterkeys():
        if key == ips_name:
            IPS[key] = state


def call_webbrowser(notification, action_name, link):
    webbrowser.get('firefox').open_new_tab(link)


def create_notify(summary, body, link):
    Notify.init("Offer")
    noti = Notify.Notification.new(summary, body, 'dialog-information')
    noti.add_action('action_click', 'Read more...', call_webbrowser, link)
    noti.show()
    # GLib.MainLoop().run()


def save_to_file(path_to_file, string):
    file = open(path_to_file, 'w')
    file.write(string)
    file.close()


def main():
    global IPS
    global LINK

    result = []

    offer_news = open('offer_news.txt')
    tag_in_file = BeautifulSoup(offer_news.readline(), 'html.parser')
    tag = tag_in_file.a
    offer_news.close()

    page = requests.get(LINK)
    soup = BeautifulSoup(page.text, 'html.parser')
    for div in soup.find_all('div', 'tt_dong1'):
        # first_a = div.a
        # main_content = first_a.find_next_subling('a')
        main_content = div.find_all('a')[1]
        for k, v in IPS.iteritems():
            if v:
                if main_content.text.find(k) != -1:
                    result.append(main_content)
    print result[1].encode('utf-8')
    if tag_in_file == '':
        pass
    else:
        try:
            old_news_index = result.index(tag)
            print old_news_index
            for idx in range(old_news_index):
                create_notify('Offer News', result[idx].text.encode('utf-8'), result[idx].get('href'))
            print "I'm here"
        except ValueError:
            pass
    offer_news = open('offer_news.txt', 'w')
    offer_news.write(result[0].__str__())
    offer_news.close()


if __name__ == '__main__':
    while 1:
        main()
        time.sleep(10)

The problem is when I click on "Read more..." button in the Notification, it does not open Firefox unless I uncomment GLib.MainLoop().run() in create_notify function, but that makes the program freeze. Could anybody help?


回答1:


The GUI applications usually use three main components: widgets, event loop and callbacks. When you start that application, you create widgets, register callbacks and start event loop. Event loop is infinite loop which looks for events from widgets (such as 'clicked button') and fires corresponding callbacks.

Now, in your application you have another infinite loop, so these two will not play along. Instead, you should make use of the GLib.MainLoop().run() to fire events. You can use GLib.timeout_add_seconds to fire periodic events such as your every 10 seconds.

Second problem is that you need to hold reference to a notification which is supposed to call callbacks. The reason why it worked when you added GLib.MainLoop().run() after noti.show() is that reference to noti still exists, but it would not work if you would do changes as I have suggested earlier. If you are sure there is always going to be just one notification active, you can hold the reference to the last notification. Otherwise you would need a list and periodically purge it or something along the lines.

The following example should set you in the right direction:

from gi.repository import GLib, Notify


class App():
    def __init__(self):
        self.last_notification = None
        Notify.init('Test')
        self.check()

    def check(self):
        self.last_notification = Notify.Notification.new('Test')
        self.last_notification.add_action('clicked', 'Action', 
                                          self.notification_callback, None)
        self.last_notification.show()
        GLib.timeout_add_seconds(10, self.check)

    def notification_callback(self, notification, action_name, data):
        print(action_name)


app = App()
GLib.MainLoop().run()


来源:https://stackoverflow.com/questions/32681532/python-program-with-notification-in-gnome-shell-doesnt-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!