<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # GTK+ 事件和信號 > 原文: [http://zetcode.com/gui/gtk2/gtkevents/](http://zetcode.com/gui/gtk2/gtkevents/) 在 GTK+ 編程教程的這一部分中,我們討論事件系統。 GTK+ 是事件驅動的系統。 所有 GUI 應用都是事件驅動的。 應用啟動一個主循環,該循環不斷檢查新生成的事件。 如果沒有事件,則應用將等待并且不執行任何操作。 在 GTK+ 中,事件是來自 X 服務器的消息。 當事件到達窗口小部件時,它可以通過發出信號對此事件做出反應。 GTK+ 程序員可以將特定的回調連接到信號。 回調是對信號做出反應的處理函數。 ## 點擊按鈕 觸發按鈕時,它會發送`clicked`信號。 可以通過鼠標指針或使用`空格鍵`觸發按鈕(只要按鈕具有焦點)。 `buttonclick.c` ```c #include <gtk/gtk.h> void button_clicked(GtkWidget *widget, gpointer data) { g_print("clicked\n"); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *halign; GtkWidget *btn; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "GtkButton"); gtk_window_set_default_size(GTK_WINDOW(window), 300, 200); gtk_container_set_border_width(GTK_CONTAINER(window), 15); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); halign = gtk_alignment_new(0, 0, 0, 0); btn = gtk_button_new_with_label("Click"); gtk_widget_set_size_request(btn, 70, 30); gtk_container_add(GTK_CONTAINER(halign), btn); gtk_container_add(GTK_CONTAINER(window), halign); g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_clicked), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; } ``` 在應用中,我們有兩個信號:`clicked`信號和`destroy`信號。 ```c g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_clicked), NULL); ``` 我們使用`g_signal_connect()`函數將`clicked`信號連接到`button_clicked()`回調。 ```c void button_clicked(GtkWidget *widget, gpointer data) { g_print("clicked\n"); } ``` 回調將`"clicked"`字符串打印到控制臺。 回調函數的第一個參數是發出信號的對象。 在我們的例子中是單擊按鈕。 第二個參數是可選的。 我們可能會向回調發送一些數據。 在我們的案例中,我們沒有發送任何數據; 我們為`g_signal_connect()`函數的第四個參數提供了`NULL`值。 ```c g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); ``` 如果按標題欄右上角的 x 按鈕,或按 `Atl + F4` ,則會發出`destroy`信號。 調用`gtk_main_quit()`函數,該函數將終止應用。 ## 移動窗口 下一個示例顯示了我們如何應對窗口移動事件。 `moveevent.c` ```c #include <gtk/gtk.h> void configure_callback(GtkWindow *window, GdkEvent *event, gpointer data) { int x, y; GString *buf; x = event->configure.x; y = event->configure.y; buf = g_string_new(NULL); g_string_printf(buf, "%d, %d", x, y); gtk_window_set_title(window, buf->str); g_string_free(buf, TRUE); } int main(int argc, char *argv[]) { GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 200); gtk_widget_add_events(GTK_WIDGET(window), GDK_CONFIGURE); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), G_OBJECT(window)); g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(configure_callback), NULL); gtk_widget_show(window); gtk_main(); return 0; } ``` 在示例中,我們在標題欄中顯示了窗口左上角的當前位置。 ```c gtk_widget_add_events(GTK_WIDGET(window), GDK_CONFIGURE); ``` 小部件的事件掩碼確定特定小部件將接收的事件類型。 一些事件是預先配置的,其他事件必須添加到事件掩碼中。 `gtk_widget_add_events()`將`GDK_CONFIGURE`事件類型添加到掩碼。 `GDK_CONFIGURE`事件類型說明了窗口的所有大小,位置和堆疊順序。 ```c g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(configure_callback), NULL); ``` 當窗口小部件的窗口的大小,位置或棧發生更改時,將發出`configure-event`。 ```c void configure_callback(GtkWindow *window, GdkEvent *event, gpointer data) { int x, y; GString *buf; x = event->configure.x; y = event->configure.y; buf = g_string_new(NULL); g_string_printf(buf, "%d, %d", x, y); gtk_window_set_title(window, buf->str); g_string_free(buf, TRUE); } ``` 回調函數具有三個參數:發出信號的對象,`GdkEvent`和可選數據。 我們確定 x,y 坐標,構建一個字符串,并將其設置為窗口標題。 ![Move event](https://img.kancloud.cn/1a/71/1a71a37cfb5f22acffebf54d6c47969a_302x226.jpg) 圖:移動事件 ## 輸入信號 以下示例顯示了我們如何對`enter`信號做出反應。 當我們使用鼠標指針進入小部件的區域時,將發出`enter`信號。 `entersignal.c` ```c #include <gtk/gtk.h> void enter_button(GtkWidget *widget, gpointer data) { GdkColor col = {0, 27000, 30000, 35000}; gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &col); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *halign; GtkWidget *btn; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 200); gtk_container_set_border_width(GTK_CONTAINER(window), 15); gtk_window_set_title(GTK_WINDOW(window), "Enter signal"); halign = gtk_alignment_new(0, 0, 0, 0); btn = gtk_button_new_with_label("Button"); gtk_widget_set_size_request(btn, 70, 30); gtk_container_add(GTK_CONTAINER(halign), btn); gtk_container_add(GTK_CONTAINER(window), halign); g_signal_connect(G_OBJECT(btn), "enter", G_CALLBACK(enter_button), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; } ``` 在該示例中,當我們將鼠標指針懸停在其上方時,按鈕小部件的背景顏色會更改。 ```c g_signal_connect(G_OBJECT(btn), "enter", G_CALLBACK(enter_button), NULL); ``` 當`enter`信號出現時,我們調用`enter_button()`用戶功能。 ```c void enter_button(GtkWidget *widget, gpointer data) { GdkColor col = {0, 27000, 30000, 35000}; gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &col); } ``` 在回調內部,我們通過調用`gtk_widget_modify_bg()`函數來更改按鈕的背景。 ## 斷開回調 我們可以從信號斷開回調。 下一個代碼示例演示了這種情況。 `disconnect.c` ```c #include <gtk/gtk.h> gint handler_id; void button_clicked(GtkWidget *widget, gpointer data) { g_print("clicked\n"); } void toogle_signal(GtkWidget *widget, gpointer window) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { handler_id = g_signal_connect(G_OBJECT(window), "clicked", G_CALLBACK(button_clicked), NULL); } else { g_signal_handler_disconnect(window, handler_id); } } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *btn; GtkWidget *cb; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 200); gtk_container_set_border_width(GTK_CONTAINER(window), 15); gtk_window_set_title(GTK_WINDOW(window), "Disconnect"); hbox = gtk_hbox_new(FALSE, 15); btn = gtk_button_new_with_label("Click"); gtk_widget_set_size_request(btn, 70, 30); gtk_box_pack_start(GTK_BOX(hbox), btn, FALSE, FALSE, 0); cb = gtk_check_button_new_with_label("Connect"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), TRUE); gtk_box_pack_start(GTK_BOX(hbox), cb, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); handler_id = g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_clicked), NULL); g_signal_connect(G_OBJECT(cb), "clicked", G_CALLBACK(toogle_signal), (gpointer) btn); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; } ``` 在代碼示例中,我們有一個按鈕和一個復選框。 復選框用于從按鈕的`clicked`信號連接或斷開回調。 ```c handler_id = g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_clicked), NULL); ``` `g_signal_connect()`返回唯一標識回調的處理器 ID。 ```c if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { handler_id = g_signal_connect(G_OBJECT(window), "clicked", G_CALLBACK(button_clicked), NULL); } else { g_signal_handler_disconnect(window, handler_id); } ``` 此代碼確定復選框的狀態。 根據狀態,它通過`g_signal_connect()`函數連接回調或通過`g_signal_handler_disconnect()`函數斷開連接。 ![Disconnect](https://img.kancloud.cn/11/53/11538399819c0537e965381e9135b796_302x226.jpg) 圖:斷開連接 ## 拖放示例 在下一個示例中,我們顯示無邊界窗口,并學習如何拖動和移動這樣的窗口。 `dragdrop.c` ```c #include <gtk/gtk.h> gboolean on_button_press(GtkWidget* widget, GdkEventButton *event, GdkWindowEdge edge) { if (event->type == GDK_BUTTON_PRESS) { if (event->button == 1) { gtk_window_begin_move_drag(GTK_WINDOW(gtk_widget_get_toplevel(widget)), event->button, event->x_root, event->y_root, event->time); } } return TRUE; } int main(int argc, char *argv[]) { GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); gtk_window_set_title(GTK_WINDOW(window), "Drag & drop"); gtk_window_set_decorated(GTK_WINDOW(window), FALSE); gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK); g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(on_button_press), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), G_OBJECT(window)); gtk_widget_show(window); gtk_main(); return 0; } ``` 該示例演示了無邊界窗口的拖放操作。 ```c gtk_window_set_decorated(GTK_WINDOW(window), FALSE); ``` 我們使用`gtk_window_set_decorated()`函數刪除窗口裝飾。 這意味著該窗口將沒有邊框和標題欄。 ```c g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(on_button_press), NULL); ``` 我們將窗口連接到`button-press-event`信號。 ```c gboolean on_button_press(GtkWidget* widget, GdkEventButton *event, GdkWindowEdge edge) { if (event->type == GDK_BUTTON_PRESS) { if (event->button == 1) { gtk_window_begin_move_drag(GTK_WINDOW(gtk_widget_get_toplevel(widget)), event->button, event->x_root, event->y_root, event->time); } } return TRUE; } ``` 在`on_button_press()`函數內,我們執行拖放操作。 我們檢查是否按下了鼠標左鍵。 然后我們調用`gtk_window_begin_move_drag()`函數,該函數開始移動窗口。 ## 計時器示例 下面的示例演示一個計時器示例。 當我們有一些重復的任務時使用計時器。 可能是時鐘,倒數,視覺效果或動畫。 `timer.c` ```c #include <cairo.h> #include <gtk/gtk.h> gchar buf[256]; gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cr = gdk_cairo_create(widget->window); cairo_move_to(cr, 30, 30); cairo_set_font_size(cr, 15); cairo_show_text(cr, buf); cairo_destroy(cr); return FALSE; } gboolean time_handler(GtkWidget *widget) { if (widget->window == NULL) return FALSE; GDateTime *now = g_date_time_new_now_local(); gchar *my_time = g_date_time_format(now, "%H:%M:%S"); g_sprintf(buf, "%s", my_time); g_free(my_time); g_date_time_unref(now); gtk_widget_queue_draw(widget); return TRUE; } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *darea; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); darea = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(window), darea); g_signal_connect(darea, "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 200); gtk_window_set_title(GTK_WINDOW(window), "Timer"); g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) window); gtk_widget_show_all(window); time_handler(window); gtk_main(); return 0; } ``` 該示例在窗口上顯示當前本地時間。 也使用 Cairo 2D 庫。 ```c g_signal_connect(darea, "expose-event", G_CALLBACK(on_expose_event), NULL); ``` 我們在`on_expose_event()`回調中繪制時間。 回調連接到`expose-event`信號,該信號在要重繪窗口時發出。 ```c g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) window); ``` 此功能注冊計時器。 `time_handler()`函數會定期重復調用。 就我們而言,每一秒鐘。 將調用計時器函數,直到返回`FALSE`。 ```c time_handler(window); ``` 這將立即調用計時器函數。 否則,將延遲一秒鐘。 ```c cairo_t *cr; cr = gdk_cairo_create(widget->window); cairo_move_to(cr, 30, 30); cairo_set_font_size(cr, 15); cairo_show_text(cr, buf); cairo_destroy(cr); ``` 此代碼在窗口上繪制當前時間。 有關 Cairo 2D 庫的更多信息,請參見 ZetCode 的 [Cairo 圖形教程](http://www.zetcode.com/gfx/cairo/)。 ```c if (widget->window == NULL) return FALSE; ``` 當窗口被破壞時,可能會調用計時器函數。 這行代碼可以防止處理已經銷毀的窗口小部件。 ```c GDateTime *now = g_date_time_new_now_local(); gchar *my_time = g_date_time_format(now, "%H:%M:%S"); g_sprintf(buf, "%s", my_time); ``` 這些行確定當前的本地時間。 時間存儲在全局`buf`變量中。 ```c gtk_widget_queue_draw(widget); ``` `gtk_widget_queue_draw()`函數使窗口區域無效,然后發出`expose-event`信號。 本章是關于 GTK+ 中的事件的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看