2009-11-17 102 views
11

外面我使用GTK +和空地工具C. 它的父窗口彈出時,按鈕按下開發一個彈出窗口(飾非)。當用戶點擊此窗口時,我想銷燬或隱藏此彈出窗口。用戶可以單擊父窗口或任何其他窗口。 我試圖捕獲GDK_FOCUS_CHANGE事件,但我無法捕獲此事件。有什麼辦法可以做到這一點?我如何知道點擊是在其他窗口上,然後彈出窗口?如何清楚彈出窗口失去了焦點? 這樣我就可以隱藏它。 相關的代碼如下:如何隱藏的Gtk彈出式窗口,當用戶clickes窗口

/* 
* 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版本。

+0

請不要轉發問題。這似乎是(更好地呈現)重複http://stackoverflow.com/questions/1740947/problem-with-gtk-popup-window-focus-change-event-handling – mlibby 2009-11-17 12:21:50

+0

我將在未來照顧這一點。 – kbalar 2009-11-17 14:52:37

回答

8

的變化:從GTK_WINDOW_POPUP

  • 開關GTK_WINDOW_TOPLEVEL,反直覺的,但我無法弄清楚如何讓一個彈出窗口接受焦點。
  • 添加gtk_window提示來防止彈出窗口在任務欄和尋呼​​機表示
  • 故意將焦點設置在彈出窗口
  • 設置GDK_FOCUS_CHANGE_MASKGDK_WINDOWgtk_widget_set_events(用於下一步驟必需)
  • 連接到在彈出的窗口中focus-out-event
  • 改變信號處理程序來處理不同的信號

竟被我d還建議閱讀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; 
} 
+0

得到它的工作! 感謝您的關注。 – kbalar 2009-11-17 14:53:36

+0

好交易。如果此答案對您有用,請隨時點擊答案旁邊的大複選標記。:) – mlibby 2009-11-17 15:13:15

+0

偉大的解決方案,但有一個問題:主窗口可視化註冊焦點變化,通過不同的顏色着色(Windows 7)。這不應該發生(假)彈出窗口。任何想法來防止這種情況? – schlamar 2012-10-12 09:35:22

2

您不需要在彈出窗口中設置鍵盤焦點。

你只需要捕獲鼠標您popup_window->window使用gdk_pointer_grab(...)與真owner_events和GDK_BUTTON_PRESS_MASK GdkEventMask參數。

然後你popup_window連接到"button-press-event"。如果*事件座標爲負數或高於popup_window大小,則在其處理程序內部隱藏/銷燬popup_window並釋放捕獲使用gdk_pointer_ungrab(...)

1

另一種選擇是簡單地按下一個按鈕監聽器添加到父窗口。這樣做的好處是彈出窗口仍然看起來像一個彈出窗口(父窗口和它本身都可以同時激活)

#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); 
}