如何在GTK中呈现透明背景的文本?

如何在GTK中呈现透明背景的文本?,gtk,cairo,pango,Gtk,Cairo,Pango,我希望在其他gtk小部件(如GtkImage或GtkButton等)上呈现具有透明/半透明背景(或无背景)的文本。 主要目标是在后台通过Gtk小部件(特别是GtkImage)显示文本。 我可以使用pangocairo库在GtkFrame上渲染文本,但我无法摆脱GtkFrame的背景 我见过使GtkWindow透明或半透明的示例,但我希望使用不透明GtkWindow和GtkLayout来放置GTKwidget,然后将GtkImage放置在布局上,并在GtkImage顶部渲染文本,以便为我的文本提供

我希望在其他gtk小部件(如GtkImage或GtkButton等)上呈现具有透明/半透明背景(或无背景)的文本。 主要目标是在后台通过Gtk小部件(特别是GtkImage)显示文本。 我可以使用pangocairo库在GtkFrame上渲染文本,但我无法摆脱GtkFrame的背景

我见过使GtkWindow透明或半透明的示例,但我希望使用不透明GtkWindow和GtkLayout来放置GTKwidget,然后将GtkImage放置在布局上,并在GtkImage顶部渲染文本,以便为我的文本提供一个良好的背景

我也尝试过使用GtkDrawingArea,但后来在创建 pixbuf并在其上呈现文本。感谢您的帮助


注意:我正在使用Compiz来合成窗口。

您可以使用GtkOverlay小部件(至少Gtk+3.2)来完成此操作

GtkOverlay-一个将窗口小部件相互叠加的容器


这里有一个完整的程序可以实现这一点。构建和运行它所需的一切都在GitHub上

#包括
#包括
#包括
#包括
常数gdouble pi=3.14159265359;
#定义橡皮擦宽度150
#定义标签长度20
类型定义结构{
轧棉宽度;
轧棉高度;
gdouble rad_阶;
基特尺度因子;
金特·尤零;
金特x_阶;
gdouble rads;
最后一次;
金特最后;
基特电流;
基特电流;
gint当前的橡皮擦;
cairo_曲面_t*plot_曲面;
cairo_t*图;
开罗橡皮擦;
GtkWidget*小部件;
GtkWidget*标签;
gdouble(*funct)(gdouble);
}图形数据包;
gboolean
do_图形(图形数据包)
{
静态gchar label_str[label_str_LEN];
如果(数据包->雷达>=2.0){
数据包->rads=0.0;
}
gdouble pi_rads=pi*数据包->rads;
snprintf(标签长度、标签长度、%s%f%s、“弧度”、数据包->rads、“圆周率”);
gtk_标签_设置_文本(gtk_标签(数据包->标签),标签_str);
数据包->rads+=数据包->无线电步进;
如果(数据包->当前\u x>数据包->宽度){
数据包->当前_x=0;
}
数据包->最后一个\u x=数据包->当前\u x;
数据包->最后一个数据包=数据包->当前数据包;
数据包->当前\u x+=数据包->x\u步;
packet->current_y=packet->y_zero-(packet->scale_factor*packet->funct(pi_rads));
数据包->当前\u橡皮擦\u x+=数据包->x\u步;
如果(数据包->当前\u橡皮擦\u x>数据包->宽度){
数据包->当前\u橡皮擦\u x=0;
}
gtk_小部件_队列_绘制(数据包->小部件);
返回TRUE;
}
gboolean
draw_回调(GtkWidget*小部件、cairo_t*绘图区、图形数据包)
{
//抹去旧的
cairo\u move\u to(数据包->橡皮擦,数据包->当前橡皮擦,0);
cairo_line_to(数据包->橡皮擦,数据包->当前橡皮擦,数据包->高度);
cairo_笔划(数据包->橡皮擦);
//策划新的
cairo\u移动到(数据包->绘图,数据包->最后一个x,数据包->最后一个y);
cairo\u line\u to(数据包->绘图,数据包->当前x,数据包->当前y);
cairo_笔划(数据包->绘图);
//将源应用于绘图区域
cairo\u set\u source\u surface(绘图区域,数据包->绘图曲面,0.0,0.0);
cairo_油漆(图纸区域);
返回FALSE;
}
静态空隙
销毁(GtkWidget*窗口,gpointer数据)
{
gtk_main_quit();
}
gboolean
删除事件(GtkWidget*窗口、GdkEvent*事件、gpointer数据)
{
返回FALSE;
}
int
主(内部argc,字符**argv)
{
GtkWidget*窗口=NULL;
GtkWidget*overlay=NULL;
GtkWidget*image_background=NULL;
GtkWidget*image=NULL;
GtkWidget*绘图区域=空;
GtkWidget*label=NULL;
图\u数据\u数据包\u t数据包={
.宽度=400,
.高度=200,
.rad_阶跃=0.05,
.比例系数=75,
.y_zero=100,
.x_步长=1,
.rads=0.0,
.last_x=0,
.last_y=0,
.当前_x=0,
.当前_y=0,
.current_橡皮擦_x=橡皮擦宽度,
.plot_surface=NULL,
.plot=NULL,
.橡皮擦=空,
.widget=NULL,
.label=NULL,
.funct=NULL
};
如果(argc>1){
如果(!strcmp(“正弦”,argv[1])){
packet.funct=sin;
}否则如果(!strcmp(“余弦”,argv[1])){
packet.funct=cos;
}否则{
packet.funct=sin;
}
}否则{
packet.funct=sin;
}
gtk_init(&argc,&argv);
//设置开罗的东西
packet.plot\u surface=cairo\u image\u surface\u create(cairo\u格式\u argb32400200);
if(NULL==packet.plot\u surface){
返回退出失败;
}
packet.plot=cairo\u create(packet.plot\u surface);
if(NULL==packet.plot){
返回退出失败;
}
cairo\u set\u source\u rgb(packet.plot,1.0,0.0,0.0);
packet.橡皮擦=cairo\u create(packet.plot\u surface);
if(NULL==数据包橡皮擦){
返回退出失败;
}
cairo_set_source_rgba(packet.橡皮擦,0.0,0.0,0.0);
cairo_set_运算符(packet.橡皮擦、cairo_运算符_CLEAR);
//窗口
窗口=gtk_窗口_新建(gtk_窗口_顶层);
如果(空==窗口){
返回退出失败;
}
packet.widget=窗口;
gtk_小部件_设置_大小_请求(窗口,400200);
g_信号连接(g_对象(窗口),“销毁”,
G_回调(销毁),空);
g_信号连接(g_对象(窗口),“删除事件”,
G_回调(删除_事件),NULL);
//覆盖层
覆盖层=gtk_覆盖层_新();
if(NULL==覆盖){
返回退出失败;
}
//背景图像
image=gtk_image_new_from_文件(“plot_background.png”);
if(NULL==图像){
返回退出失败;
}
image_background=gtk_image_new_from_文件(“pi_background.png”);
如果(空==图像\背景){
返回退出失败;
}
//密谋
图纸面积=gtk图纸面积新();
如果(空==绘图区域){
返回退出失败;
}
gtk
#include <gtk/gtk.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

const gdouble pi = 3.14159265359;

#define ERASER_WIDTH 150
#define LABEL_STR_LEN 20

typedef struct {
    gint width;
    gint height;
    gdouble rad_step;
    gint scale_factor;
    gint y_zero;
    gint x_step;
    gdouble rads;
    gint last_x;
    gint last_y;
    gint current_x;
    gint current_y;
    gint current_eraser_x;
    cairo_surface_t *plot_surface;
    cairo_t *plot;
    cairo_t *eraser;
    GtkWidget *widget;
    GtkWidget *label;
    gdouble (*funct)(gdouble);
} graph_data_packet_t;

gboolean
do_graph (graph_data_packet_t *packet)
{
    static gchar label_str[LABEL_STR_LEN];

    if (packet->rads >= 2.0) {
        packet->rads = 0.0;
    }
    gdouble pi_rads = pi * packet->rads;

    snprintf(label_str, LABEL_STR_LEN, "%s%f%s", "Radians ", packet->rads, "pi");
    gtk_label_set_text(GTK_LABEL(packet->label), label_str);

    packet->rads += packet->rad_step;
    if (packet->current_x > packet->width) {
        packet->current_x = 0;
    }
    packet->last_x = packet->current_x;
    packet->last_y = packet->current_y;
    packet->current_x += packet->x_step;
    packet->current_y = packet->y_zero - (packet->scale_factor * packet->funct (pi_rads));

    packet->current_eraser_x += packet->x_step;
    if (packet->current_eraser_x > packet->width) {
        packet->current_eraser_x = 0;
    }

    gtk_widget_queue_draw(packet->widget);

    return TRUE;
}

gboolean
draw_callback (GtkWidget *widget, cairo_t *drawing_area, graph_data_packet_t *packet)
{
    // Erase Old
    cairo_move_to (packet->eraser, packet->current_eraser_x, 0);
    cairo_line_to (packet->eraser, packet->current_eraser_x, packet->height);
    cairo_stroke(packet->eraser);

    // Plot New
    cairo_move_to (packet->plot, packet->last_x, packet->last_y);
    cairo_line_to (packet->plot, packet->current_x, packet->current_y);
    cairo_stroke (packet->plot);

    // Apply source to drawing area
    cairo_set_source_surface (drawing_area, packet->plot_surface, 0.0, 0.0);

    cairo_paint(drawing_area);

    return FALSE;
}

static void 
destroy (GtkWidget *window, gpointer data)
{
    gtk_main_quit();
}

gboolean 
delete_event (GtkWidget *window, GdkEvent *event, gpointer data)
{
    return FALSE;
}

int 
main(int argc, char **argv)
{
    GtkWidget *window = NULL; 
    GtkWidget *overlay = NULL;
    GtkWidget *image_background = NULL;
    GtkWidget *image = NULL;
    GtkWidget *drawing_area = NULL;
    GtkWidget *label =  NULL;

    graph_data_packet_t packet = {
        .width = 400,
        .height = 200,
        .rad_step = 0.05,
        .scale_factor = 75,
        .y_zero = 100,
        .x_step = 1,
        .rads = 0.0,
        .last_x = 0,
        .last_y = 0, 
        .current_x = 0,
        .current_y = 0,
        .current_eraser_x = ERASER_WIDTH,
        .plot_surface = NULL,
        .plot = NULL,
        .eraser = NULL,
        .widget = NULL,
        .label = NULL,
        .funct = NULL
    };

    if (argc > 1) {
        if (!strcmp("sine", argv[1])) {
            packet.funct = sin;
        } else if (!strcmp("cosine", argv[1])) {
            packet.funct = cos;
        } else {
            packet.funct = sin;
        }
    } else {
        packet.funct = sin;
    }

    gtk_init(&argc, &argv);

    // Setup Cairo stuff
    packet.plot_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 200);
    if (NULL == packet.plot_surface) {
        return EXIT_FAILURE;
    }

    packet.plot = cairo_create (packet.plot_surface);
    if (NULL == packet.plot) {
        return EXIT_FAILURE;
    }
    cairo_set_source_rgb (packet.plot, 1.0, 0.0, 0.0);

    packet.eraser = cairo_create (packet.plot_surface);
    if (NULL == packet.eraser) {
        return EXIT_FAILURE;
    }
    cairo_set_source_rgba (packet.eraser, 0.0, 0.0, 0.0, 0.0);
    cairo_set_operator(packet.eraser, CAIRO_OPERATOR_CLEAR);

    // Window
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    if(NULL == window) {
        return EXIT_FAILURE;
    }
    packet.widget = window;
    gtk_widget_set_size_request (window, 400, 200);

    g_signal_connect (G_OBJECT (window), "destroy",
                G_CALLBACK (destroy), NULL);

    g_signal_connect (G_OBJECT (window), "delete_event",
                G_CALLBACK (delete_event), NULL);

    // Overlay
    overlay = gtk_overlay_new ();
    if (NULL == overlay) {
        return EXIT_FAILURE;
    }

    // Background Image
    image = gtk_image_new_from_file ("plot_background.png");
    if (NULL == image) {
        return EXIT_FAILURE;
    }

    image_background = gtk_image_new_from_file ("pi_background.png");
    if (NULL == image_background) {
        return EXIT_FAILURE;
    }

    // Plot
    drawing_area = gtk_drawing_area_new ();
    if (NULL == drawing_area) {
        return EXIT_FAILURE;
    }
    gtk_widget_set_size_request (drawing_area, 400, 200);
    g_signal_connect (G_OBJECT (drawing_area), "draw",
        G_CALLBACK (draw_callback), &packet);

    // Label
    label = gtk_label_new ("Radians: 0.0 pi");
    if (NULL == label) {
        return EXIT_FAILURE;
    }
    packet.label = label;
    gtk_widget_set_halign (label, GTK_ALIGN_START);
    gtk_widget_set_valign (label, GTK_ALIGN_END);

    // Put it all together
    gtk_container_add(GTK_CONTAINER(overlay), image_background);
    gtk_overlay_add_overlay (GTK_OVERLAY (overlay), image);
    gtk_overlay_add_overlay (GTK_OVERLAY (overlay), drawing_area);
    gtk_overlay_add_overlay (GTK_OVERLAY (overlay), label);
    gtk_container_add (GTK_CONTAINER (window), overlay);

    gtk_widget_show_all (window);

    g_timeout_add(100, (GSourceFunc) do_graph, &packet);

    gtk_main();

    return EXIT_SUCCESS;
}