如何在Gtk3绘图区域用Cairo实现棋盘格背景的透明度渐变
在Gtk3中为带透明度的渐变添加棋盘格背景
我正在Gtk3中开发颜色选择器组件,希望通过滑块/数值按钮调整颜色alpha值时,在绘图区域(Drawing Area)展示当前透明度状态。目前已能绘制带透明度的渐变,但透明度效果不够直观清晰,因此需要为渐变添加棋盘格样式背景以增强辨识度。
原代码
#include <cairo.h> #include <gtk/gtk.h> void draw_gradient(cairo_t *); static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) { draw_gradient(cr); return FALSE; } void draw_gradient(cairo_t *cr) { int width = 300; int height = 100; cairo_pattern_t *gradient; gradient =cairo_pattern_create_linear(0.0, 0.0, width, 0.0); cairo_pattern_add_color_stop_rgba (gradient, 0, 75,0,130, 0.3); //Purple with alpha cairo_pattern_add_color_stop_rgba (gradient, 1, 75,0,130, 1); //Purple cairo_set_source (cr, gradient); cairo_paint (cr); cairo_pattern_destroy (gradient); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *darea; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); darea = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER (window), darea); g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL); g_signal_connect(G_OBJECT(window), "destroy",G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 100); gtk_window_set_title(GTK_WINDOW(window), "Linear gradients"); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0; }
解决方案
要实现棋盘格背景,核心思路是先绘制棋盘格,再绘制带透明度的渐变,利用渐变的透明特性让棋盘格透出来,增强透明度的直观性。以下是修改后的完整代码:
#include <cairo.h> #include <gtk/gtk.h> void draw_checkerboard(cairo_t *cr, int width, int height); void draw_gradient(cairo_t *cr, int width, int height); static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) { // 获取控件实际宽高,适配窗口大小变化 int width = gtk_widget_get_allocated_width(widget); int height = gtk_widget_get_allocated_height(widget); // 先画棋盘格背景 draw_checkerboard(cr, width, height); // 再画带透明度的渐变 draw_gradient(cr, width, height); return FALSE; } void draw_checkerboard(cairo_t *cr, int width, int height) { const int tile_size = 10; // 棋盘格方块大小,可按需调整 // 遍历绘制所有棋盘格方块 for (int y = 0; y < height; y += tile_size) { for (int x = 0; x < width; x += tile_size) { // 奇偶行交错填充颜色 if ((x/tile_size + y/tile_size) % 2 == 0) { cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); // 浅灰色 } else { cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); // 白色 } cairo_rectangle(cr, x, y, tile_size, tile_size); cairo_fill(cr); } } } void draw_gradient(cairo_t *cr, int width, int height) { cairo_pattern_t *gradient; gradient = cairo_pattern_create_linear(0.0, 0.0, width, 0.0); // 注意:cairo的RGB值范围是0-1,需将原0-255的颜色值转换为浮点数 cairo_pattern_add_color_stop_rgba(gradient, 0, 75.0/255.0, 0.0, 130.0/255.0, 0.3); // 带透明度的紫色 cairo_pattern_add_color_stop_rgba(gradient, 1, 75.0/255.0, 0.0, 130.0/255.0, 1.0); // 不透明紫色 cairo_set_source(cr, gradient); cairo_paint(cr); cairo_pattern_destroy(gradient); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *darea; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); darea = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(window), darea); g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 100); gtk_window_set_title(GTK_WINDOW(window), "Linear gradients with checkerboard"); gtk_widget_show_all(window); gtk_main(); return 0; }
关键修改说明
- 新增
draw_checkerboard函数:通过循环绘制交错的浅灰/白色小方块,实现棋盘格效果,方块大小可通过tile_size参数调整 - 调整绘制顺序:先绘制棋盘格背景,再绘制渐变,确保渐变的透明度能让背景透出
- 修正颜色值错误:原代码中直接使用0-255的RGB值,而cairo的
cairo_pattern_add_color_stop_rgba要求RGB值为0-1的浮点数,因此将颜色值转换为75.0/255.0这类比例值 - 适配窗口大小:改用
gtk_widget_get_allocated_width/height获取控件实际尺寸,代替固定值,支持窗口缩放
内容的提问来源于stack exchange,提问作者dibyendu
相关产品推荐
相关产品推荐

