如何与Pygtk / gtkbuilder反复显示对话?
-
09-10-2019 - |
题
我创建了一个Pygtk应用程序,该应用程序显示用户按下按钮时显示对话框。对话框加载在我的 __init__
方法:
builder = gtk.Builder()
builder.add_from_file("filename")
builder.connect_signals(self)
self.myDialog = builder.get_object("dialog_name")
如果处理程序,则显示对话框使用命令显示 self.myDialog.run()
, ,但这只能工作一次,因为之后 run()
对话框自动破坏。如果我第二次单击按钮,则应用程序崩溃。
我读到有一种使用方法 show()
代替 run()
在对话框没有被破坏的地方,但我觉得这对我来说不是正确的方法,因为我希望对话框形成式表现并仅在用户关闭后才将控制权返回到代码。
是否有一种简单的方法可以反复使用该对话框 run()
使用GTKBuilder?我尝试使用GTKBuilder重新加载整个对话框,但这似乎并没有用,对话框缺少所有子元素(我更喜欢在程序开始时只使用一次构建器)。
解决方案 (编辑)
如下答案所指出的那样,使用 hide()
解决问题。我首先认为您仍然需要捕获“删除事件”,但实际上并不是必需的。一个有效的简单示例是:
import pygtk
import gtk
class DialogTest:
def rundialog(self, widget, data=None):
self.dia.show_all()
result = self.dia.run()
self.dia.hide()
def destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("destroy", self.destroy)
self.dia = gtk.Dialog('TEST DIALOG', self.window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
self.dia.vbox.pack_start(gtk.Label('This is just a Test'))
self.button = gtk.Button("Run Dialog")
self.button.connect("clicked", self.rundialog, None)
self.window.add(self.button)
self.button.show()
self.window.show()
if __name__ == "__main__":
testApp = DialogTest()
gtk.main()
解决方案
实际上,阅读 文档 上 Dialog.run()
. 。对话框不会自动销毁。如果你 hide()
当 run()
方法退出,然后您应该能够 run()
它随心所欲。
另外,您可以将对话框设置为构建器文件中的模态,然后只是 show()
它。这将达到类似的效果,但与 run()
- 因为 run()
创建主要GTK循环的第二个实例。
编辑
如果您不连接到 delete-event
信号是您要单击两次关闭按钮。这是发生的事情:
- 您单击“运行对话框”,这调用对话框的
run()
方法。 - 模态对话框出现,并启动自己的主循环。
- 您单击“关闭”按钮。对话框的主循环退出,但是
run()
覆盖关闭按钮的正常行为,对话框未关闭。它也不是隐藏的,因此徘徊。 - 您想知道为什么对话框仍在那里,然后再次单击“关闭”按钮。自从
run()
不再活动了,触发了关闭按钮的正常行为:对话框被销毁。 - 您再次单击“运行对话框”,试图调用
run()
破坏对话的方法。碰撞!
因此,如果您确保 hide()
步骤3之后的对话框,然后一切都应该工作。无需连接到 delete-event
信号。
其他提示
我只是花了一些时间来弄清楚这一点。从构建器重新取出相同的对象不会创建对象的新实例,而只会返回对旧(被摧毁)对象的引用。但是,如果创建一个新的构建器实例,并将文件加载到新的构建器中,它将创建一个新实例。
因此,我的对话框创建功能看起来像这样:
def create():
builder = gtk.Builder()
builder.add_from_file('gui/main.ui')
dlg = builder.get_object('new_dialog')
def response_function(dialog, response_id):
... do stuff ...
dialog.destroy()
dlg.connect('response', response_function)
dlg.show_all()
请注意,在这种情况下,我没有阻止使用Run()响应,因为我使用的是扭曲,但应该等效。
您的对话框只需要运行一次。假设菜单项触发对话框,代码应该看起来像这样:
def on_menu_item_clicked(self, widget, data=None):
dialog = FunkyDialog()
response = dialog.run()
if response = gtk.RESPONSE_OK:
// do something with the dialog data
dialog.destroy()
dialog.run()
是一个封锁主环,当对话框发送响应时返回。这通常是通过确定和取消按钮完成的。发生这种情况时,对话框完成并需要销毁。
要重复显示对话框,用户应遵循相同的工作流程(在上面的示例中,将单击菜单项)。对话负责,在 __init__
, ,用于设置自己。如果你 hide()
对话框,您有与该对话框进行通信的问题,因此它与应用程序的其余部分保持最新 即使隐藏.
某些人想“反复运行对话框”的原因之一是因为用户输入了无效的信息,并且您希望为用户提供纠正它的机会。这必须在对话框的响应信号处理程序中处理。对话框中的事件顺序是:
- 用户实际按确定按钮
- 对话发送回复
gtk.RESPONSE_OK
(-5) - 对话框呼吁处理程序以获取响应信号
- 对话框将处理程序称为“确定”按钮
- 对话
run()
方法返回响应
为了防止步骤4和5发生,响应处理程序必须抑制响应信号。这是如下:
def on_dialog_response(self, dialog, response, data=None:
if response == gtk.RESPONSE_OK:
if data_is_not_valid:
# Display an error message to the user
# Suppress the response
dialog.emit_stop_by_name('response')