試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

PyGTKでシステムトレイを使用してメニューを表示する

バージョン2.10以上のPyGTKでは、gtk.StatusIconオブジェクトにより、システムトレイにアイコンを常駐させてポップアップメニューを表示することができる。また、アイコンを直接クリックしたときの処理を扱うこともできる。
下はコード例。
[任意]ファイル名: systraytest.py

#! /usr/bin/python
# -*- encoding: utf-8 -*-

import sys
try:
  import pygtk
  pygtk.require("2.0")
except:
  pass
try:
  import gtk
except:
  print >> sys.stderr, "Error: PyGTK not installed"
  sys.exit(1)
if gtk.pygtk_version < (2,10,0):
  errtitle = "Error"
  errmsg = "PyGTK 2.10.0 or later required"
  if gtk.pygtk_version < (2,4,0):
    print >> sys.stderr, errtitle + ": " + errmsg
  else:
    errdlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_OK)
    errdlg.set_title(errtitle)
    errdlg.set_markup(errmsg)
    errdlg.run()
  sys.exit(1)


class TrayMenu(gtk.Menu):
  """
  システムトレイのメニュー(アイコン付き)
  """
  def __init__(self, tray):
    gtk.Menu.__init__(self)  # 親クラスのコンストラクタ

    self.tray = tray

    # 項目1
    self.item1 = gtk.ImageMenuItem("item1")
    self.item1.connect("activate", self.item1_activate)
    self.item1.set_image(gtk.image_new_from_stock('gtk-preferences', gtk.ICON_SIZE_MENU))
    self.append(self.item1)

    # 項目2
    self.item2 = gtk.ImageMenuItem("item2")
    self.item2.connect("activate", self.item2_activate)
    self.item2.set_image(gtk.image_new_from_stock('gtk-open', gtk.ICON_SIZE_MENU))
    self.item2.set_sensitive(False)  # 初期状態で選択できない項目の例
    self.append(self.item2)

    # 項目3
    self.item3 = gtk.ImageMenuItem("item3")
    self.item3.connect("activate", self.item3_activate)
    self.item3.set_image(gtk.image_new_from_stock('gtk-close', gtk.ICON_SIZE_MENU))
    self.append(self.item3)

    # 区切り線(インスタンスを生成してそのまま入れている)
    self.append(gtk.SeparatorMenuItem())

    # 終了
    self.item_quit = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
    self.item_quit.connect('activate', self.quit_activate)
    self.append(self.item_quit)

    # このメニューを表示可能にする
    self.show_all()
  def item1_activate(self, widget):
    """
    項目item1が選択されたときの処理
    """
    print "item1 activated"
  def item2_activate(self, widget):
    """
    項目item2が選択されたときの処理
    """
    self.item2.set_sensitive(False)  # item2を選択できなくする
    self.item3.set_sensitive(True)   # item3を選択できるようにする
    self.tray.set_blinking(False)  # gtk.StatusIconのset_blinking(False)で点滅解除
    print "item2 activated"
  def item3_activate(self, widget):
    """
    項目item3が選択されたときの処理
    """
    self.item2.set_sensitive(True)   # item2を選択できるようにする
    self.item3.set_sensitive(False)  # item3を選択できなくする
    self.tray.set_blinking(True)  # 点滅開始
    print "item3 activated"
  def quit_activate(self, widget):
    """
    終了の項目が選択されたときの処理
    """
    gtk.main_quit()
  def show_menu(self, widget, button, time):
    """
    メニューのポップアップを行う
    """
    # gtk.status_icon_position_menu()でメニューをアイコンの位置に合わせる
    self.popup(None, None, gtk.status_icon_position_menu, button, time, self.tray)

class PyGTKSystrayTest:
  """
  システムトレイのテスト
  """
  def main(self):
    tray = gtk.StatusIcon()       # PyGTK 2.10以上
    menu = TrayMenu(tray)         # gtk.Menuの子クラス
    # 今回はgtk.STOCK_DIALOG_INFOのストックアイコンを使用
    # set_from_file()やset_from_icon_name()、set_from_pixbuf()も使える
    tray.set_from_stock(gtk.STOCK_DIALOG_INFO)
    tray.set_tooltip("test")      # マウスポインタを少し乗せたときに出る文字列
    tray.connect("activate", menu.item1_activate)  # 通常クリック時
    tray.connect("popup-menu", menu.show_menu)     # メニューを出す
    gtk.main()

if __name__ == "__main__":
  app = PyGTKSystrayTest()
  app.main()

これを実行するとシステムトレイに「情報」アイコンが表示され

  • メニューから選択した項目によって、端末に異なったメッセージが表示される
  • 通常クリックしたときには「item1」を選択したのと同じ効果になるようにしている
  • item2は最初無効で、item3を選択すると選択できるようになる(今度は代わりにitem3が無効になる)・これを選択すると元の状態に戻る
  • item3を選択してから次にitem2を選択するまで、アイコンが点滅する

という動作をする。
(2008/7/24)グローバル変数を使用しないように修正

関連記事:

参考URL: