如果使用 Glade 进行绘图,GtkDrawingArea 不会更新

Posted

技术标签:

【中文标题】如果使用 Glade 进行绘图,GtkDrawingArea 不会更新【英文标题】:GtkDrawingArea won't update when drawing happens if Glade is used 【发布时间】:2018-11-24 15:40:53 【问题描述】:

我创建了一个非常简单的 GTK3 C 应用程序,其中包含按钮和 GtkDrawingArea(与 GtkPaned 一起保存)。当按下按钮时,它应该立即绘制一个矩形,但是,它不会发生。它只发生在 GtkPaned 分割部分上的鼠标啸叫时(参见 .gif)。如果不使用Glade,那么这个问题就不存在了。

如何解决这个问题?

gif

C 代码:

#include <gtk/gtk.h>

//==============================================================Global=variables========================================================================
static cairo_surface_t *surface = NULL;
GtkWidget *DrawArea;

//==============================================================Functions===============================================================================


void clear_surface (void)

    cairo_t *cr;

    cr = cairo_create (surface);

    cairo_set_source_rgb (cr, 0, 1, 1);
    cairo_paint (cr);

    cairo_destroy (cr);


//Create a new surface of the appropriate size to store our scribbles
gboolean configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, gpointer data)

    if (surface)
    
        cairo_surface_destroy (surface);
    


    surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), CAIRO_CONTENT_COLOR, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget));

    /* Initialize the surface to white */
    clear_surface ();

    /* We've handled the configure event, no need for further processing. */
    return TRUE;


/* Redraw the screen from the surface. Note that the ::draw
 * signal receives a ready-to-be-used cairo_t that is already
 * clipped to only draw the exposed areas of the widget
 */
gboolean draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data)

    cairo_set_source_surface (cr, surface, 0, 0);
    cairo_paint (cr);

    return FALSE;


//Draw a rectangle on the surface at the given position
void draw_brush (GtkWidget *widget, double x, double y)

    cairo_t *cr;

    /* Paint to the surface, where we store our state */
    cr = cairo_create (surface);

    cairo_rectangle (cr, x - 3, y - 3, 6, 6);
    cairo_fill (cr);

    cairo_destroy (cr);

    //Now invalidate the affected region of the drawing area.
    gtk_widget_queue_draw_area (widget, x - 3, y - 3, 6, 6);


void draw_rectangle (GtkWidget *widget, float posX, float posY, float length, float height, float colorR, float colorG, float colorB)

    cairo_t *cr;

    /* Paint to the surface, where we store our state */
    cr = cairo_create (surface);
    cairo_set_source_rgb (cr, colorR, colorG, colorB);

    cairo_rectangle (cr, posX, posY, length, height);
    cairo_fill (cr);

    cairo_destroy (cr);

    //Now invalidate the affected region of the drawing area.
    gtk_widget_queue_draw_area (widget, posX, posY, length, height);



//==================================Button=stuff==========================
void Button_clicked(GtkWidget* widget, gpointer data)

    g_print("Clicked\n");
    draw_brush (DrawArea, 10, 10);
    //gtk_widget_queue_draw (window_main);






int main(int argc, char *argv[])



    GtkBuilder      *builder; 
    GtkWidget       *window;

    gtk_init(&argc, &argv);

    DrawArea = gtk_drawing_area_new ();
    builder = gtk_builder_new();
    gtk_builder_add_from_file (builder, "Resources/GUI_design.glade", NULL);

    window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
    gtk_builder_connect_signals(builder, NULL);

    g_object_unref(builder);

    gtk_widget_show(window);                
    gtk_main();

    return 0;





// called when window is closed
void on_window_main_destroy()

    gtk_main_quit();

空地代码:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window_main">
    <property name="can_focus">False</property>
    <property name="default_width">500</property>
    <property name="default_height">500</property>
    <property name="icon">icon.png</property>
    <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkPaned" id="paned">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="orientation">vertical</property>
        <property name="position">300</property>
        <property name="position_set">True</property>
        <child>
          <object class="GtkDrawingArea" id="DrawArea">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <signal name="configure-event" handler="configure_event_cb" swapped="no"/>
            <signal name="draw" handler="draw_cb" swapped="no"/>
          </object>
          <packing>
            <property name="resize">False</property>
            <property name="shrink">False</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="Button">
            <property name="label" translatable="yes">button</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="clicked" handler="Button_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="resize">True</property>
            <property name="shrink">True</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

【问题讨论】:

【参考方案1】:

我终于找到并解决了问题!!!!

int main 现在看起来像这样(删除了 1 行,添加了 1 行)

int main(int argc, char *argv[])



    GtkBuilder      *builder; 
    GtkWidget       *window;

    gtk_init(&argc, &argv);

    //DrawArea = gtk_drawing_area_new ();
    builder = gtk_builder_new();
    gtk_builder_add_from_file (builder, "Resources/GUI_design.glade", NULL);

    window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
    gtk_builder_connect_signals(builder, NULL);

    DrawArea = GTK_WIDGET(gtk_builder_get_object(builder, "DrawArea")); //This is very important

    g_object_unref(builder);

    gtk_widget_show(window);                
    gtk_main();

    return 0;

描述导致这个问题的原因:Glade 和我创建了 2 个单独的指针,我只用我的指针做事,而不是 Glade 的。那条重要的线将这两个指针连接在一起,现在它可以工作了。巨呼!

这个教程帮助我解决了这个问题:https://prognotes.net/2016/03/gtk-3-c-code-hello-world-tutorial-using-glade-3/

【讨论】:

以上是关于如果使用 Glade 进行绘图,GtkDrawingArea 不会更新的主要内容,如果未能解决你的问题,请参考以下文章

Gtk+/Glade编程--简介

gtk 绘图区不重绘内容

在对话窗口中使用 Glade,如何为按钮添加响应

FreeBASIC 和 GTK Glade 的 glade Button 是如何工作的?

gtkmm & glade - 多个窗口不工作

使用 Glade 时在 GTK-Notebook 中添加选项卡