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

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

GtkBuilderとGladeについてと、PyGTK上での使用について(実際のコード・前半)

GtkBuilderとGladeについてと、PyGTK上での使用について(概要)」の続き。
PyGTK + Gladeの簡単な例」のコードをもとにgtk.Builderオブジェクトを使用するような修正を行い、gladeファイルと同じ感覚で関数を置き換えていけばうまくいくと思ったのだが、残念ながらそうはいかず、書き方を変えなくてはならない部分が出てきた。ここでは、その作業中のコードを含めて、修正のメモをする。
長さの関係で2回に分けるが、今回は動作しない状態のコードを貼り付けることになる。

使用したuiファイル

gtk-builder-convertでgladeファイルを変換したもの。
ファイル名: pygtkbuildertest.ui

<?xml version="1.0"?>
<interface>
  <object class="GtkUIManager" id="uimanager1">
    <child>
      <object class="GtkActionGroup" id="actiongroup1">
        <child>
          <object class="GtkAction" id="menuitem1">
            <property name="name">menuitem1</property>
            <property name="label" translatable="yes">_File</property>
          </object>
        </child>
        <child>
          <object class="GtkAction" id="imagemenuitem1">
            <property name="stock_id" translatable="yes">gtk-quit</property>
            <property name="name">imagemenuitem1</property>
            <signal handler="gtk_main_quit" name="activate"/>
          </object>
        </child>
      </object>
    </child>
    <ui>
      <menubar name="menubar1">
        <menu action="menuitem1">
          <menuitem action="imagemenuitem1"/>
        </menu>
      </menubar>
    </ui>
  </object>
  <object class="GtkWindow" id="window1">
    <property name="width_request">320</property>
    <property name="height_request">200</property>
    <signal handler="gtk_main_quit" name="delete_event"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <child>
          <object class="GtkMenuBar" constructor="uimanager1" id="menubar1">
            <property name="visible">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="label" translatable="yes">Test</property>
            <signal handler="on_button1_clicked" name="clicked"/>
          </object>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkStatusbar" id="statusbar1">
            <property name="visible">True</property>
            <property name="spacing">2</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

シグナル接続がうまくいかない?

PyGTK + Gladeの簡単な例」では、gladeファイルに記述されているシグナル接続の情報を、gtk.glade.XMLオブジェクトのメンバ関数signal_autoconnect()に引数selfを指定することで行い、更に追加でシグナル接続情報の辞書を用意し、引数に指定してもう一度この関数を呼び出してハンドラ関数の関連付けを行った。
ところが、gtk.Builderオブジェクトのメンバ関数connect_signals()では、self指定と辞書指定のいずれか一方しか使用できなかった。より正確には「2回目に呼び出したconnect_signals()は効果がなかった」。

#! /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,12,0):
  errtitle = "Error"
  errmsg = "PyGTK 2.12.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 PyGTKBuilderTest:
  """
  テスト
  """
  def __init__(self):
    """
    初期化処理
    """
    # uiファイル(同じディレクトリのpygtkbuildertest.ui)を読み込む
    uifile = os.path.dirname(__file__) + "/pygtkbuildertest.ui"
    xml = gtk.Builder()
    xml.add_from_file(uifile)
    # uiファイルで定義されているシグナルを自動で接続
    xml.connect_signals(self)
    # ハンドラ「gtk_main_quit」は別途「gtk.main_quit()」に設定
    # インスタンス指定と辞書指定はどちらか一方しかできない?
    # 先に実行したほうだけが有効になっているような感じ
    signal_dic = { "gtk_main_quit" : gtk.main_quit }
    xml.connect_signals(signal_dic)  # self指定したほうをコメントアウトすると動作
    # 個別のウィジェットをXMLから取り出す
    self.window = xml.get_object("window1")
    # 表示
    self.window.show_all()
  def on_button1_clicked(self, widget):
    """
    ボタンが押されたときの処理
    """
    print "on_button1_clicked"
  def on_imagemenuitem1_select(self, widget):
    """
    メニュー項目が選択されたときの処理(呼ばれない)
    """
    print "on_imagemenuitem1_select"
  def on_imagemenuitem1_deselect(self, widget):
    """
    メニュー項目が選択解除されたときの処理(呼ばれない)
    """
    print "on_imagemenuitem1_deselect"
  def main(self):
    """
    GTK+のメインループを呼ぶ
    """
    gtk.main()

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

上のコードではメニュー項目からの終了が機能しない他、ウィンドウマネージャの閉じるボタンなどを使用して閉じたときに、メインループが終了しない。
もし、

xml.connect_signals(self)

の行をコメントアウトした場合、これらは動作し、逆にボタンクリックは機能しなくなる。

GtkBuilderとGladeについてと、PyGTK上での使用について(実際のコード・後半)」に続く

関連記事:

参考URL:

使用したバージョン:

  • GTK+ 2.12.9(2.12.9-r2)
  • PyGTK 2.12.0
  • Glade 3.4.4