如何在GTK中使用透明背景渲染其他小部件的文本?

时间:2011-03-14 09:10:55

标签: gtk cairo pango

我希望使用透明/半透明背景(或没有背景)渲染文本,而不是像GtkImage或GtkButton等其他gtk小部件。 主要目标是在后台将文本显示在Gtk Widgets(尤其是GtkImage)上。 我可以使用pangocairo库在GtkFrame上渲染文本,但我无法摆脱GtkFrame的背景。

我见过让GtkWindow变得透明或半透明的例子,但是我想用GtkLayout设置不透明的GtkWindout来放置GtkWidgets,然后将GtkImage放在布局上并在GtkImage上渲染Text,这样它就为我的文本提供了一个很好的背景

我也尝试过使用GtkDrawingArea,但后来我在创建cairo上下文时迷路了 pixbuf和渲染文本。任何帮助表示赞赏。

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

2 个答案:

答案 0 :(得分:1)

你可以使用GtkOverlay小部件(至少Gtk + 3.2)

  

GtkOverlay - 一个将小部件叠加在一起的容器

http://developer.gnome.org/gtk3/stable/GtkOverlay.html

答案 1 :(得分:0)

这是执行此操作的整个程序。构建和运行它所需的一切都在GitHub上。

https://github.com/sweckhoff/GTK-Cairo-Sinusoids/blob/master/gtk_cairo_sinusoid_plot.c

#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;
}