2

私は現在、C を使用して GTK+3/cairo を学習しようとしています。cairo を使用して gtk 描画領域にゲージ面と針を描画する小さなアプリケーションを作成しました。

これはこれまでのところうまく機能します。描画イベントに対して同じコールバック関数を持つ複数の描画領域 (複数のゲージ) を作成しようとしましたが、これは静的な値でもうまく機能します。

私の質問ですが、それぞれ独自の値を持つ複数のゲージを描画できるようにしたいと考えています。しかし、コールバック関数でどのゲージ (描画領域) が描画信号を発したかを知るにはどうすればよいでしょうか? これには、ゲージのデータを「作成して保存」する方法も含まれていると思います。これにより、描画コールバック内からプロパティを取得できます。

おそらく、ゲージのデータを保持する構造体を作成し、それらを複数作成する必要があります。これは、GTK を使用するさまざまなプロジェクトを調べて集めたものですが、複雑すぎて、その仕組みを完全に理解することはできません。

これは、描画領域を作成する方法です:

gaugearea1 = gtk_drawing_area_new();
gtk_box_pack_start(GTK_BOX(hbox), gaugearea1, FALSE, FALSE, 5);
gtk_widget_set_size_request(gaugearea1, 300, 300);
gtk_widget_realize(gaugearea1);
g_signal_connect(gaugearea1, "draw", G_CALLBACK(draw_event), NULL);

コールバック関数はこのように書かれており、かなり標準的です。

static gboolean draw_event(GtkWidget *widget, cairo_t *cr)
{
    GdkWindow *win;
    win = gtk_widget_get_window(widget);

    // Draw all arcs/lines using cr
}

このようなものにアプローチする方法についてのヒントは大歓迎です。

4

1 に答える 1

5

The GtkDrawingArea that emits the signal is simply the widget you receive in your callback. Just cast it to the appropriate type, if needed.

But look carefully at the docs from the draw signal:

The "draw" signal

gboolean     user_function                  (GtkWidget    *widget,
                                            CairoContext *cr,
                                            gpointer      user_data) : Run Last

Your draw_event function is missing the last parameter, the gpointer user_data.

And that's the use of the last NULL parameter of the call to g_signal_connect(). So you can put here a pointer to a struct with all the data you need.

Or you can use the g_object_set_data() function to attach a pointer to the widget, but I wouldn't recommend that for such a simple application.

If you have a fixed number of gauges, all is well: just create the same number of structs, but if your number of gauges is dynamic, you have to create the structs in the head, so a new problem arises: when do you free the data? The answer is in g_signal_connect_data(): this function receives an additional callback that is called when the struct is no longer needed.

Something like the follwoing:

struct GaugeData
{
    /* your data here */
};
static void gauge_data_free(gpointer ptr, GClosure *clo)
{
    struct GaugeData *data = ptr;
    /* free extra resources, if needed */
    g_free(data);
}
static gboolean draw_event(GtkWidget *widget, cairo_t *cr, gpointer ptr)
{
    struct GaugeData *data = ptr;

    // Draw all arcs/lines using cr and data
}

void CreateOneGauge()
{
    gaugearea1 = gtk_drawing_area_new();
    struct GaugeData *data = g_new(GaugeData, 1);
    /* init the data */

    /* ... */
    g_signal_connect_data(gaugearea1, "draw", G_CALLBACK(draw_event), 
                data, gauge_data_free, 0);
}
于 2012-06-29T22:09:46.293 に答える