在 gtk 中绘制背景图像 - 我的尝试都不起作用

发布于 2024-12-07 12:41:16 字数 5406 浏览 4 评论 0 原文

我一直在尝试在 gtk 小部件上设置背景图像,但没有成功,即使在尝试了 4 种不同的方法之后也是如此。

下面的程序包含3种方法(第4种方法不涉及代码)。我使用 MinGW (g++ 4.5.0) 和 gtkmm 2.4 编译它。 APPROACH 宏可以设置为 1、2 或 3,以便选择编译哪种方法。我还在评论中添加了参考资料,以便您可以了解我的想法来自哪里。

#include <iostream>
#include <gtkmm/main.h>
#include <gtkmm/alignment.h>
#include <gtkmm/box.h>
#include <gtkmm/entry.h>
#include <gtkmm/eventbox.h>
#include <gtkmm/frame.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include <gtkmm/table.h>
#include <gtkmm/window.h>

// Set this to 1, 2 or 3 to try different ways of drawing the background
// Set to 0 to load no background at all
#define APPROACH (0)

// Making this alignment global in order to modify it from drawBackground
Gtk::Alignment* alignment;

bool drawBackground(GdkEventExpose* event) {
    std::cout << "Draw background" << std::endl;

    // Load background image
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_file("background.jpg");
    Glib::RefPtr<Gdk::Pixmap> pixmap;
    Glib::RefPtr<Gdk::Bitmap> mask;
    pixbuf->render_pixmap_and_mask(pixmap, mask,0);

    {
        // Test that pixbuf was created correctly
        Glib::RefPtr<Gdk::Pixbuf> back_to_pixbuf = Gdk::Pixbuf::create((Glib::RefPtr<Gdk::Drawable>)pixmap, 0, 0, pixbuf->get_width(), pixbuf->get_height());
        back_to_pixbuf->save("back_to_pixbuf.png", "png");
    }

#if APPROACH == 1
    // Approach 1: draw_pixbuf
    // Ref: http://islascruz.org/html/index.php/blog/show/Image-as-background-in-a-Gtk-Application..html
    Glib::RefPtr<Gtk::Style> style = alignment->get_style();
    alignment->get_window()->draw_pixbuf(style->get_bg_gc(Gtk::STATE_NORMAL), pixbuf, 0, 0, 0, 200, pixbuf->get_width(), pixbuf->get_height(), Gdk::RGB_DITHER_NONE, 0, 0);
#endif

#if APPROACH == 2
    // Approach 2: set_back_pixmap
    // Ref: http://www.gtkforums.com/viewtopic.php?t=446
    //      http://stackoverflow.com/questions/3150706/gtk-drawing-set-background-image
    alignment->get_window()->set_back_pixmap(pixmap);
#endif
}

int main (int argc, char *argv[])
{
    Gtk::Main kit(argc, argv);

    Gtk::Window w;
    Gtk::VBox mainBox;

    // Top image
    Gtk::Image topImage("header.jpg");
    mainBox.pack_start(topImage,false,false,0);

    // Middle alignment
    alignment = Gtk::manage(new Gtk::Alignment);
    mainBox.pack_start(*alignment,true,true,0);

    // Create widget
    Gtk::Alignment mywidget(0.5, 0.5, 0.1, 0.9);
    Gtk::Table table;
    Gtk::Label label1("Username"); table.attach(label1,0,1,0,1);
    Gtk::Label label2("Password"); table.attach(label2,0,1,1,2);
    Gtk::Entry entry1;             table.attach(entry1,1,2,0,1);
    Gtk::Entry entry2;             table.attach(entry2,1,2,1,2);
    Gtk::Button button("Login");   table.attach(button,1,2,2,3);
    mywidget.add(table);

    // Put widget in middle alignment
    alignment->add(mywidget);

    // Try to change the background
#if APPROACH == 1 || APPROACH == 2
    alignment->signal_expose_event().connect(sigc::ptr_fun(&drawBackground), true);
#endif

#if APPROACH == 3
    // Approach 3: modify the style using code
    // Ref: http://www.gtkforums.com/viewtopic.php?t=446
    // Load background image
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_file("background.jpg");
    Glib::RefPtr<Gdk::Pixmap> pixmap;
    Glib::RefPtr<Gdk::Bitmap> mask;
    pixbuf->render_pixmap_and_mask(pixmap, mask,0);
    Glib::RefPtr<Gtk::Style> style = alignment->get_style()->copy();
    style->set_bg_pixmap(Gtk::STATE_NORMAL,pixmap);
    style->set_bg_pixmap(Gtk::STATE_ACTIVE,pixmap);
    style->set_bg_pixmap(Gtk::STATE_PRELIGHT,pixmap);
    style->set_bg_pixmap(Gtk::STATE_SELECTED,pixmap);
    style->set_bg_pixmap(Gtk::STATE_INSENSITIVE,pixmap);
    alignment->set_style(style);
#endif

    // Approach 4: modify share\themes\MS-Windows\gtk-2.0
    // adding the following line
    // bg_pixmap[NORMAL] = "D:\\path\\to\\file\\background.jpg"
    // in the style "msw-default" section
    // Ref: http://lists.ximian.com/pipermail/gtk-sharp-list/2005-August/006324.html

    // Show the window
    w.add(mainBox);
    w.show_all();
    kit.run(w);
    return 0;
}

我使用的图像链接: header.jpg background.jpg

布局模仿了我的实际程序。主窗口包含一个 Gtk::VBox,顶部有标题图像,底部有 Gtk::Alignment。此对齐的内容会随着时间的推移而改变,但我希望它有一个始终可见的背景图像。

当根本不加载背景时,标题图像会正确加载,窗口如下所示:

在此处输入图像描述

方法 1 是一种更接近工作的方法,尽管它隐藏了标签和按钮:

在此处输入图像描述

方法23 看起来与不加载背景相同。此外,方法 2 给了我以下错误消息:

(test-img-fondo.exe:1752): Gdk-CRITICAL **: gdk_window_set_back_pixmap: assertion `pixmap == NULL || !parent_relative' failed

添加以下行来修改 share\themes\MS-Windows\gtk-2.0

bg_pixmap[NORMAL] = "D:\\path\\to\\file\\background.jpg"

最后,在方法 4 中,我尝试通过在样式“msw-”中 默认”部分。它也不起作用。

那么,有人成功地在 Gtk 小部件上绘制了背景图像吗?这有可能吗?我的代码中是否有任何更改可以使此工作正常进行?有什么解决方法吗?

非常感谢所有帮助。

I've been trying to set a background image on a gtk widget without success, even after trying 4 different approaches.

The following program contains 3 approaches (the 4th approach involves no code). I compiled it using MinGW (g++ 4.5.0) and gtkmm 2.4. The APPROACH macro can be set to 1, 2 or 3 in order to choose which approach to compile. I've also added references in the comments, so you can find out where I got the ideas from.

#include <iostream>
#include <gtkmm/main.h>
#include <gtkmm/alignment.h>
#include <gtkmm/box.h>
#include <gtkmm/entry.h>
#include <gtkmm/eventbox.h>
#include <gtkmm/frame.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include <gtkmm/table.h>
#include <gtkmm/window.h>

// Set this to 1, 2 or 3 to try different ways of drawing the background
// Set to 0 to load no background at all
#define APPROACH (0)

// Making this alignment global in order to modify it from drawBackground
Gtk::Alignment* alignment;

bool drawBackground(GdkEventExpose* event) {
    std::cout << "Draw background" << std::endl;

    // Load background image
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_file("background.jpg");
    Glib::RefPtr<Gdk::Pixmap> pixmap;
    Glib::RefPtr<Gdk::Bitmap> mask;
    pixbuf->render_pixmap_and_mask(pixmap, mask,0);

    {
        // Test that pixbuf was created correctly
        Glib::RefPtr<Gdk::Pixbuf> back_to_pixbuf = Gdk::Pixbuf::create((Glib::RefPtr<Gdk::Drawable>)pixmap, 0, 0, pixbuf->get_width(), pixbuf->get_height());
        back_to_pixbuf->save("back_to_pixbuf.png", "png");
    }

#if APPROACH == 1
    // Approach 1: draw_pixbuf
    // Ref: http://islascruz.org/html/index.php/blog/show/Image-as-background-in-a-Gtk-Application..html
    Glib::RefPtr<Gtk::Style> style = alignment->get_style();
    alignment->get_window()->draw_pixbuf(style->get_bg_gc(Gtk::STATE_NORMAL), pixbuf, 0, 0, 0, 200, pixbuf->get_width(), pixbuf->get_height(), Gdk::RGB_DITHER_NONE, 0, 0);
#endif

#if APPROACH == 2
    // Approach 2: set_back_pixmap
    // Ref: http://www.gtkforums.com/viewtopic.php?t=446
    //      http://stackoverflow.com/questions/3150706/gtk-drawing-set-background-image
    alignment->get_window()->set_back_pixmap(pixmap);
#endif
}

int main (int argc, char *argv[])
{
    Gtk::Main kit(argc, argv);

    Gtk::Window w;
    Gtk::VBox mainBox;

    // Top image
    Gtk::Image topImage("header.jpg");
    mainBox.pack_start(topImage,false,false,0);

    // Middle alignment
    alignment = Gtk::manage(new Gtk::Alignment);
    mainBox.pack_start(*alignment,true,true,0);

    // Create widget
    Gtk::Alignment mywidget(0.5, 0.5, 0.1, 0.9);
    Gtk::Table table;
    Gtk::Label label1("Username"); table.attach(label1,0,1,0,1);
    Gtk::Label label2("Password"); table.attach(label2,0,1,1,2);
    Gtk::Entry entry1;             table.attach(entry1,1,2,0,1);
    Gtk::Entry entry2;             table.attach(entry2,1,2,1,2);
    Gtk::Button button("Login");   table.attach(button,1,2,2,3);
    mywidget.add(table);

    // Put widget in middle alignment
    alignment->add(mywidget);

    // Try to change the background
#if APPROACH == 1 || APPROACH == 2
    alignment->signal_expose_event().connect(sigc::ptr_fun(&drawBackground), true);
#endif

#if APPROACH == 3
    // Approach 3: modify the style using code
    // Ref: http://www.gtkforums.com/viewtopic.php?t=446
    // Load background image
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_file("background.jpg");
    Glib::RefPtr<Gdk::Pixmap> pixmap;
    Glib::RefPtr<Gdk::Bitmap> mask;
    pixbuf->render_pixmap_and_mask(pixmap, mask,0);
    Glib::RefPtr<Gtk::Style> style = alignment->get_style()->copy();
    style->set_bg_pixmap(Gtk::STATE_NORMAL,pixmap);
    style->set_bg_pixmap(Gtk::STATE_ACTIVE,pixmap);
    style->set_bg_pixmap(Gtk::STATE_PRELIGHT,pixmap);
    style->set_bg_pixmap(Gtk::STATE_SELECTED,pixmap);
    style->set_bg_pixmap(Gtk::STATE_INSENSITIVE,pixmap);
    alignment->set_style(style);
#endif

    // Approach 4: modify share\themes\MS-Windows\gtk-2.0
    // adding the following line
    // bg_pixmap[NORMAL] = "D:\\path\\to\\file\\background.jpg"
    // in the style "msw-default" section
    // Ref: http://lists.ximian.com/pipermail/gtk-sharp-list/2005-August/006324.html

    // Show the window
    w.add(mainBox);
    w.show_all();
    kit.run(w);
    return 0;
}

Links to images I used: header.jpg background.jpg

The layout mimics that of my actual program. The main window contains a Gtk::VBox with a header image on top and an Gtk::Alignment at the bottom. The contents of this alignment will change over time but I want it to have a background image always visible.

When loading no background at all, the header image loads correctly and the window looks like this:

enter image description here

Approach 1 is the one that is closer to work, though it hides the labels and the buttons:

enter image description here

Approaches 2 and 3 look the same as loading no background. Besides, approach 2 gives me the following error message:

(test-img-fondo.exe:1752): Gdk-CRITICAL **: gdk_window_set_back_pixmap: assertion `pixmap == NULL || !parent_relative' failed

Finally, in approach 4, I attempt to modify share\themes\MS-Windows\gtk-2.0 by adding the following line

bg_pixmap[NORMAL] = "D:\\path\\to\\file\\background.jpg"

in the style "msw-default" section. It doesn't work either.

So, has anyone succesfully drawn a background image on a Gtk widget? Is this possible at all? Any changes in my code that would make this work? Any workarounds?

All help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

破晓 2024-12-14 12:41:16

我想我自己已经解决了。使用方法 1,但更改此行

alignment->signal_expose_event().connect(sigc::ptr_fun(&drawBackground), true);

alignment->signal_expose_event().connect(sigc::ptr_fun(&drawBackground), false);

这样,对 drawBackground 的调用发生在 gtk 调用其自己的处理程序之前。

在此处输入图像描述

我还应该指出,在真实的程序中,图像应该在 绘制背景

I think I've solved it myself. Use approach 1 but change this line

alignment->signal_expose_event().connect(sigc::ptr_fun(&drawBackground), true);

for this:

alignment->signal_expose_event().connect(sigc::ptr_fun(&drawBackground), false);

This way, the call to drawBackground occurs before gtk calls its own handlers.

enter image description here

I should also point out that, in a real program, the images should be loaded once outside of drawBackground.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文