6

我想让背景透明,只有小部件可见。

这是我的代码:

#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
    gtk_init (&argc, &argv);
    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    // Title
    gtk_window_set_title(GTK_WINDOW (window), "Transparency");
    //gtk_window_set_opacity(GTK_WINDOW(window), 0.5);

    // CSS
    GtkCssProvider *provider = gtk_css_provider_new();
    GdkDisplay *display = gdk_display_get_default();
    GdkScreen *screen = gdk_display_get_default_screen(display);
    gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
    gtk_css_provider_load_from_data(GTK_CSS_PROVIDER (provider),
                                    "GtkWindow {\n"
                                    "   background-color: rgba(0,0,0,0);\n"
                                    "}\n",
                                     -1, NULL);
    g_object_unref (provider);

    // Window
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_resize(GTK_WINDOW(window), 400, 300);
    gtk_widget_show_all(window);

    gtk_main();
    return 0;
}

我用gtk3。当程序执行时,它只是显示黑色。CSS(或 rgba)功能不起作用。我尝试使用 gtk_window_set_opacity(),但它也只显示黑色。如何修复我的代码?

4

2 回答 2

16

我按照评论建议的链接进行操作,但不幸的是它是为 Gtk 2 编写的。我已经为 Gtk 3 重新设计了它。(我使用的是 Gtk 3.8,但据我所知,它没有使用 Gtk 3.10 中已弃用的任何内容)。该程序会生成一个绿色的半透明正方形,其中包含按钮。当然,您可以通过将函数的最后一个参数更改为cairo_set_source_rgba0 来使正方形完全透明。

注意:我使用以下命令编译了它(假设您调用了文件transparent.c):

gcc -o transparent transparent.c `pkg-config gtk+-3.0 --libs --cflags`

这是代码:

C 版本

/**
 * Original code by: Mike - http://plan99.net/~mike/blog (now a dead link--unable to find it).
 * Modified by karlphillip for StackExchange:
 *     (https://stackoverflow.com/questions/3908565/how-to-make-gtk-window-background-transparent)
 * Re-worked for Gtk 3 by Louis Melahn, L.C., January 30, 2014.
 */

#include <gtk/gtk.h>

static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer user_data);
static gboolean draw(GtkWidget *widget, cairo_t *new_cr, gpointer user_data);
static void clicked(GtkWindow *win, GdkEventButton *event, gpointer user_data);

int main(int argc, char **argv)
{
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
    gtk_window_set_title(GTK_WINDOW(window), "Alpha Demo");
    g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);

    gtk_widget_set_app_paintable(window, TRUE);

    g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(draw), NULL);
    g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL);

    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
    gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
    g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(clicked), NULL);

    GtkWidget* fixed_container = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window), fixed_container);
    GtkWidget* button = gtk_button_new_with_label("button1");
    gtk_widget_set_size_request(button, 100, 100);
    gtk_container_add(GTK_CONTAINER(fixed_container), button);

    screen_changed(window, NULL, NULL);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

gboolean supports_alpha = FALSE;
static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer userdata)
{
    /* To check if the display supports alpha channels, get the visual */
    GdkScreen *screen = gtk_widget_get_screen(widget);
    GdkVisual *visual = gdk_screen_get_rgba_visual(screen);

    if (!visual)
    {
        printf("Your screen does not support alpha channels!\n");
        visual = gdk_screen_get_system_visual(screen);
        supports_alpha = FALSE;
    }
    else
    {
        printf("Your screen supports alpha channels!\n");
        supports_alpha = TRUE;
    }

    gtk_widget_set_visual(widget, visual);
}

static gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer userdata)
{
    cairo_save (cr);

    if (supports_alpha)
    {
        cairo_set_source_rgba (cr, 0.5, 1.0, 0.50, 0.5); /* transparent */
    }
    else
    {
        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* opaque white */
    }

    /* draw the background */
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
    cairo_paint (cr);

    cairo_restore (cr);

    return FALSE;
}

static void clicked(GtkWindow *win, GdkEventButton *event, gpointer user_data)
{
    /* toggle window manager frames */
    gtk_window_set_decorated(win, !gtk_window_get_decorated(win));
} 

C++ 版本

我包含了一个非常相似的程序,这次是用gtkmmC++ 编写的。可以使用以下命令编译:

g++ -otransparent main.cpp transparent.cpp `pkg-config gtkmm-3.0 --cflags --libs` -std=c++11

请注意,我使用了新 C++-11 标准中的一些特性,因此您需要一个支持它们的编译器。(如果没有,只需要在auto关键字出现时将其替换为适当的类型,这可以从函数的定义中弄清楚。)共有三个文件:main.cpptransparent.htransparent.cpp.

主文件

/** * main.cpp * * 代码改编自 Mike 的 'alphademo.c' * (http://plan99.net/~mike/blog--现在是死链接--无法找到它。) * 已修改由 karlphillip 为 StackExchange 提供:* (https://stackoverflow.com/questions/3908565/how-to-make-gtk-window-background-transparent) * 由 Louis Melahn 于 2014 年 1 月 31 日为 Gtkmm 3.0 重新工作。 */ #include "transparent.h" #include int main (int argc, char *argv[]) { Glib::RefPtr app = Gtk::Application::create(argc, argv, "org.gtkmm.example.transparent "); 透明透明;//显示窗口并在关闭时返回。返回应用程序->运行(透明);}

透明的.h

/**
 * transparent.h
 *
 * Code adapted from 'alphademo.c' by Mike
 * (http://plan99.net/~mike/blog--now a dead link--unable to find it.)
 * as modified by karlphillip for StackExchange:
 *     (https://stackoverflow.com/questions/3908565/how-to-make-gtk-window-background-transparent)
 * Re-worked for Gtkmm 3.0 by Louis Melahn, L.C. January 31, 2014.
 */

#ifndef TRANSPARENT_H_
#define TRANSPARENT_H_

#include <iostream>
#include <gtk/gtk.h>
#include <gtkmm/window.h>
#include <gtkmm/button.h>
#include <gtkmm/alignment.h>

class Transparent : public Gtk::Window
{

private:
    std::string _buttonLabel;

public:
    Transparent();
    void set_visual(Glib::RefPtr<Gdk::Visual> visual);
    virtual ~Transparent();

protected:
    // Signal handlers:
    // Note that on_draw is actually overriding a virtual function
    // from the Gtk::Window class. I set it as virtual here in case
    // someone wants to override it again in a derived class.
    void on_button_clicked();
    virtual bool on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr);
    void on_screen_changed(const Glib::RefPtr<Gdk::Screen>& previous_screen);
    bool on_window_clicked(GdkEventButton* event);

    // Member widgets:
    Gtk::Alignment _alignment;
    Gtk::Button _button;

    bool _SUPPORTS_ALPHA = false;

};

#endif /* TRANSPARENT_H_ */

透明的.cpp

/**
 * transparent.cpp
 *
 * Code adapted from 'alphademo.c' by Mike
 * (http://plan99.net/~mike/blog--now a dead link--unable to find it.)
 * as modified by karlphillip for StackExchange:
 *     (https://stackoverflow.com/questions/3908565/how-to-make-gtk-window-background-transparent)
 * Re-worked for Gtkmm 3.0 by Louis Melahn, L.C. January 31, 2014.
 */
#include "transparent.h"

Transparent::Transparent() :
    _buttonLabel("Button1"),
    _alignment(Gtk::ALIGN_START, Gtk::ALIGN_START, 0.0, 0.0),    // Aligns the button.
    _button(_buttonLabel)                                        // Creates a new button with label '_buttonLabel'.
{

    // Set up the top-level window.
    set_title("Transparency test");
    set_default_size(400,400);
    set_decorated(false);
    add_events(Gdk::BUTTON_PRESS_MASK);
    set_position(Gtk::WIN_POS_CENTER);
    set_app_paintable(true);

    // Signal handlers
    signal_draw().connect(sigc::mem_fun(*this, &Transparent::on_draw));
    signal_screen_changed().connect(sigc::mem_fun(*this, &Transparent::on_screen_changed));
    signal_button_press_event().connect(sigc::mem_fun(*this, &Transparent::on_window_clicked));
    _button.signal_clicked().connect(sigc::mem_fun(*this, &Transparent::on_button_clicked));

    // Widgets

    on_screen_changed(get_screen());

    // This will add the aligner.
    add(_alignment);

    // Now pack the button into the aligner.
    _alignment.add(_button);

    // Set up the button
    _button.set_size_request(100, 100);

    // Show the window and all its children.
    show_all();
}

Transparent::~Transparent()
{
}

void Transparent::on_button_clicked()
{
    std::cout << "The button '" << _buttonLabel << "' was pressed." << std::endl;
}

bool Transparent::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
    cr->save();
    if (_SUPPORTS_ALPHA) {
        cr->set_source_rgba(0.5, 1.0, 0.5, 0.5);    // transparent
    } else {
        cr->set_source_rgb(0.5, 1.0, 0.5);          // opaque
    }
    cr->set_operator(Cairo::OPERATOR_SOURCE);
    cr->paint();
    cr->restore();

    return Gtk::Window::on_draw(cr);
}

/**
 * Checks to see if the display supports alpha channels
 */
void Transparent::on_screen_changed(const Glib::RefPtr<Gdk::Screen>& previous_screen) {
    auto screen = get_screen();
    auto visual = screen->get_rgba_visual();

    if (!visual) {
        std::cout << "Your screen does not support alpha channels!" << std::endl;
    } else {
        std::cout << "Your screen supports alpha channels!" << std::endl;
        _SUPPORTS_ALPHA = TRUE;
    }

    set_visual(visual);
}

/**
 * This simply adds a method which seems to be missing in Gtk::Widget,
 * so I had to use Gtk+ manually.
 *
 * Sets the visual for 'this' (the current widget).
 */
void Transparent::set_visual(Glib::RefPtr<Gdk::Visual> visual) {
    gtk_widget_set_visual(GTK_WIDGET(gobj()), visual->gobj());
}

/**
 * If I click somewhere other than the button, this toggles
 * between having window decorations and not having them.
 */
bool Transparent::on_window_clicked(GdkEventButton* event) {
    set_decorated(!get_decorated());
    return false;
}

希望这可以帮助!

于 2014-01-30T15:17:35.357 回答
8

在解决同样的问题时,我注意到如果我在 show_all函数之后在顶层窗口上调用 gtk_window_set_opacity() ,则使整个窗口(部分)透明对我有用。试试这个:

gtk_widget_show_all ( window );
gtk_widget_set_opacity (GTK_WIDGET (window), 0.5);

这对你也有用吗?

于 2013-11-05T22:10:11.090 回答