GTK+2:透明地绘制在其他小部件之上
GTK+2: Drawing above other widgets transparently
我被迫使用 Gtk+2。所以请不要讨论切换到 3 或 4。
我需要创建类似于 Gtk3s 的东西 GtkOverlay
并且我需要在其他小部件上绘制透明背景。
我想使用 GtkFixed
并将我的“普通”小部件放在那里,然后使用 GtkEventBox
放在顶部并在将颜色图(如果支持)设置为透明后连接其公开事件.
我做了一些工作,但没有达到预期的结果。它导致事件框变成半透明的(如我所愿),但现在显示下面的小部件,但显示 window.
下面的所有内容
到目前为止,这是我的代码(抱歉搞得一团糟):
#include <gtk/gtk.h>
GtkWidget *window;
GtkWidget *button;
GtkWidget *vbox;
GtkWidget *fixed;
GtkWidget *event_overlay;
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 colormap */
GdkScreen *screen = gtk_widget_get_screen(widget);
GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
if (!colormap)
{
printf("Your screen does not support alpha channels!\n");
colormap = gdk_screen_get_rgb_colormap(screen);
supports_alpha = FALSE;
}
else
{
printf("Your screen supports alpha channels!\n");
supports_alpha = TRUE;
}
gtk_widget_set_colormap(widget, colormap);
}
static gboolean exposed (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5); /* transparent */
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_destroy(cr);
return TRUE;
}
static void hello( GtkWidget *widget,
gpointer data )
{
gtk_fixed_put(GTK_FIXED(fixed), event_overlay, 100, 100);
}
static void destroy( GtkWidget *widget,
gpointer data )
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy), NULL);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked",
G_CALLBACK (hello), NULL);
vbox = gtk_vbox_new(TRUE, 5);
gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0);
fixed = gtk_fixed_new();
gtk_fixed_set_has_window(GTK_FIXED(fixed), TRUE);
gtk_widget_set_size_request(button, 500, 500);
gtk_fixed_put(GTK_FIXED(fixed), vbox, 0, 0);
event_overlay = gtk_event_box_new();
gtk_widget_set_size_request(event_overlay, 500, 500);
g_signal_connect(event_overlay, "expose-event", G_CALLBACK(exposed), NULL);
g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL);
gtk_widget_set_app_paintable(window, TRUE);
gtk_container_add (GTK_CONTAINER (window), fixed);
screen_changed(window, NULL, NULL);
gtk_widget_show_all (window);
gtk_widget_show(event_overlay);
gtk_main ();
return 0;
}
结果如下:
事实证明,GTK+ 2 的作者实际上已经预见到了这个用例。作为 gtk-demo
程序的一部分,有一对非常相似的 ready-made 示例,与 GTK+ 2 文档一起分发。两个演示都位于“Offscreen windows”节点下。
代码有点复杂,这里就不放了;该演示实际上 subclasses GtkContainer
创建一个新的小部件 class 将事件转发到其 child 并将其呈现到 off-screen window对渲染结果进行进一步的转换。但是您应该会发现“效果”示例很容易适应您的需要:您所要做的就是修改 gtk_mirror_bin_expose
以简单地将 off-screen window 的内容绘制到容器的真实容器中window 然后在其上绘制 semi-transparent 叠加层;并调整 gtk_mirror_bin_size_request
和 gtk_mirror_bin_size_allocate
以简单地将所有 sizing-related 信号透明地转发到 child。
我被迫使用 Gtk+2。所以请不要讨论切换到 3 或 4。
我需要创建类似于 Gtk3s 的东西 GtkOverlay
并且我需要在其他小部件上绘制透明背景。
我想使用 GtkFixed
并将我的“普通”小部件放在那里,然后使用 GtkEventBox
放在顶部并在将颜色图(如果支持)设置为透明后连接其公开事件.
我做了一些工作,但没有达到预期的结果。它导致事件框变成半透明的(如我所愿),但现在显示下面的小部件,但显示 window.
下面的所有内容到目前为止,这是我的代码(抱歉搞得一团糟):
#include <gtk/gtk.h>
GtkWidget *window;
GtkWidget *button;
GtkWidget *vbox;
GtkWidget *fixed;
GtkWidget *event_overlay;
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 colormap */
GdkScreen *screen = gtk_widget_get_screen(widget);
GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
if (!colormap)
{
printf("Your screen does not support alpha channels!\n");
colormap = gdk_screen_get_rgb_colormap(screen);
supports_alpha = FALSE;
}
else
{
printf("Your screen supports alpha channels!\n");
supports_alpha = TRUE;
}
gtk_widget_set_colormap(widget, colormap);
}
static gboolean exposed (GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5); /* transparent */
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_destroy(cr);
return TRUE;
}
static void hello( GtkWidget *widget,
gpointer data )
{
gtk_fixed_put(GTK_FIXED(fixed), event_overlay, 100, 100);
}
static void destroy( GtkWidget *widget,
gpointer data )
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy), NULL);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked",
G_CALLBACK (hello), NULL);
vbox = gtk_vbox_new(TRUE, 5);
gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0);
fixed = gtk_fixed_new();
gtk_fixed_set_has_window(GTK_FIXED(fixed), TRUE);
gtk_widget_set_size_request(button, 500, 500);
gtk_fixed_put(GTK_FIXED(fixed), vbox, 0, 0);
event_overlay = gtk_event_box_new();
gtk_widget_set_size_request(event_overlay, 500, 500);
g_signal_connect(event_overlay, "expose-event", G_CALLBACK(exposed), NULL);
g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL);
gtk_widget_set_app_paintable(window, TRUE);
gtk_container_add (GTK_CONTAINER (window), fixed);
screen_changed(window, NULL, NULL);
gtk_widget_show_all (window);
gtk_widget_show(event_overlay);
gtk_main ();
return 0;
}
结果如下:
事实证明,GTK+ 2 的作者实际上已经预见到了这个用例。作为 gtk-demo
程序的一部分,有一对非常相似的 ready-made 示例,与 GTK+ 2 文档一起分发。两个演示都位于“Offscreen windows”节点下。
代码有点复杂,这里就不放了;该演示实际上 subclasses GtkContainer
创建一个新的小部件 class 将事件转发到其 child 并将其呈现到 off-screen window对渲染结果进行进一步的转换。但是您应该会发现“效果”示例很容易适应您的需要:您所要做的就是修改 gtk_mirror_bin_expose
以简单地将 off-screen window 的内容绘制到容器的真实容器中window 然后在其上绘制 semi-transparent 叠加层;并调整 gtk_mirror_bin_size_request
和 gtk_mirror_bin_size_allocate
以简单地将所有 sizing-related 信号透明地转发到 child。