Displaying RGB Image in GTK+-2.2
I'm writing a class that can take my own RGB images and display them to windows using GTK+-2.2. My Image class stores the images as packed 24-bit RGB bytes, so the conversion should be trivial. I'm using the gdk_draw_rgb(...) method to draw to my window, but nothing gets drawn at all - the window just shows up gray.
I did get this to work using Cairo, unfortunately Cairo can only represent images in 32bpp format, and doing that conversion was just too slow.
class ImageDisplay
{
public:
ImageDisplay();
~ImageDisplay();
void showImage(Image img, std::string label="");
private:
std::thread _gtkThread;
std::map<std::string, GtkWidget*> _windows;
};
// ######################################################################
void gtkThreadMethod()
{
g_thread_init(NULL);
gdk_threads_init();
gdk_threads_enter();
int argc=1;
char **argv = new char*;
argv[0] = new char[8];
sprintf(argv[0], 开发者_如何学运维"display");
gtk_init(&argc, &argv);
gdk_rgb_set_verbose(TRUE);
gtk_main();
gdk_threads_leave();
}
// ######################################################################
ImageDisplay::ImageDisplay()
{
// Start gtk in its own thread
_gtkThread = std::thread(gtkThreadMethod);
}
// ######################################################################
ImageDisplay::~ImageDisplay()
{
// Tell GTK that it's time to quit
gdk_threads_enter();
gtk_main_quit();
gdk_threads_leave();
// Wait for the thread to die
_gtkThread.join();
}
// ######################################################################
void ImageDisplay::showImage(Image img, std::string label)
{
gdk_threads_enter();
// Create a new window if one doesn't yet exist
if(_windows.find(label) == _windows.end())
{
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), label.c_str());
gtk_window_set_default_size(GTK_WINDOW(window), img.dims().w(), img.dims().h());
gtk_widget_set_app_paintable(window, TRUE);
gtk_window_set_resizable(GTK_WINDOW(window), true);
GdkGeometry size_hints;
size_hints.min_aspect = 1;
size_hints.max_aspect = 1;
gtk_window_set_geometry_hints(GTK_WINDOW(window), window,
&size_hints, GDK_HINT_ASPECT);
gtk_widget_show_all(window);
_windows[label] = window;
}
GtkWidget* window = _windows[label];
GdkGC *gc = gdk_gc_new(gtk_widget_get_root_window(window));
gdk_draw_rgb_image(
gtk_widget_get_root_window(window),
gc,
0, 0,
img.dims().w(), img.dims().h(),
GDK_RGB_DITHER_NORMAL,
(const unsigned char*)img.const_begin(),
img.dims().w()*3);
gdk_threads_leave();
}
gdk_draw_rgb_image(
gtk_widget_get_root_window(window),
There's your problem. In X terminology (which GTK+ borrows from heavily), the "root window" refers to the desktop background. You want gtk_widget_get_window
which will get you the GdkDrawable
which represents your window.
However... I haven't walked very far up the stack from the line above, and I am not sure what the caller of this code looks like, but you generally want to draw in an "expose event" handler, rather than immediately after calling gtk_window_new
. The last time I was writing this kind of code (it's been a while, I'll admit), what I would do is create a GdkPixmap
to draw in and then copy its contents to the user-visible GdkWindow
on the expose event. The GtkDrawingArea
widget is helpful here, so I would search for examples using that.
To display a (client-side) image, I think you should look into using the GtkImage
widget, rather than "overloading" a random widget to do custom painting.
This will in turn expose a GdkPixbuf
holding the pixels.
精彩评论