0

記録ボタンと停止ボタンを持つスクリプトがあります。記録ボタンは無限ループを実行しますが、他のボタン (停止ボタン) もブロックします。私が構築したかったのは、記録ボタンのクリックで開始し、停止ボタンのクリックで停止するプロセスだけです。スクリプトは次のとおりです。

# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# This file is in the public domain
### END LICENSE

from locale import gettext as _

from gi.repository import Gtk # pylint: disable=E0611
import logging
logger = logging.getLogger('recordme')

from recordme_lib import Window
from recordme.AboutRecordmeDialog import AboutRecordmeDialog
from recordme.PreferencesRecordmeDialog import PreferencesRecordmeDialog

class RecordmeWindow(Window):
    __gtype_name__ = "RecordmeWindow"
    record = False

    def finish_initializing(self, builder): # pylint: disable=E1002
        """Set up the main window"""
        super(RecordmeWindow, self).finish_initializing(builder)

       self.AboutDialog = AboutRecordmeDialog
       self.PreferencesDialog = PreferencesRecordmeDialog

       # Code for other initialization actions should be added here.
       self.button1 = self.builder.get_object('button1')
       self.button2 = self.builder.get_object('button2')

    def on_button1_clicked(self, widget):
        while(not self.record):
             print 'button1 clicked'
             while gtk.events_pending():
                gtk.main_iteration(False)

この問題についてのアイデアはありますか?

4

3 に答える 3

2

これもイベントベースの WX で同様のプログラムに遭遇しました。この問題を解決するために私が見つけた最良の (そしておそらく唯一の) 方法は、メイン ループ中にタイマーで実行される関数を作成することです。私のものは定期的に実行されましたが、関数を実行するときに待機してループを閉じるように設定することもできます。GTK では、これを別のモジュール「gobject」で行う必要があります。GTK で定期的に実行されるメソッドの例を次に示します。

import gobject

class gtk_object(object):
    def __init__(self):
        gobject.timeout_add(100, self.my_function)
    def my_function(self):
        #do something here, like stopping the loop or having a timer to stop the loop
        return True
于 2013-11-19T04:44:32.147 に答える
1

GTK+ (ほとんどの UI ツールキットと同様) はイベントベースです。つまり、内部の「イベント ループ」 (ユーザー入力の処理やウィンドウの再描画などのイベントを収集して処理するループ) を実行します。すべてのイベント ハンドラーは、メイン ループからディスパッチされます。イベントを処理するには、ループが「回転」している必要があります。

あなたの例では、メインループをブロックしています:

def on_button1_clicked(self, widget):
    while(not self.record):
         print 'button1 clicked'

この関数が終了しない限り、制御はメイン ループに戻らないため、他のイベントを処理したり、ウィンドウを再描画したりできません。

このスニペット フォームPyGTK FAQを追加して、その間にメイン ループがイベントを処理できるようにすることができます。

while gtk.events_pending():
  gtk.main_iteration(False)
于 2013-11-11T20:01:53.660 に答える
1

レコード機能が CPU を集中的に使用する、および/またはブロックする可能性がある、および/またはソフト リアルタイム アシュアランスが必要であると仮定すると、別の「ワーカー」スレッドに移動することをお勧めします。

次に、ウィンドウとボタンを作成します。

ここでは、「記録」をクリックすると、ワーカーに記録を開始するように合図します。「停止」をクリックすると、ワーカーに停止するように通知します。必要に応じて、アプリを終了する場合は、停止がクリックされたときにメイン ループを終了します。

ウィンドウが閉じられたときにアプリを終了し、ワーカー スレッドを正しく終了するための追加の制御ロジックは、一番下にあります。

#!/usr/bin/env python
import time
import logging
import threading
from gi.repository import Gtk


class Worker(threading.Thread):
    should_record = False
    quit = False

    def run(self):
        while not self.quit:
            if self.should_record:
                logging.warn("recording...")
                # cpu-intensive code here
            else:
                time.sleep(0.1)


class MainWindow(Gtk.Window):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.worker = Worker()
        self.worker.start()
        hb = Gtk.Box()
        self.add(hb)
        record = Gtk.Button("Record")
        stop = Gtk.Button("Stop")
        hb.add(record)
        hb.add(stop)

        def command(arg):
            self.worker.should_record = arg

        record.connect("clicked", lambda _b: command(True))
        stop.connect("clicked", lambda _b: command(False))
        # optional, if you want to quit the app on stop as well
        stop.connect("clicked", lambda _b: Gtk.main_quit())

if __name__ == "__main__":
    main = MainWindow()
    try:
        # optional, if you want to support close window to quit app
        main.connect("delete-event", Gtk.main_quit)
        main.show_all()
        Gtk.main()
    finally:
        main.worker.quit = True
        main.worker.join()

古いもの

理想的には、Gtk+ 3Gtk.main()の代わりに使用したいと考えています。Gtk.main_iteration()

Gtk+ 2 では、モジュール名はgtkではなくgi.repository.Gtk.

次に、次の方法で機知を終了できます。

Gtk.main_quit

def main_quit()

Gtk.main_quit() 関数は、Gtk.main() 関数への最新の呼び出しによって開始された現在のメイン ループ レベルを終了します。この関数を呼び出すことにより、メイン ループのネスト レベルが削減されます。

複数の入れ子になったメイン ループを持つことができます。その場合、それらのそれぞれを終了する必要があります。

gtk_dialog.run()または、ボタンのデフォルトのアクションを使用してループを終了することもできます。

于 2013-11-18T14:09:22.643 に答える