圆月山庄资源网 Design By www.vgjia.com
在写桌面软件时,通常会使用到托盘上的泡泡提示功能,让我们来看看使用python如何实现这个小功能。
一、Linux系统
在Linux上,实现一个气泡提示非常简单,使用GTK实现的pynotify模块提供了些功能,我的环境是Ubuntu,默认安装此模块,如果没有,下载源文件编译安装一个。实现代码如下:
#!/usr/bin/python #coding:utf-8 import pynotify pynotify.init ("Bubble@Linux") bubble_notify = pynotify.Notification ("Linux上的泡泡提示", "看,比Windows上实现方便多了!") bubble_notify.show ()
效果:
二、Windows下的实现
Windows下实现是比较复杂的,没有pynotify这样一个模块,找到了一个还算不错的模块(地址),这个类有些语法上的小问题,至少在python2.6下如此,需要修改一下,如下是修改后的代码),基本可用,代码如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- #gtkPopupNotify.py # # Copyright 2009 Daniel Woodhouse # modified by NickCis 2010 http://github.com/NickCis/gtkPopupNotify # Modifications: # Added: * Corner support (notifications can be displayed in all corners # * Use of gtk Stock items or pixbuf to render images in notifications # * Posibility of use fixed height # * Posibility of use image as background # * Not displaying over Windows taskbar(taken from emesene gpl v3) # * y separation. # * font description options # * Callbacks For left, middle and right click # #This program is free software: you can redistribute it and/or modify #it under the terms of the GNU Lesser General Public License as published by #the Free Software Foundation, either version 3 of the License, or #(at your option) any later version. # #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU Lesser General Public License for more details. # #You should have received a copy of the GNU Lesser General Public License #along with this program. If not, see <http://www.gnu.org/licenses/>. import os import gtk import pango import gobject # This code is used only on Windows to get the location on the taskbar # Taken from emesene Notifications (Gpl v3) taskbarOffsety = 0 taskbarOffsetx = 0 if os.name == "nt": import ctypes from ctypes.wintypes import RECT, DWORD user = ctypes.windll.user32 MONITORINFOF_PRIMARY = 1 HMONITOR = 1 class MONITORINFO(ctypes.Structure): _fields_ = [ ('cbSize', DWORD), ('rcMonitor', RECT), ('rcWork', RECT), ('dwFlags', DWORD) ] taskbarSide = "bottom" taskbarOffset = 30 info = MONITORINFO() info.cbSize = ctypes.sizeof(info) info.dwFlags = MONITORINFOF_PRIMARY user.GetMonitorInfoW(HMONITOR, ctypes.byref(info)) if info.rcMonitor.bottom != info.rcWork.bottom: taskbarOffsety = info.rcMonitor.bottom - info.rcWork.bottom if info.rcMonitor.top != info.rcWork.top: taskbarSide = "top" taskbarOffsety = info.rcWork.top - info.rcMonitor.top if info.rcMonitor.left != info.rcWork.left: taskbarSide = "left" taskbarOffsetx = info.rcWork.left - info.rcMonitor.left if info.rcMonitor.right != info.rcWork.right: taskbarSide = "right" taskbarOffsetx = info.rcMonitor.right - info.rcWork.right class NotificationStack: def __init__(self, size_x=300, size_y=-1, timeout=5, corner=(False, False), sep_y=0): """ Create a new notification stack. The recommended way to create Popup instances. Parameters: `size_x` : The desired width of the notifications. `size_y` : The desired minimum height of the notifications. If it isn't set, or setted to None, the size will automatically adjust `timeout` : Popup instance will disappear after this timeout if there is no human intervention. This can be overridden temporarily by passing a new timout to the new_popup method. `coner` : 2 Value tuple: (true if left, True if top) `sep_y` : y distance to separate notifications from each other """ self.size_x = size_x self.size_y = -1 if (size_y == None): pass else: size_y self.timeout = timeout self.corner = corner self.sep_y = sep_y """ Other parameters: These will take effect for every popup created after the change. `edge_offset_y` : distance from the bottom of the screen and the bottom of the stack. `edge_offset_x` : distance from the right edge of the screen and the side of the stack. `max_popups` : The maximum number of popups to be shown on the screen at one time. `bg_color` : if None default is used (usually grey). set with a gtk.gdk.Color. `bg_pixmap` : Pixmap to use as background of notification. You can set a gtk.gdk.Pixmap or a path to a image. If none, the color background will be displayed. `bg_mask` : If a gtk.gdk.pixmap is specified under bg_pixmap, the mask of the pixmap has to be setted here. `fg_color` : if None default is used (usually black). set with a gtk.gdk.Color. `show_timeout` : if True, a countdown till destruction will be displayed. `close_but` : if True, the close button will be displayed. `fontdesc` : a 3 value Tuple containing the pango.FontDescriptions of the Header, message and counter (in that order). If a string is suplyed, it will be used for the 3 the same FontDescription. http://doc.stoq.com.br/devel/pygtk/class-pangofontdescription.html """ self.edge_offset_x = 0 self.edge_offset_y = 0 self.max_popups = 5 self.fg_color = None self.bg_color = None self.bg_pixmap = None self.bg_mask = None self.show_timeout = False self.close_but = True self.fontdesc = ("Sans Bold 14", "Sans 12", "Sans 10") self._notify_stack = [] self._offset = 0 def new_popup(self, title, message, image=None, leftCb=None, middleCb=None, rightCb=None): """Create a new Popup instance.""" if len(self._notify_stack) == self.max_popups: self._notify_stack[0].hide_notification() self._notify_stack.append(Popup(self, title, message, image, leftCb, middleCb, rightCb)) self._offset += self._notify_stack[-1].y def destroy_popup_cb(self, popup): self._notify_stack.remove(popup) #move popups down if required offset = 0 for note in self._notify_stack: offset = note.reposition(offset, self) self._offset = offset class Popup(gtk.Window): def __init__(self, stack, title, message, image, leftCb, middleCb, rightCb): gtk.Window.__init__(self, type=gtk.WINDOW_POPUP) self.leftclickCB = leftCb self.middleclickCB = middleCb self.rightclickCB = rightCb self.set_size_request(stack.size_x, stack.size_y) self.set_decorated(False) self.set_deletable(False) self.set_property("skip-pager-hint", True) self.set_property("skip-taskbar-hint", True) self.connect("enter-notify-event", self.on_hover, True) self.connect("leave-notify-event", self.on_hover, False) self.set_opacity(0.2) self.destroy_cb = stack.destroy_popup_cb if type(stack.fontdesc) == tuple or type(stack.fontdesc) == list: fontH, fontM, fontC = stack.fontdesc else: fontH = fontM = fontC = stack.fontdesc main_box = gtk.VBox() header_box = gtk.HBox() self.header = gtk.Label() self.header.set_markup("<b>%s</b>" % title) self.header.set_padding(3, 3) self.header.set_alignment(0, 0) try: self.header.modify_font(pango.FontDescription(fontH)) except Exception, e: print e header_box.pack_start(self.header, True, True, 5) if stack.close_but: close_button = gtk.Image() close_button.set_from_stock(gtk.STOCK_CANCEL, gtk.ICON_SIZE_BUTTON) close_button.set_padding(3, 3) close_window = gtk.EventBox() close_window.set_visible_window(False) close_window.connect("button-press-event", self.hide_notification) close_window.add(close_button) header_box.pack_end(close_window, False, False) main_box.pack_start(header_box) body_box = gtk.HBox() if image is not None: self.image = gtk.Image() self.image.set_size_request(70, 70) self.image.set_alignment(0, 0) if image in gtk.stock_list_ids(): self.image.set_from_stock(image, gtk.ICON_SIZE_DIALOG) elif type(image) == gtk.gdk.Pixbuf: self.image.set_from_pixbuf(image) else: self.image.set_from_file(image) body_box.pack_start(self.image, False, False, 5) self.message = gtk.Label() self.message.set_property("wrap", True) self.message.set_size_request(stack.size_x - 90, -1) self.message.set_alignment(0, 0) self.message.set_padding(5, 10) self.message.set_markup(message) try: self.message.modify_font(pango.FontDescription(fontM)) except Exception, e: print e self.counter = gtk.Label() self.counter.set_alignment(1, 1) self.counter.set_padding(3, 3) try: self.counter.modify_font(pango.FontDescription(fontC)) except Exception, e: print e self.timeout = stack.timeout body_box.pack_start(self.message, True, False, 5) body_box.pack_end(self.counter, False, False, 5) main_box.pack_start(body_box) eventbox = gtk.EventBox() eventbox.set_property('visible-window', False) eventbox.set_events(gtk.gdk.BUTTON_PRESS_MASK) eventbox.connect("button_press_event", self.onClick) eventbox.add(main_box) self.add(eventbox) if stack.bg_pixmap is not None: if not type(stack.bg_pixmap) == gtk.gdk.Pixmap: stack.bg_pixmap, stack.bg_mask = gtk.gdk.pixbuf_new_from_file(stack.bg_pixmap).render_pixmap_and_mask() self.set_app_paintable(True) self.connect_after("realize", self.callbackrealize, stack.bg_pixmap, stack.bg_mask) elif stack.bg_color is not None: self.modify_bg(gtk.STATE_NORMAL, stack.bg_color) if stack.fg_color is not None: self.message.modify_fg(gtk.STATE_NORMAL, stack.fg_color) self.header.modify_fg(gtk.STATE_NORMAL, stack.fg_color) self.counter.modify_fg(gtk.STATE_NORMAL, stack.fg_color) self.show_timeout = stack.show_timeout self.hover = False self.show_all() self.x, self.y = self.size_request() #Not displaying over windows bar if os.name == 'nt': if stack.corner[0] and taskbarSide == "left": stack.edge_offset_x += taskbarOffsetx elif not stack.corner[0] and taskbarSide == 'right': stack.edge_offset_x += taskbarOffsetx if stack.corner[1] and taskbarSide == "top": stack.edge_offset_x += taskbarOffsety elif not stack.corner[1] and taskbarSide == 'bottom': stack.edge_offset_x += taskbarOffsety if stack.corner[0]: posx = stack.edge_offset_x else: posx = gtk.gdk.screen_width() - self.x - stack.edge_offset_x sep_y = 0 if (stack._offset == 0): pass else: stack.sep_y self.y += sep_y if stack.corner[1]: posy = stack._offset + stack.edge_offset_y + sep_y else: posy = gtk.gdk.screen_height()- self.y - stack._offset - stack.edge_offset_y self.move(posx, posy) self.fade_in_timer = gobject.timeout_add(100, self.fade_in) def reposition(self, offset, stack): """Move the notification window down, when an older notification is removed""" if stack.corner[0]: posx = stack.edge_offset_x else: posx = gtk.gdk.screen_width() - self.x - stack.edge_offset_x if stack.corner[1]: posy = offset + stack.edge_offset_y new_offset = self.y + offset else: new_offset = self.y + offset posy = gtk.gdk.screen_height() - new_offset - stack.edge_offset_y + stack.sep_y self.move(posx, posy) return new_offset def fade_in(self): opacity = self.get_opacity() opacity += 0.15 if opacity >= 1: self.wait_timer = gobject.timeout_add(1000, self.wait) return False self.set_opacity(opacity) return True def wait(self): if not self.hover: self.timeout -= 1 if self.show_timeout: self.counter.set_markup(str("<b>%s</b>" % self.timeout)) if self.timeout == 0: self.fade_out_timer = gobject.timeout_add(100, self.fade_out) return False return True def fade_out(self): opacity = self.get_opacity() opacity -= 0.10 if opacity <= 0: self.in_progress = False self.hide_notification() return False self.set_opacity(opacity) return True def on_hover(self, window, event, hover): """Starts/Stops the notification timer on a mouse in/out event""" self.hover = hover def hide_notification(self, *args): """Destroys the notification and tells the stack to move the remaining notification windows""" for timer in ("fade_in_timer", "fade_out_timer", "wait_timer"): if hasattr(self, timer): gobject.source_remove(getattr(self, timer)) self.destroy() self.destroy_cb(self) def callbackrealize(self, widget, pixmap, mask=False): #width, height = pixmap.get_size() #self.resize(width, height) if mask is not False: self.shape_combine_mask(mask, 0, 0) self.window.set_back_pixmap(pixmap, False) return True def onClick(self, widget, event): if event.button == 1 and self.leftclickCB != None: self.leftclickCB() self.hide_notification() if event.button == 2 and self.middleclickCB != None: self.middleclickCB() self.hide_notification() if event.button == 3 and self.rightclickCB != None: self.rightclickCB() self.hide_notification() if __name__ == "__main__": #example usage def notify_factory(): color = ("green", "blue") image = "logo1_64.png" notifier.bg_color = gtk.gdk.Color(color[0]) notifier.fg_color = gtk.gdk.Color(color[1]) notifier.show_timeout = True notifier.edge_offset_x = 20 notifier.edge_offset_y = 30 notifier.new_popup("Windows上的泡泡提示", "NND,比Linux下复杂多了,效果还不怎么样", image=image) return True def gtk_main_quit(): print "quitting" gtk.main_quit() notifier = NotificationStack(timeout=1) gobject.timeout_add(4000, notify_factory) gobject.timeout_add(8000, gtk_main_quit) gtk.main()
效果如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
圆月山庄资源网 Design By www.vgjia.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
圆月山庄资源网 Design By www.vgjia.com
暂无评论...
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
2024年11月05日
2024年11月05日
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]