В настоящее время я пытаюсь изучить GTK + 3 / cairo с помощью C. Я написал небольшое приложение, которое рисует циферблат и стрелку в области рисования gtk с помощью cairo.
Пока это работает хорошо, я попытался создать несколько областей рисования (несколько датчиков), у которых все имеют одну и ту же функцию обратного вызова для события рисования, это также хорошо работает со статическими значениями.
Теперь мой вопрос, я хотел бы иметь возможность рисовать несколько датчиков, каждый со своими значениями. Но как мне узнать в моей функции обратного вызова, какой датчик (область рисования) испустил сигнал рисования? Я предполагаю, что это также включает в себя то, как я «создаю и сохраняю» данные для датчиков, чтобы их свойства можно было получить из обратного вызова отрисовки.
Мне, вероятно, следует создать структуру, содержащую данные для датчика, и создать несколько из них. Это то, что я понял, просмотрев различные проекты, использующие 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
}
Будем очень признательны за любые советы о том, как подойти к чему-то подобному.
1 ответ
GtkDrawingArea
, излучающий сигнал, - это просто widget
, который вы получаете в обратном вызове. При необходимости просто приведите его к соответствующему типу.
Но внимательно посмотрите документацию по сигналу draw
:
Сигнал "ничья"
gboolean user_function (GtkWidget *widget,
CairoContext *cr,
gpointer user_data) : Run Last
В вашей функции draw_event
отсутствует последний параметр, gpointer user_data
.
И это использование последнего параметра NULL
вызова g_signal_connect()
. Таким образом, вы можете поместить здесь указатель на структуру со всеми необходимыми данными.
Или вы можете использовать функцию g_object_set_data()
, чтобы прикрепить указатель к виджету, но я бы не рекомендовал это для такого простого приложения.
Если у вас фиксированное количество датчиков, все в порядке: просто создайте такое же количество структур, но если ваше количество датчиков динамическое, вы должны создать структуры в голове, поэтому возникает новая проблема: когда вы освобождаете данные? Ответ находится в g_signal_connect_data()
: эта функция получает дополнительный обратный вызов, который вызывается, когда структура больше не нужна.
Что-то вроде следующего:
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);
}
Похожие вопросы
Связанные вопросы
Новые вопросы
c
C - это язык программирования общего назначения, используемый для системного программирования (ОС и встраиваемых), библиотек, игр и кроссплатформенности. Этот тег следует использовать с общими вопросами, касающимися языка C, как это определено в стандарте ISO 9899 (последняя версия 9899: 2018, если не указано иное, а также для запросов, специфичных для версии, с c89, c99, c11 и т. Д.). C отличается от C ++ и не должен сочетаться с тэгом C ++ без разумной причины.