我有一个带有记录和停止按钮的脚本,记录按钮执行无限循环,但它也会阻止另一个按钮(停止按钮)。我想要构建的是一个从点击记录按钮开始的过程,停止点击停止按钮。这是脚本:
# -*- 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)
有关此问题的任何想法?
答案 0 :(得分: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
答案 1 :(得分: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)
答案 2 :(得分: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 + 3中使用Gtk.main()
代替Gtk.main_iteration()
。
在Gtk + 2中,模块名称为gtk
而不是gi.repository.Gtk
。
然后你可以退出机智:
Gtk.main_quit
def main_quit()
Gtk.main_quit()函数终止当前的主循环级别 最近调用Gtk.main()函数启动。该 通过调用此函数可以减少主循环的嵌套级别。
你可以有几个嵌套的主循环,在这种情况下,你必须退出每个主循环。
或者您也可以使用gtk_dialog.run()
,然后按钮的默认操作就是退出循环。