Как скрыть Gtk Popup Window, когда пользователь щелкает за окном - PullRequest
11 голосов
/ 17 ноября 2009

Я разработал одно всплывающее окно (без оформления), используя 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.

Ответы [ 3 ]

8 голосов
/ 17 ноября 2009

Изменения:

  • переключается с GTK_WINDOW_POPUP на GTK_WINDOW_TOPLEVEL, нелогично, но я не мог понять, как заставить всплывающее окно принимать фокус.
  • добавить gtk_window подсказки, чтобы всплывающее окно не отображалось на панели задач и в пейджере
  • намеренно установил фокус на всплывающем окне
  • установите GDK_FOCUS_CHANGE_MASK на GDK_WINDOW с помощью 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;
}
2 голосов
/ 10 сентября 2010

Вам не нужно устанавливать фокус клавиатуры на всплывающее окно.

Вам просто нужно захватить мышь на popup_window->window, используя gdk_pointer_grab(...) с аргументами True owner_events и GDK_BUTTON_PRESS_MASK GdkEventMask.

Затем подключите ваше всплывающее окно к "button-press-event". Внутри его обработчик скрывает / уничтожает ваше popup_window и освобождает захват, используя gdk_pointer_ungrab(...), если * координаты события отрицательны или превышают ваш размер popup_window.

1 голос
/ 01 ноября 2015

Другая альтернатива - просто добавить слушатель нажатия кнопки в родительское окно. Преимущество этого заключается в том, что всплывающее окно по-прежнему выглядит как всплывающее окно (и родитель, и сам он могут быть активны одновременно)

#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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...