【问题标题】:How to hide Gtk Popup Window when user clickes outside the window当用户在窗口外单击时如何隐藏 Gtk 弹出窗口
【发布时间】:2009-11-17 09:11:50
【问题描述】:

我使用 GTK+ 和 Glade 工具在 C 中开发了一个弹出窗口(未装饰)。 单击按钮时,它会在其父窗口中弹出。当用户在此窗口外单击时,我想销毁或隐藏此弹出窗口。用户可以单击父窗口或任何其他窗口。 我试图捕获GDK_FOCUS_CHANGE 事件,但我无法捕获此事件。有什么办法可以做到这一点?我怎么知道点击是在其他窗口上然后弹出窗口?弹出窗口失去焦点如何清楚? 这样我就可以隐藏它。 相关代码如下:

/*
 * Compile me with:

 gcc -o popup popup.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
*/

#include <gtk/gtk.h>

static void on_popup_clicked (GtkButton*, GtkWidget*);
static gboolean on_popup_window_event(GtkWidget*, GdkEventExpose*);

int main (int argc, char *argv[])
{
    GtkWidget *window, *button, *vbox;

    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (window), "Parent window");
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    gtk_widget_set_size_request (window, 300, 300);
    gtk_window_set_position (GTK_WINDOW (window),GTK_WIN_POS_CENTER);

    button = gtk_button_new_with_label("Pop Up");
    g_signal_connect (G_OBJECT (button), "clicked",G_CALLBACK (on_popup_clicked),(gpointer) window);

    vbox = gtk_vbox_new (FALSE, 3);
    gtk_box_pack_end(GTK_BOX (vbox), button, FALSE, FALSE, 5);
    gtk_container_add (GTK_CONTAINER (window), vbox);

    gtk_widget_show_all (window);
    gtk_main ();
    return 0;
}

void on_popup_clicked (GtkButton* button, GtkWidget* pWindow)
{
    GtkWidget *popup_window;
    popup_window = gtk_window_new (GTK_WINDOW_POPUP);
    gtk_window_set_title (GTK_WINDOW (popup_window), "Pop Up window");
    gtk_container_set_border_width (GTK_CONTAINER (popup_window), 10);
    gtk_window_set_resizable(GTK_WINDOW (popup_window), FALSE);
    gtk_window_set_decorated(GTK_WINDOW (popup_window), FALSE);
    gtk_widget_set_size_request (popup_window, 150, 150);
    gtk_window_set_transient_for(GTK_WINDOW (popup_window),GTK_WINDOW (pWindow));
    gtk_window_set_position (GTK_WINDOW (popup_window),GTK_WIN_POS_CENTER);
    g_signal_connect (G_OBJECT (button), "event",
                        G_CALLBACK (on_popup_window_event),NULL);

    GdkColor color;
    gdk_color_parse("#3b3131", &color);
    gtk_widget_modify_bg(GTK_WIDGET(popup_window), GTK_STATE_NORMAL, &color);


    gtk_widget_show_all (popup_window);
}

gboolean on_popup_window_event(GtkWidget *popup_window, GdkEventExpose *event)
{
    if(event->type == GDK_FOCUS_CHANGE)
        gtk_widget_hide (popup_window);

    return FALSE;
}

在这里,当用户单击父窗口或其他窗口时,我无法隐藏此弹出窗口。我怎样才能做到这一点?

我必须坚持使用 Gtk+2.14 版本。

【问题讨论】:

标签: c gtk


【解决方案1】:

变化:

  • GTK_WINDOW_POPUP 切换到GTK_WINDOW_TOPLEVEL,违反直觉,但我不知道如何让弹出窗口接受焦点。
  • 添加gtk_window 提示以防止弹出窗口显示在任务栏和寻呼​​机中
  • 故意将焦点设置在弹出窗口上
  • GDK_WINDOW 上的GDK_FOCUS_CHANGE_MASK 设置为gtk_widget_set_events(下一步需要)
  • 连接弹窗的focus-out-event
  • 更改信号处理程序以处理不同的信号

我还建议阅读 GTK+ 源代码,了解它在显示工具提示和菜单时如何处理弹出窗口...但这些通常会因鼠标超出范围而不是弹出窗口失去焦点而被破坏瑟。


#include 

static void on_popup_clicked (GtkButton*, GtkWidget*);
gboolean on_popup_focus_out (GtkWidget*, GdkEventFocus*, gpointer);

int
main (int argc, char *argv[])
{
  GtkWidget *window, *button, *vbox;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Parent window");
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
  gtk_widget_set_size_request (window, 300, 300);
  gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);

  button = gtk_button_new_with_label ("Pop Up");
  g_signal_connect (G_OBJECT (button),
                    "clicked",
                    G_CALLBACK (on_popup_clicked),
                    (gpointer) window);

  vbox = gtk_vbox_new (FALSE, 3);
  gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 5);
  gtk_container_add (GTK_CONTAINER (window), vbox);

  gtk_widget_show_all (window);
  gtk_main ();
  return 0;
}

void
on_popup_clicked (GtkButton* button, GtkWidget* pWindow)
{
  GtkWidget *popup_window;

  popup_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (popup_window), "Pop Up window");
  gtk_container_set_border_width (GTK_CONTAINER (popup_window), 10);
  gtk_window_set_resizable (GTK_WINDOW (popup_window), FALSE);
  gtk_window_set_decorated (GTK_WINDOW (popup_window), FALSE);
  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (popup_window), TRUE);
  gtk_window_set_skip_pager_hint (GTK_WINDOW (popup_window), TRUE);
  gtk_widget_set_size_request (popup_window, 150, 150);
  gtk_window_set_transient_for (GTK_WINDOW (popup_window), GTK_WINDOW (pWindow));
  gtk_window_set_position (GTK_WINDOW (popup_window), GTK_WIN_POS_CENTER);

  gtk_widget_set_events (popup_window, GDK_FOCUS_CHANGE_MASK);
  g_signal_connect (G_OBJECT (popup_window),
                    "focus-out-event",
                    G_CALLBACK (on_popup_focus_out),
                    NULL);

  GdkColor color;
  gdk_color_parse ("#3b3131", &color);
  gtk_widget_modify_bg (GTK_WIDGET (popup_window), GTK_STATE_NORMAL, &color);

  gtk_widget_show_all (popup_window);
  gtk_widget_grab_focus (popup_window);
}

gboolean
on_popup_focus_out (GtkWidget *widget,
                    GdkEventFocus *event,
                    gpointer data)
{
  gtk_widget_destroy (widget);
  return TRUE;
}

【讨论】:

  • 好交易。如果此答案对您有用,请随时单击答案旁边的大复选标记。 :)
  • 很好的解决方案,但有一个问题:主窗口通过不同的边框着色(Windows 7)在视觉上记录焦点变化。这不应该发生在(假)弹出窗口中。有什么办法可以防止这种情况发生吗?
  • 为了清楚起见,这里有一些截图:imageshack.us/g/211/beforegp.png(以图标为例)
【解决方案2】:

您无需将键盘焦点设置为弹出窗口。

您只需使用带有 True owner_events 和 GDK_BUTTON_PRESS_MASK GdkEventMask 参数的 gdk_pointer_grab(...) 将鼠标捕获到您的 popup_window-&gt;window

然后将您的 popup_window 连接到 "button-press-event"。如果 *event 坐标为负数或高于您的 popup_window 大小,则在它的处理程序内部隐藏/销毁您的 popup_window 并使用 gdk_pointer_ungrab(...) 释放捕获。

【讨论】:

    【解决方案3】:

    另一种选择是简单地将按钮按下侦听器添加到父窗口。这样做的好处是弹出窗口仍然看起来像一个弹出窗口(父级和自身都可以同时处于活动状态)

    #include <stdio.h>
    #include <gtk/gtk.h>
    
    static void on_popup_clicked (GtkButton*, GtkWidget*);
    
    gulong handler_id;
    
    gboolean
    on_click (GtkWidget *widget,
                   GdkEvent  *event,
                   gpointer   user_data)
    {
      g_signal_handler_disconnect (widget, handler_id);
      gtk_widget_destroy (user_data);
      return TRUE;
    }
    
    
    gboolean
    on_popup_focus_out (GtkWidget *widget,
                        GdkEventFocus *event,
                        gpointer data)
    {
      gtk_widget_destroy (widget);
      return TRUE;
    }
    
    
    int
    main (int argc, char *argv[])
    {
      GtkWidget *window, *button, *vbox;
    
      gtk_init (&argc, &argv);
    
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_title (GTK_WINDOW (window), "Parent window");
      gtk_container_set_border_width (GTK_CONTAINER (window), 10);
      gtk_widget_set_size_request (window, 300, 300);
      gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
    
      button = gtk_button_new_with_label ("Pop Up");
      g_signal_connect (G_OBJECT (button),
                        "clicked",
                        G_CALLBACK (on_popup_clicked),
                        (gpointer) window);
    
      vbox = gtk_vbox_new (FALSE, 3);
      gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 5);
      gtk_container_add (GTK_CONTAINER (window), vbox);
    
      gtk_widget_show_all (window);
      gtk_main ();
      return 0;
    }
    
    void
    on_popup_clicked (GtkButton* button, GtkWidget* pWindow)
    {
      GtkWidget *popup_window;
    
      popup_window = gtk_window_new (GTK_WINDOW_POPUP);
      gtk_window_set_title (GTK_WINDOW (popup_window), "Pop Up window");
      gtk_container_set_border_width (GTK_CONTAINER (popup_window), 10);
      gtk_window_set_resizable (GTK_WINDOW (popup_window), FALSE);
      gtk_window_set_decorated (GTK_WINDOW (popup_window), FALSE);
      gtk_window_set_skip_taskbar_hint (GTK_WINDOW (popup_window), TRUE);
      gtk_window_set_skip_pager_hint (GTK_WINDOW (popup_window), TRUE);
      gtk_widget_set_size_request (popup_window, 150, 150);
      gtk_window_set_transient_for (GTK_WINDOW (popup_window), GTK_WINDOW (pWindow));
      gtk_window_set_position (GTK_WINDOW (popup_window), GTK_WIN_POS_CENTER);
    
      gtk_widget_add_events (popup_window, GDK_FOCUS_CHANGE_MASK);
      gtk_widget_add_events (pWindow, GDK_BUTTON_PRESS_MASK);
    
      g_signal_connect (G_OBJECT (popup_window),
                        "focus-out-event",
                        G_CALLBACK (on_popup_focus_out),
                        NULL);
    
      handler_id = g_signal_connect (G_OBJECT (pWindow),
                        "button-press-event",
                        G_CALLBACK (on_click),
                        popup_window);
    
      GdkColor color;
      gdk_color_parse ("#3b3131", &color);
      gtk_widget_modify_bg (GTK_WIDGET (popup_window), GTK_STATE_NORMAL, &color);
    
      gtk_widget_show_all (popup_window);
      gtk_widget_grab_focus (popup_window);
    }
    

    【讨论】:

      猜你喜欢
      • 2022-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2015-08-11
      相关资源
      最近更新 更多