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

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

ウィンドウ、システムトレイ、バージョン情報ダイアログでアイコンを指定(コード例)

ウィンドウ、システムトレイ、バージョン情報ダイアログでアイコンを指定(覚え書き)」の続き。

コード例

ウィンドウの位置とサイズを記憶し、壊さずに隠した後で再表示を行う」のコードにアイコンの処理を追加したもの。
アイコンの指定には複数の方法(メンバ関数)があるため、コメント記号の後ろに他の方法も書いているところがある。
[任意]ファイル名: iconloadtest.py

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

import sys
import os
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)

# XPM形式のアイコン
xpm_icon = ["48 48 2 1",
  " 	c None",
  ".	c #66C8FF",
  "                                                ",
  "                                                ",
  "                       ..                       ",
  "                       ..                       ",
  "                       ..                       ",
  "                      ....                      ",
  "                      ....                      ",
  "                      ....                      ",
  "                     ......                     ",
  "                     ......                     ",
  "                     ......                     ",
  "                    ........                    ",
  "                    ........                    ",
  "                    ........                    ",
  "                   ..........                   ",
  "                   ..........                   ",
  "                   ..........                   ",
  "                  ............                  ",
  "   ..........................................   ",
  " .............................................. ",
  "   ..........................................   ",
  "    ........................................    ",
  "     ......................................     ",
  "      ....................................      ",
  "        ................................        ",
  "         ..............................         ",
  "          ............................          ",
  "            ........................            ",
  "             ......................             ",
  "              ....................              ",
  "              ....................              ",
  "              ....................              ",
  "              ....................              ",
  "             ......................             ",
  "             ......................             ",
  "             ......................             ",
  "            ........................            ",
  "            ...........  ...........            ",
  "            .........      .........            ",
  "           .........        .........           ",
  "           .......            .......           ",
  "           ......              ......           ",
  "           .....                .....           ",
  "          ....                    ....          ",
  "          ...                      ...          ",
  "          .                          .          ",
  "                                                ",
  "                                                ",]


def url_handler(dialog, link, user_data):
  """
  バージョン情報ダイアログのURLをクリックしたときに開く
  """
  # xdg-openとfirefoxだけの簡易的なチェックをしている
  if os.system("xdg-open %s" % link) != 0:
    if os.system("firefox %s" % link) != 0:
      print "url open failed"


class TestWindow(gtk.Window):
  """
  テスト用ウィンドウ
  """
  pos  = None  # 復元処理が最初だけ行われないように
  size = None  # 分岐する関係で、Noneにしている
  def __init__(self, item, **args):
    """
    ウィンドウの初期化
    """
    gtk.Window.__init__(self, **args)  # 親クラスのコンストラクタ

    global xpm_icon

    self.item = item
    self.set_title("Test window")
    self.set_size_request(300, 180)  # 最小サイズ
    # ファイルの場所を指定してset_icon_from_file()で開く
    # この場合はスクリプトと同じディレクトリにある「icon.png」
    self.set_icon_from_file(os.path.join(os.path.dirname(__file__), "icon.png"))
    # 下は埋め込みXPMアイコンを使用する場合(色数とサイズに注意)
    # (set_icon()の引数はgtk.gdk.Pixbufオブジェクト)
    ##self.set_icon(gtk.gdk.pixbuf_new_from_xpm_data(xpm_icon))
    # set_icon_name()ではアイコン名で指定
    # /usr/share/icons/[使用しているアイコンテーマ名]/以下や
    # /usr/share/pixmaps/以下の拡張子を除いたファイル名部分を指定
    ##self.set_icon_name("user-trash-full")

    # スクロールバーの付いたテキストビューを1つ配置
    self.textview = gtk.TextView()
    self.sw = gtk.ScrolledWindow()
    self.sw.add(self.textview)
    self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    self.add(self.sw)

    # シグナル
    self.connect("delete_event", self.delete)
  def delete(self, widget, event):
    """
    閉じるボタンなどにより閉じられたときの処理
    """
    # 座標とサイズの記憶(2要素のタプル型)
    self.pos = self.get_position()  # X座標とY座標
    self.size = self.get_size()     # 幅と高さ
    # メニュー項目のチェックを外す
    self.item.set_active(False)
    # 隠しつつ、Trueを返して破壊を防ぐ
    return self.hide_on_delete()  # gtk.Widgetクラスのメンバ関数
  def restore_and_show_all(self, active):
    """
    記憶された位置とサイズを復元して表示する
    """
    if active == True:  # gtk.CheckMenuItemのチェック状態を引数として渡している
      # 位置とサイズを復元してから再表示・最初は復元しない
      if self.pos:      # 初期値はNoneにしているため、最初は復元されない
        (x, y) = self.pos           # タプル要素の分解
        self.move(x, y)             # 移動
      if self.size:
        (width, height) = self.size
        self.resize(width, height)  # サイズ変更
      self.show_all()               # 再表示
    else:
      # 既に表示されているときには隠すようにする
      self.emit("delete_event", None)  # delete_eventを起こす

class TrayMenu(gtk.Menu):
  """
  システムトレイのメニュー
  """
  def __init__(self, tray):
    gtk.Menu.__init__(self)

    self.tray = tray

    # メニュー項目(チェック形式)
    self.item1 = gtk.CheckMenuItem("Window")
    self.item1.connect("activate", self.item1_activate)
    self.append(self.item1)

    # 区切り線
    self.append(gtk.SeparatorMenuItem())

    # メニュー項目(バージョン情報ダイアログ)
    self.item2 = gtk.ImageMenuItem(stock_id=gtk.STOCK_ABOUT)
    self.item2.connect('activate', self.item2_activate)
    self.append(self.item2)

    # 区切り線
    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()

    # ウィンドウを準備しておく
    self.win = TestWindow(item=self.item1, type=gtk.WINDOW_TOPLEVEL)
  def activate(self, widget):
    # item1を選択したことにする(チェックの状態変化 + ウィンドウ表示状態変化)
    self.item1.emit("activate")
  def item1_activate(self, widget):
    """
    項目item1が選択されたときの処理
    """
    self.win.restore_and_show_all(widget.get_active())  # widgetとself.item1は同一
  def item2_activate(self, widget):
    """
    項目item2が選択されたときの処理
    """
    global xpm_icon

    url = "http://d.hatena.ne.jp/kakurasan/20080726/p1"
    gtk.about_dialog_set_url_hook(url_handler, url)  # URLを開く関数の関連付け
    aboutdlg = gtk.AboutDialog()
    # ダイアログ(gtk.Windowの子クラス)のアイコンの指定方法も同様
    aboutdlg.set_icon_from_file(os.path.join(os.path.dirname(__file__), "icon.png"))
    ##aboutdlg.set_icon(gtk.gdk.pixbuf_new_from_xpm_data(xpm_icon))  # XPM
    aboutdlg.set_name("Test")
    aboutdlg.set_copyright("(C) 2008 kakurasan")
    aboutdlg.set_comments("Icon test")  # アプリケーションの説明など
    aboutdlg.set_license("Licensed under GPLv3")  # 実際にはライセンス本文を入れる
    aboutdlg.set_wrap_license(True)  # ライセンス自動折り返し
    aboutdlg.set_website(url)        # 実際のURL
    aboutdlg.set_website_label(url)  # URLリンクで表示される文字列
    aboutdlg.set_authors(["kakurasan"])
    # バージョン情報ダイアログのロゴ(set_logo()の引数)もgtk.gdk.Pixbuf
    ##aboutdlg.set_logo(gtk.gdk.pixbuf_new_from_xpm_data(xpm_icon))
    # ファイルから読み込む場合はgtk.gdk.pixbuf_new_from_file()でPixbuf生成
    aboutdlg.set_logo(gtk.gdk.pixbuf_new_from_file(os.path.join(os.path.dirname(__file__), "icon.png")))
    # set_logo_icon_name()ではアイコン名で指定
    ##aboutdlg.set_logo_icon_name("user-trash-full")
    aboutdlg.run()
    aboutdlg.destroy()
  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 PyGTKIconLoadTest:
  """
  アイコン、ロゴのテスト
  """
  def main(self):
    tray = gtk.StatusIcon()   # PyGTK 2.10以上
    menu = TrayMenu(tray)     # gtk.Menuの子クラス
    # アイコン名による指定
    ##tray.set_from_icon_name("user-trash-full")
    # ファイルを直接開く場合は直接その場所を指定
    ##tray.set_from_file(os.path.join(os.path.dirname(__file__), "icon.png"))
    # XPMアイコンはコードへの埋め込みができる(ただし、色数とサイズに注意)
    tray.set_from_pixbuf(gtk.gdk.pixbuf_new_from_xpm_data(xpm_icon))

    tray.set_tooltip("test")  # マウスポインタを少し乗せたときに出る文字列
    tray.connect("activate", menu.activate)     # 通常クリック時の処理
    tray.connect("popup-menu", menu.show_menu)  # メニューを出す
    gtk.main()

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

この中で

os.path.join(os.path.dirname(__file__), "icon.png")

と書いている部分のアイコンは、コードと同じディレクトリに置かれたicon.pngを使用する。ファイルが存在しない場合

gobject.GError: ファイル '[スクリプトのあるディレクトリ]/icon.png' のオープンに失敗しました: そのようなファイルやディレクトリはありません

となる。
テスト用に適当に作ったアイコンを
http://cid-3f9be5b1cd4a806c.skydrive.live.com/browse.aspx/%E5%85%AC%E9%96%8B/%E3%83%86%E3%82%B9%E3%83%88%E7%94%A8%E7%B4%A0%E6%9D%90/GTK+%E3%81%AE%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3%E6%8C%87%E5%AE%9A%E3%83%86%E3%82%B9%E3%83%88
に作成・アップロードしたが、これを使用すると、バージョン情報のダイアログでは

と表示される。上のコードでは、ここの他にウィンドウのアイコンとしてもこれを使用している。また、システムトレイでは、埋め込んだXPMのアイコン(水色の星マーク)を表示している。

関連記事:

参考URL: