使用Gtk 3与Cairo实现随机位置图片旋转遇阻求助
Hey there! I get that you're trying to make an image rotate at random positions using GTK but hitting snags with your code. Let's break down what's likely missing and get this working properly.
First, let's fill in the gaps in your original code snippet—you probably didn't set up a timer to trigger rotations, handle random position generation correctly, or properly apply Cairo transformations. Here's a complete, working version of the code with clear explanations:
#include <gtk/gtk.h> #include <cairo.h> #include <stdlib.h> #include <time.h> GtkWidget *window; GtkWidget *img; gdouble rotation_angle = 0.0; gint random_x = 0; gint random_y = 0; static void rotate_cb() { // Increment rotation angle (adjust the value to change rotation speed) rotation_angle += 5.0; if (rotation_angle >= 360.0) { rotation_angle = 0.0; } // Generate new random position that keeps the entire image inside the window gint win_w = gtk_widget_get_allocated_width(window); gint win_h = gtk_widget_get_allocated_height(window); gint img_w = gtk_widget_get_allocated_width(img); gint img_h = gtk_widget_get_allocated_height(img); random_x = rand() % (win_w - img_w); random_y = rand() % (win_h - img_h); // Tell GTK to redraw the window with updated values gtk_widget_queue_draw(window); } static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) { if (!img) return FALSE; gint img_w = gtk_widget_get_allocated_width(img); gint img_h = gtk_widget_get_allocated_height(img); // Save the current Cairo state to avoid messing up other draws cairo_save(cr); // Move the drawing origin to the center of our random position cairo_translate(cr, random_x + img_w/2, random_y + img_h/2); // Rotate the context (convert degrees to radians since Cairo uses radians) cairo_rotate(cr, rotation_angle * G_PI / 180.0); // Shift back so the image rotates around its own center, not the origin cairo_translate(cr, -img_w/2, -img_h/2); // Draw the image using GTK's icon renderer gtk_render_icon(GTK_WIDGET(widget), GTK_IMAGE(img)->storage, gtk_widget_get_state_flags(widget), img_w, img_h, NULL, cr); // Restore the original Cairo context state cairo_restore(cr); return TRUE; } int main(int argc, char *argv[]) { gtk_init(&argc, &argv); srand(time(NULL)); // Seed the random number generator window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(window), 600, 400); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); // Load your image (replace "your_image.png" with your actual image path) img = gtk_image_new_from_file("your_image.png"); if (!img) { g_print("Failed to load image!\n"); return 1; } // Use a drawing area to handle custom Cairo rendering GtkWidget *drawing_area = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(window), drawing_area); g_signal_connect(drawing_area, "draw", G_CALLBACK(on_draw_event), img); // Set up a timer to update rotation/position every 50ms (adjust for speed) g_timeout_add(50, (GSourceFunc)rotate_cb, NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
Key Fixes & Explanations:
- Random Position Logic: We calculate positions that ensure the whole image stays inside the window by subtracting the image's dimensions from the window's size before generating random values.
- Smooth Rotation: Cairo uses radians, so we convert our degree-based angle. The double translation trick makes the image rotate around its own center instead of the window's top-left corner.
- Timer Trigger:
g_timeout_addcalls our update function every 50ms to refresh the angle and position, then triggers a redraw to show the changes. - Custom Rendering: Using a
GtkDrawingAreagives us full control over how the image is drawn, instead of relying on the default image widget behavior.
Compilation Note:
To compile this code (make sure you have GTK3 installed), run:
gcc -o rotating_image rotating_image.c `pkg-config --cflags --libs gtk+-3.0`
Just replace "your_image.png" with the path to your actual image, and you should see it rotating at random positions smoothly!
内容的提问来源于stack exchange,提问作者Andrew Shao

