How can I render Text with transparent background over other widgets in GTK?

前端 未结 2 674
南笙
南笙 2021-01-07 01:37

I wish to render text with transparent/translucent background (or no background) over other gtk widgets like GtkImage or GtkButton etc. Primary goal is to have text display

相关标签:
2条回答
  • 2021-01-07 01:56

    Here is an entire program that does this. Everything that you need to build and run it is at 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;
    }
    
    0 讨论(0)
  • 2021-01-07 02:08

    You can do it with GtkOverlay widget (Gtk+ 3.2 at least)

    GtkOverlay — A container which overlays widgets on top of each other

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

    0 讨论(0)
提交回复
热议问题