そのため、インターフェイス要素のレイアウトについては説明しません。そのような記事は既に存在しているからです。 次のステップについて説明します。進行状況を表示するプロセスで、何らかの作業を行うアプリケーションを作成します。
たとえば、変換ユーティリティ(ImageMagickパッケージ)の2つの機能のプリミティブGUIを作成します。 私たちのプログラムは4つの価値を取ります:
- 画像を縮小するサイズ
- 品質
- 画像付きカタログ
- 保存するディレクトリ
インターフェイス自体は、空き地で作成されます。 重要なのは、プロジェクトがGtkBuilder形式である必要があることです。

以下に2つのコード例を示します。1つ目は普通のもので、2つ目は画像処理用の別のスレッドを作成します。 2つの例があります-スレッドをいじることが理にかなっているかどうかを明確に確認するためです。
スケルトンプログラム:
#!/usr/bin/python
# coding: utf-8
try :
import sys , pygtk
pygtk . require ( '2.0' )
except :
print ' PyGTK'
sys . exit ( 1 )
import gtk , os , time
class GUI ( object ) :
def __init__ ( self ) :
self . wTree = gtk . Builder ( )
#
self . wTree . add_from_file ( "convert.glade" )
#
self . wTree . connect_signals ( self )
self . window1 = self . wTree . get_object ( "window1" )
self . progressdialog = self . wTree . get_object ( "progressdialog" )
self . progressbar_label = self . wTree . get_object ( "progressbar_label" )
self . window1 . show ( )
#
self . wTree . get_object ( "size" ) . set_value ( 100 )
self . wTree . get_object ( "quality" ) . set_value ( 95 )
self . progressbar = self . wTree . get_object ( "progressbar" )
def on_cancel ( self , widget ) :
gtk . main_quit ( )
def on_progressdialog_close ( self , * args ) :
self . stop = True
self . progressdialog . hide ( )
return True
if __name__ = = "__main__" :
app = GUI ( )
gtk . main ( )
メインのon_startメソッドを追加します。これは、プログレスバーダイアログを表示し、ユーザー指定の値を受け取り、ファイルのリストを生成し(ディレクトリを除く)、処理に直接関与します。
def on_start ( self , widget ) :
self . progressdialog . show ( )
self . stop = False
# GUI
self . size = int ( self . wTree . get_object ( "size" ) . get_value ( ) )
self . quality = int ( self . wTree . get_object ( "quality" ) . get_value ( ) )
self . from_dir = self . wTree . get_object ( "from_dir" ) . get_current_folder ( )
self . to_dir = self . wTree . get_object ( "to_dir" ) . get_current_folder ( )
files = [ ]
all_files = os . listdir ( self . from_dir )
for f in all_files :
fullname = os . path . join ( self . from_dir , f )
if os . path . isfile ( fullname ) :
files . append ( f )
count = len ( files )
i = 1.0
for file in files :
#
if self . stop :
break
self . progressbar_label . set_text ( file )
self . progressbar . set_fraction ( i / count )
os . popen ( 'convert -resize ' + str ( self . size ) + ' -quality ' + str ( self . quality ) + ' ' + os . path . join ( self . from_dir , file ) + ' ' + os . path . join ( self . to_dir , file ) )
#
while gtk . events_pending ( ) :
gtk . main_iteration ( )
time . sleep ( 5 )
i + = 1
self . progressdialog . hide ( )
ダイアログボックスを表示し、GUIから値を読み込み、ファイルのリストを生成します。 次に、ファイルリストを繰り返し処理するループを実行します。
まず、self.stopの処理の終了を示す停止フラグがあるかどうかを確認します(キャンセルボタンのon_progressdialog_closeメソッドで設定するか、ダイアログボックスを閉じます)。 さらに、プロセスでは、進行状況バーのテキストと処理の割合を変更し、必要なパラメーターを使用して変換ユーティリティ自体を実行します。
重要なコード
while gtk . events_pending ( ) :
gtk . main_iteration ( )
これがないと、ダイアログボックスが表示されず、処理が完了するまでインターフェイスがフリーズします。 これは、ループが完了するまでインターフェイスの再描画(メインループ)をブロックするためです。 上記のコードは、短時間メインループに制御を戻します。
また、具体的にtime.sleep(5)を追加しました。高速コンピューターを使用している場合、処理中(またはスリープ中)にインターフェイスがイベントに応答しないことに気付かない場合があります。
スレッド
PyGTKのスレッドでは、知らないうちにいじらなければなりませんでした。 まず、gtk.gdk.threads_init()を呼び出す必要があり、さらにgtkへのすべての呼び出しは、gtk.threads_enter()およびgtk.threads_leave()によってフレーム化される必要があります。
#!/usr/bin/python
# coding: utf-8
try :
import sys , pygtk
pygtk . require ( '2.0' )
except :
print ' PyGTK'
sys . exit ( 1 )
import threading , gtk , os , time
class GUI ( object ) :
def __init__ ( self ) :
self . wTree = gtk . Builder ( )
#
self . wTree . add_from_file ( "convert.glade" )
#
self . wTree . connect_signals ( self )
self . window1 = self . wTree . get_object ( "window1" )
self . dialog = {
"progressdialog" : self . wTree . get_object ( "progressdialog" ) ,
"progressbar_label" : self . wTree . get_object ( "progressbar_label" ) ,
"progressbar" : self . wTree . get_object ( "progressbar" )
}
self . window1 . show ( )
#
self . wTree . get_object ( "size" ) . set_value ( 100 )
self . wTree . get_object ( "quality" ) . set_value ( 95 )
def on_cancel ( self , widget ) :
gtk . main_quit ( )
def on_progressdialog_close ( self , * args ) :
self . work . stop ( )
self . dialog [ 'progressdialog' ] . hide ( )
return True
def on_start ( self , widget ) :
self . dialog [ 'progressdialog' ] . show ( )
#
self . data = {
'size' : int ( self . wTree . get_object ( "size" ) . get_value ( ) ) ,
'quality' : int ( self . wTree . get_object ( "quality" ) . get_value ( ) ) ,
'from_dir' : self . wTree . get_object ( "from_dir" ) . get_current_folder ( ) ,
'to_dir' : self . wTree . get_object ( "to_dir" ) . get_current_folder ( )
}
files = [ ]
all_files = os . listdir ( self . data [ 'from_dir' ] )
for f in all_files :
fullname = os . path . join ( self . data [ 'from_dir' ] , f )
if os . path . isfile ( fullname ) :
files . append ( f )
self . work = Worker ( self . dialog , self . data , files )
self . work . start ( )
if __name__ = = "__main__" :
gtk . gdk . threads_init ( )
app = GUI ( )
gtk . gdk . threads_enter ( )
gtk . main ( )
gtk . gdk . threads_leave ( )
コードが少し変更されました。 self.dialogディクショナリを作成しました。これは以下で役立ちます。on_startメソッドは、データを準備して新しいスレッドを起動するだけで、直接処理はプログラムのインターフェイスをブロックしません。
Workerクラスを作成します。
class Worker ( threading . Thread ) :
#
stopthread = threading . Event ( )
def __init__ ( self , dialog , data , files ) :
threading . Thread . __init__ ( self )
self . dialog = dialog
self . data = data
self . files = files
def run ( self ) :
count = len ( self . files )
i = 1.0
for file in self . files :
#
if ( self . stopthread . isSet ( ) ) :
self . stopthread . clear ( )
break
self . dialog [ 'progressbar' ] . set_fraction ( i / count )
self . dialog [ 'progressbar_label' ] . set_text ( file )
os . popen ( 'convert -resize ' + str ( self . data [ 'size' ] ) + ' -quality ' + str ( self . data [ 'quality' ] ) + ' ' + os . path . join ( self . data [ 'from_dir' ] , file ) + ' ' + os . path . join ( self . data [ 'to_dir' ] , file ) )
time . sleep ( 2 )
i + = 1
#
self . stopthread . clear ( )
#
self . dialog [ 'progressdialog' ] . hide ( )
def stop ( self ) :
self . stopthread . set ( )
パラメーターを受け入れるように、コンストラクター(__init__)を再定義する必要がありました。 これらは、ダイアログ辞書(私が言った、便利になるだろう)、データ(サイズ、品質、2つのディレクトリ)、およびファイルのリストです。
runメソッドには、起動時に実行する必要があるもの、つまり 処理自体。
「顔の結果」と言うように、それだけです。
この例では、対話の完了率とその変化の計算は、作業スレッドで直接行われます。 これは不正な形式と見なされ、複数のスレッドが存在する場合は機能しません(より正確には、エラーが発生しても機能します)。
プログラムのわずかに拡張されたバージョンは次のようになります

機能について読んで、 ここからダウンロードしてください 。
ソースコードでアーカイブします 。
UPD:
alex3dは、マニュアルに一致する場合、Worker.runで次の行を実行することを思い出しました
self.dialog['progressbar'].set_fraction(i/count)
self.dialog['progressbar_label'].set_text(file)
包む必要がある
gtk.threads_enter()/ gtk.threads_leave()。