Нарисуйте GtkImage с помощью Cairo

Я попробовал решения, предложенные в аналогичных заметках (Как создать gtkimage из контекста cairo, Как создать gtkimage с поверхности cairo) но они не работали для меня.

В моей реальной программе фоновая задача вычисляет последовательные состояния физической симуляции, и каждая итерация должна добавлять точку на диаграмму. Если бы я использовал GtkDrawingArea, мне пришлось бы хранить все эти точки (не зная заранее, сколько их будет) и рисовать все при каждом сигнале отрисовки. Итак, моя идея состоит в том, чтобы использовать GtkImage, где я должен рисовать только одну новую точку на каждой итерации.

В следующей тестовой программе что-то должно быть нарисовано по нажатию кнопки, но ничего не происходит. Может кто-нибудь указать ошибку?

/* Test for drawing an image with Cairo. To be compiled with:
   gcc -Wall -g gtk_img.c -o gtk_img `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0`
*/

#include <stdio.h>
#include <gdk/gdk.h>
#include <cairo.h>
#include <gtk/gtk.h>

#define BORDER      6
#define WIDTH       100
#define HEIGHT      100

cairo_surface_t *surf;
cairo_t         *cr;
cairo_pattern_t *back, *fore;


/*  Event Handlers
    ==============
*/

static gboolean Delete_Event
       (GtkWidget *widget, GdkEvent *event, gpointer data)
{
    return FALSE;
}

static void Destroy (GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();
}

static void Draw_Now (GtkWidget *widget, gpointer data)
{
    printf("Draw button clicked\n");
    cr = cairo_create (surf);
    cairo_set_source (cr, back);
    cairo_paint (cr);
    cairo_set_source (cr, fore);
    cairo_move_to (cr, 0.0, 0.0);
    cairo_line_to (cr, 20.0, 20.0);
    cairo_stroke (cr);
}


/*  Main Program
    ============
*/

int main (int argc, char *argv[])
{
    GtkWidget   *window;
    GtkImage    *img;
    GtkBox      *vbox;
    GtkButton   *button;
    
    // init GTK, make window with vbox
    gtk_init (&argc, &argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",
              G_CALLBACK (Delete_Event), NULL);
    g_signal_connect (G_OBJECT (window), "destroy",
              G_CALLBACK (Destroy), NULL);
    gtk_container_set_border_width (GTK_CONTAINER (window), BORDER);
    vbox = (GtkBox*)gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
    gtk_container_add (GTK_CONTAINER(window), (GtkWidget*)vbox);

    // make image
    surf = cairo_image_surface_create (CAIRO_FORMAT_RGB24, WIDTH, HEIGHT);
    img = (GtkImage*)gtk_image_new_from_surface (surf);
    gtk_image_clear (img);
    back = cairo_pattern_create_rgb (0.9, 0.9, 0.9);
    fore = cairo_pattern_create_rgb (0.1, 0.1, 0.1);
    gtk_box_pack_start (vbox, (GtkWidget*)img, TRUE, TRUE, FALSE);

    // button
    button = (GtkButton*)gtk_button_new_with_label ("Draw");
    g_signal_connect
       (G_OBJECT (button), "clicked", G_CALLBACK (Draw_Now), NULL);
    gtk_box_pack_start (vbox, (GtkWidget*)button, FALSE, FALSE, FALSE);

    // start GTK
    gtk_widget_show_all (window);
    gtk_main ();
    
    return 0;
}

Разве вам не нужно также сообщать GtkImage, что что-то изменилось/чтобы вызвать перерисовку? Однако я действительно не знаю, как это сделать. Случайной идеей было бы вызвать gtk_image_clear(), а затем gtk_image_set_from_surface(). Надеюсь, есть лучшие способы...

Uli Schlachter 13.05.2022 21:41

Привет, Ули, твое 2. предложение - решение. Пожалуйста, сделайте публикацию из вашего комментария, тогда я смогу прокомментировать его более подробно, отметить тему как решенную, и вы можете получить значок.

hreba 14.05.2022 11:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
25
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы рисуете на поверхность cairo, но «ничего не знает», поэтому перерисовка не запускается.

Случайной идеей для запуска перерисовки будет вызов gtk_image_clear(), а затем gtk_image_set_from_surface(). Бьюсь об заклад, есть лучшие способы сделать это, но я действительно не знаю GTK, извините.

gtk_image_clear() это как раз то, чего я не хочу делать, потому что (в моем понимании) это сотрет то, что было нарисовано до сих пор. gtk_image_set_from_surface() однако это решение. Я расширил свою тестовую программу счетчиком, чтобы при каждом нажатии кнопки рисовался новый отрезок линии. И фактически каждый новый сегмент появляется в дополнение к тому, что было раньше. Большое спасибо за твою помощь!
hreba 15.05.2022 14:49

Другие вопросы по теме