You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:53:12