避免关闭 GTK 对话框
Posted
技术标签:
【中文标题】避免关闭 GTK 对话框【英文标题】:Avoiding Closing a GTK Dialog 【发布时间】:2018-03-29 08:10:18 【问题描述】:有什么方法可以在按下 OK 按钮之后但在 GTK 对话框中关闭对话框之前运行代码?我希望能够在按下 OK 按钮后对输入到对话框中的一些代码进行语法检查,如果代码无法编译,可以选择保持对话框打开。经过一番谷歌搜索后,我找到了How to avoid closing of Gtk.Dialog in Python?,但令人遗憾的是,答案缺乏细节,所以我不知道如何实现这一点。如何做到这一点?
编辑:虽然链接的问题专门询问了 Python,但我实际上并不关心任何特定的语言。我正在使用 Haskell 绑定,但我可以通过 GTK+ 绑定以任何语言回答。
编辑:如果您发现这个问题试图弄清楚如何进行验证,但没有我的复杂要求,我强烈建议您查看下面的@AlexanderDmitriev's answer。
【问题讨论】:
您是否点击了答案中的链接? 是的,我做到了。但是,我已经知道如何构建自定义对话框 - 它是自定义对话框,其内容需要在关闭对话框之前进行验证,我不知道如何制作。 【参考方案1】:我正在添加另一个答案,以使之前的答案有效。
我看到了两种实现期望行为的方法。
-
使用已弃用的
gtk_dialog_get_action_area
并在此处打包一个按钮
停止信号发射以防止 GtkDialog “看到”响应按钮被按下。
这两种方法都可以在下面的代码中找到。查找deprecated
用于第一种方法,查找awesome
用于第二种方法
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class DialogExample(Gtk.Dialog):
button_state = True
def awesome_cb (button, de):
if de.button_state:
print("Awesome ok")
else:
print("Awesome Not allowed")
button.stop_emission_by_name ("clicked")
def deprecated_cb (button, de):
if de.button_state:
print("Deprecated ok")
de.response(11)
else:
print("Deprecated Not allowed");
def switch_state(button, de):
de.button_state = not de.button_state
de.dialog_ok_btn.set_sensitive (de.button_state)
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(150, 100)
label = Gtk.Label("This is a dialog to display additional information")
box = self.get_content_area()
state_switcher_btn = Gtk.Button ("Switch")
state_switcher_btn.connect ("clicked", DialogExample.switch_state, self)
box.add(label)
box.add(state_switcher_btn)
hard_work_button = Gtk.Button ("deprec")
hard_work_button.connect ("clicked", DialogExample.deprecated_cb, self)
carea = self.get_action_area()
carea.add (hard_work_button)
tfb = Gtk.Button ("awesome");
tfb.connect("clicked", DialogExample.awesome_cb, self)
self.add_action_widget(tfb, 12)
self.dialog_ok_btn = self.get_widget_for_response (Gtk.ResponseType.OK)
self.show_all()
def do_response (self, response_id):
print ("Response! ID is ", response_id)
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
button = Gtk.Button("Open dialog")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
elif response == Gtk.ResponseType.CANCEL:
print("The Cancel button was clicked")
dialog.destroy()
win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
【讨论】:
【参考方案2】:看起来 GtkDialog 本身不允许取消按钮按下(从用户的角度来看这是可以的)。但是,每次用户更改某些内容时,您都可以检查它并使按钮敏感与否。我已经扩展了code from answer to mentioned question
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class DialogExample(Gtk.Dialog):
#this variable controls, whether OK is sensitive
button_state = True
def switch_state(button, de):
print ("switcher")
de.button_state = not de.button_state
de.set_response_sensitive (Gtk.ResponseType.OK, de.button_state)
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(150, 100)
label = Gtk.Label("This is a dialog to display additional information")
box = self.get_content_area()
# a button to switch OK's sensitivity
state_switcher_btn = Gtk.Button ("Switch")
state_switcher_btn.connect ("clicked", DialogExample.switch_state, self)
box.add(label)
box.add(state_switcher_btn)
self.show_all()
def do_response (self, response_id):
print ("Override! ID is ", response_id)
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
button = Gtk.Button("Open dialog")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
elif response == Gtk.ResponseType.CANCEL:
print("The Cancel button was clicked")
dialog.destroy()
win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
【讨论】:
聪明的解决方案!不幸的是,我想做的特定类型的验证 - 语法检查 - 会产生一个长而详细的错误消息,我想在消息对话框中显示它,但否则我会使用这个解决方案。我正在编辑我的问题以反映这一点。 我不明白,有什么问题。在我的switch_state
函数中,您仍然可以get_content_area
并在那里打包错误消息。甚至在GtkRevealer
中打包一个标签,并在用户输入正确或错误时分别显示和隐藏文本
好点 - 我没有想到这一点。但是,我一直在考虑您的解决方案,并意识到不幸的是它无论如何都行不通。您的答案需要一些地方放置代码来交换按钮的灵敏度。在您的代码中,将此代码放在switch_state
方法中。我的问题与 TextView 有关,因此为了正确执行此操作,我需要在每次更改文本时检查输入的代码。但是,这意味着每次用户输入另一个字符时,我都需要重新解析输入的代码,...
... 花费很长时间并且使应用程序不太适合使用。我已经编辑了我的问题以更好地反映我的问题。【参考方案3】:
我曾经也有过这个。我决定捕捉response
信号。我有一个可以处理验证的函数。但是,处理response
信号的函数总是返回True
以向GTK 表明信号已经被处理并且对话框没有关闭。如果对话框需要关闭,我手动完成。
myDialogWindow.connect("response", validate_response)
def validate_response(dialog, response_id):
# validate
if correct:
dialog.destroy()
else:
print("Something went wrong")
return True
虽然这可以完成工作,但我不确定这是最类似于 GTK 的解决方案。
【讨论】:
【参考方案4】:根据 Alexander Dmitriev 使用 button.stop_emission_by_name
的提示,我想出了这个解决方案,这可能就是您所要求的:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyDialog(Gtk.Dialog):
def __init__(self, *args, **kwargs):
super(MyDialog, self).__init__(*args, **kwargs)
self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK)
self.connect("response", self._cb_response)
def _cb_response(self, widget, response_id):
if response_id == Gtk.ResponseType.OK and self._check_invalid():
msg = Gtk.MessageDialog(
parent=self,
text="There are errors in what you entered.\n\n"
"Are you sure you want to continue?",
message_type=Gtk.MessageType.QUESTION,
buttons=Gtk.ButtonsType.YES_NO,
)
response = msg.run()
msg.destroy()
if response == Gtk.ResponseType.NO:
widget.stop_emission_by_name("response")
return True
return False
def _check_invalid(self):
"""Placeholder for checking for problems"""
return True
dialog = MyDialog()
dialog.run()
【讨论】:
以上是关于避免关闭 GTK 对话框的主要内容,如果未能解决你的问题,请参考以下文章
对于Gtk #Windows,是否有Form.Showdialog等价物?