【问题标题】:Avoiding Closing a GTK Dialog避免关闭 GTK 对话框
【发布时间】:2018-03-29 08:10:18
【问题描述】:

有什么方法可以在按下 OK 按钮之后但在 GTK 对话框中关闭对话框之前运行代码?我希望能够在按下 OK 按钮后对输入到对话框中的一些代码进行语法检查,如果代码无法编译,可以选择保持对话框打开。经过一番谷歌搜索后,我找到了How to avoid closing of Gtk.Dialog in Python?,但令人遗憾的是,答案缺乏细节,所以我不知道如何实现这一点。如何做到这一点?

编辑:虽然链接的问题专门询问了 Python,但我实际上并不关心任何特定的语言。我正在使用 Haskell 绑定,但我可以通过 GTK+ 绑定以任何语言回答。

编辑:如果您发现这个问题试图弄清楚如何进行验证,但没有我的复杂要求,我强烈建议您查看下面的@AlexanderDmitriev's answer

【问题讨论】:

  • 您是否点击了答案中的链接?
  • 是的,我做到了。但是,我已经知道如何构建自定义对话框 - 它是自定义对话框,其内容需要在关闭对话框之前进行验证,我不知道如何制作。

标签: dialog modal-dialog gtk gtk3


【解决方案1】:

我正在添加另一个答案,以使之前的答案有效。

我看到了两种实现期望行为的方法。

  1. 使用已弃用的gtk_dialog_get_action_area 并在此处打包一个按钮
  2. 停止信号发射以防止 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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-04
        • 1970-01-01
        • 1970-01-01
        • 2015-05-17
        • 1970-01-01
        • 2010-12-13
        • 2020-11-01
        • 2012-08-11
        相关资源
        最近更新 更多