问题描述
在我的Gtk-Gdk-Cairo-Pango应用程序开始时,我创建了一个窗口:
GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
首先,有 GtkWindow
,但 gtk_create_window
返回 GtkWidget
,而不是 GtkWindow
,为什么?
然后,一些函数,如 在文档中还有 确实有: 但是它仍然没有告诉我, when when 和 为什么 我应该创建Gtk或Gdk窗口? 现在你问,我正在试图解决什么问题?当然,我尝试在gtk + gdk之上使用cairo + pango绘制文本,在鼠标移动之后。问题是,虽然实际绘图似乎表现很快,但我无法完全按照鼠标移动来实现。在我的 我试图加速更新通过调用 gdk_window_process_updates(..)
require GdkWindow * $ c $
$ b gtk_window_set_geometry_hints()
另一方面需要 GtkWindow *
GdkWindow * gdk_window_new()
,它返回 GdkWindow
。
这里要遵循的模式是什么?
motion_notify_event
中,我只是调用 gtk_widget_queue_draw(GtkWidget)
,但是在实际的鼠标在屏幕上移动后,如果我绘制单个字符,它在移动阶段不会与鼠标指针对齐,只会在鼠标停止后捕获它。
gdk_window_process_updates(GDK_WINDOW(window),false);
,编译器吃掉它,但我得到了运行时断言: Gdk-CRITICAL **: gdk_window_process_updates:声明'GDK_IS_WINDOW(窗口)'失败
。
$ b include
我不能在这个宏中找到任何信息,以及如何/何时使用它。 #include< gtk / gtk.h>
#define TXT1234567890
int X = 0,Y = 0;
static void do_drawing(cairo_t *);
GtkWidget *窗口;
PangoLayout * layout = 0;
static gboolean on_draw_event(GtkWidget * widget,cairo_t * cr,
gpointer user_data){
do_drawing(cr);
返回FALSE;
static void do_drawing(cairo_t * cr){
if(layout == 0){
layout = pango_cairo_create_layout(cr);
pango_layout_set_text(layout,TXT,-1);
}
for(int y = 0; y cairo_set_source_rgb(cr,1,0,1);
cairo_move_to(cr,0 + X,0 + y * 20 + Y);
pango_cairo_show_layout(cr,layout);
}
gtk_widget_queue_draw(window);
static gint onmouse(GtkWidget * widget,GdkEventMotion * event){
X = event-> x; Y =事件 - > y;
gtk_widget_queue_draw(widget);
gdk_window_process_updates(GDK_WINDOW(widget),false);
}
int main(int argc,char * argv []){
GtkWidget * darea;
gtk_init(& argc,& argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window),darea);
gtk_widget_set_events(window,GDK_EXPOSURE_MASK
| GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK);
g_signal_connect(G_OBJECT(darea),draw,G_CALLBACK(on_draw_event),NULL);
g_signal_connect(window,destroy,G_CALLBACK(gtk_main_quit),NULL);
g_signal_connect(window,motion_notify_event,G_CALLBACK(onmouse),NULL);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window),5000,5000);
gtk_window_set_title(GTK_WINDOW(window),Lines);
gtk_widget_show_all(window);
gtk_main();
返回0;
/ em>(X11,Wayland,Windows的user32.dll,以及Mac OS X中名称我不记得的那个)并不(必然)自己提供很多功能。他们给你的是:
- 可以创建屏幕区域,名为 windows ,您可以吸引,移动,调整大小,重塑形状,最小化,隐藏在其他窗口之后,并以其他基本方式进行控制 - 但对于我们的讨论而言,其中最重要的一点是借鉴
- 鼠标Windows的事件处理:当鼠标移入或移出窗口时,窗口周围或当鼠标光标位于窗口上时单击鼠标按钮时的通知
- 概念的窗口,它接收此窗口的键盘输入( focused window )和键盘事件:当用户键入窗口时
- 其他各种函数(绘图鼠标例如游标)
与一个工具组合时,可以将矢量图形和文本渲染结合到一个窗口中(通常由其他工具库,如cairo和pango),GUI工具包即可发挥作用。这就是窗口管理器窗口,并将它分成所有熟悉的小控件:按钮,文本字段,列表,标签页,网页渲染器等。
在这种情况下,GTK +是GUI工具包。它提供了您在程序中使用的大量控件。
当您使用GUI工具包时,通常不会直接与窗口管理器进行交互。相反,GUI工具包提供了自己的窗口。当您创建GUI工具包窗口时,GUI工具包会创建底层窗口管理器窗口,然后控制所有绘图和事件,以便它可以处理在窗口中为您提供所有那些整齐控制的工作。
b
$ b对于GTK +,这是GtkWindow。
GTK +的设计者不希望每个人都拥有所有的窗口管理器交互代码GTK +自己支持的平台。相反,他们创建了一个独立的库(包含在GTK +源代码中),称为GDK。 GDK提供了一个一致的便携式API,用于围绕低级特定于平台的窗口管理器函数。
因此GdkWindow是封装在窗口管理器窗口中的类型,并提供便携式界面GTK +使用。当你创建一个GdkWindow时,你创建了这些低级窗口管理器窗口中的一个,而不是你放置控件的更丰富的GtkWindow。
历史上X11一直很资源约束。 GTK +不会为每个控件创建窗口管理器窗口;它只为GtkWindow,GtkPopover和其他类似的控件创建这些控件,这些控件作为我们用户认为的windows。
有了这些知识,您现在可以你的问题的答案:你几乎总是想使用GtkWindow,并且几乎从不想使用GdkWindow。 GdkWindow只对实现某些GTK +控件非常有用。
和GdkWindow和GtkWindow不可互换。
(这仍然是一种合理准确的过度简化,并不适用于所有环境,例如,编写本机Windows程序的人,通常为每个人创建窗口管理器窗口控制,窗口管理器提供了一些基本的控件,比如按钮,我也可能在上面的解释中得到了一些细节错误。)
GDK和GTK +还有其他几个优点。举例来说,添加Wayland支持并不(就我所知;我可能很错误)需要对GTK +本身进行很多更改,并且有一个名为,它可让正常的GTK +程序在网页浏览器中呈现。
更新,因为我似乎将这个问题联系在一起:
- 有一段时间,大多数GtkWidgets实际上都有他们自己的GdkWindows; 。现在,我描述的情况就是这样。
At the beginning of my Gtk-Gdk-Cairo-Pango app, I create the window:
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
First, there is
GtkWindow
, butgtk_create_window
returnsGtkWidget
, notGtkWindow
, why?Then, some functions, like
gdk_window_process_updates(..)
requireGdkWindow*
.gtk_window_set_geometry_hints()
on the other hand requiresGtkWindow*
.In documentation there is also
GdkWindow* gdk_window_new()
that returnsGdkWindow
.Sure there is documentation saying:
But it still does not tell me, when and why I should create Gtk or Gdk windows? What is the pattern here to follow?
Now you ask, what particular problem I am trying to solve? Sure, I try to draw text using cairo+pango on top of gtk+gdk, right after mouse moves. The problem is that although the actual drawing seems to be fast performing, I cannot get it happen exactly as mouse moves. In my
motion_notify_event
I just callgtk_widget_queue_draw(GtkWidget)
but there is obvious lag behind the actual mouse moving on screen, even if I draw single character it is not aligned with the mouse pointer during the move phase and only catches it after the mouse is stopped.What I tried is to speed up the update by calling
gdk_window_process_updates(GDK_WINDOW(window), false);
, the compiler eats it, but I got runtime assertion:Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed
. I cannot find any information on this macro and how/when to use it.include
#include <gtk/gtk.h> #define TXT "1234567890" int X = 0, Y = 0; static void do_drawing(cairo_t *); GtkWidget *window; PangoLayout *layout = 0; static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) { do_drawing(cr); return FALSE; } static void do_drawing(cairo_t *cr) { if (layout == 0) { layout = pango_cairo_create_layout (cr); pango_layout_set_text (layout, TXT, -1); } for (int y = 0; y < 2; y++) { cairo_set_source_rgb (cr, 1, 0, 1); cairo_move_to (cr, 0+X, 0 + y * 20 + Y); pango_cairo_show_layout (cr, layout); } gtk_widget_queue_draw(window); } static gint onmouse(GtkWidget *widget, GdkEventMotion *event) { X = event->x; Y = event->y; gtk_widget_queue_draw(widget); gdk_window_process_updates(GDK_WINDOW(widget), false); } int main(int argc, char *argv[]) { GtkWidget *darea; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); darea = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(window), darea); gtk_widget_set_events (window, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(window, "motion_notify_event", G_CALLBACK(onmouse), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 5000, 5000); gtk_window_set_title(GTK_WINDOW(window), "Lines"); gtk_widget_show_all(window); gtk_main(); return 0; }
解决方案Window managers (X11, Wayland, Windows's user32.dll, and the one in Mac OS X whose name I don't remember) do not (necessarily) provide much functionality on their own. What they give you is:
- the ability to create on-screen regions, called windows, which you can draw on, move around, resize, reshape, minimize, hide behind other windows, and control in other basic ways — but the most important of these for our discussion is "draw on"
- mouse event handling for windows: notifications when the mouse moves into or out of a window, around inside a window, or when the mouse buttons are clicked when the mouse cursor is over a window
- the concept of a window which receives keyboard input (the focused window) and keyboard events for this window: when the user types into a window
- miscellaneous other functions (drawing mouse cursors, for instance)
When combined with a facility to do vector graphics and text rendering into a window (which is often provided by other libraries, such as cairo and pango), the GUI toolkit comes into play. This is what takes the window manager window and divides it into all the little controls that you're familiar with: buttons, text fields, lists, tabs, web page renderers, etc.
GTK+ is the GUI toolkit in this case. It provides the plethora of controls that you use in your programs.
When you use a GUI toolkit, you don't typically interact with the window manager directly. So instead, the GUI toolkit provides its own window. When you create a GUI toolkit window, the GUI toolkit creates the underlying window manager window, then takes control of all the drawing and events so that it can handle the work of giving you all those neat controls in that window.
For GTK+, this is GtkWindow.
The designers of GTK+ did not want to have all the window manager interaction code for each individual platform that GTK+ supports in GTK+ itself. Instead, they created a separate library (included with the GTK+ source code), called GDK. GDK provides a consistent portable API around the low-level platform-specific window manager functions.
So GdkWindow is the type that wraps around a window manager window and provides the portable interface that GTK+ uses. When you create a GdkWindow, you're creating one of these low-level window manager windows, not the richer GtkWindow that you place controls on.
X11 has historically been very resource-constraining. GTK+ doesn't create a window manager window for every control; it only creates these for GtkWindow, GtkPopover, and other similar controls that act as what we as users think of as windows.
Armed with all this knowledge, you can now figure the answer to your question: you almost always want to use GtkWindow, and almost never want to use GdkWindow. GdkWindow is only really useful for the implementation of certain GTK+ controls.
And GdkWindow and GtkWindow are NOT interchangeable.
(This is a still-reasonably-accurate oversimplification of what's going on. It does not hold true for all environments. People who write native Windows programs, for instance, generally do create window manager windows for each control, and the window manager provides some basic controls, such as buttons. I may have also gotten some details in the above explanation wrong.)
The separation between GDK and GTK+ also has several other advantages. Adding Wayland support, for instance, did not (as far as I know; I could very well be wrong about this) require many changes to GTK+ itself, and there is a GDK layer called broadway which lets normal GTK+ programs render in a web browser.
Updates, since I seem to be linking this a lot:
- There was a time when most GtkWidgets actually had their own GdkWindows; here's what happened. Now, the situation I described is the case.
这篇关于GtkWindow和GdkWindow之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- 其他各种函数(绘图鼠标例如游标)