在我的Gtk-Gdk-Cairo-Pango应用程序的开头,创建窗口:
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
首先,有
GtkWindow
,但是gtk_create_window
返回GtkWidget
,而不是GtkWindow
,为什么?然后,某些功能(例如
gdk_window_process_updates(..)
)需要GdkWindow*
。另一方面,
gtk_window_set_geometry_hints()
需要GtkWindow*
。在文档中,还有
GdkWindow* gdk_window_new()
返回GdkWindow
。当然有documentation saying:
GdkWindow是屏幕上的矩形区域。这是低级的
对象,用于实现高级对象,例如GtkWidget和
GTK +级别上的GtkWindow。 GtkWindow是顶层窗口,
用户可能会将其视为带有标题栏等的“窗口”;一个
GtkWindow可能包含许多GdkWindow。
但是它仍然没有告诉我,何时以及为什么我应该创建Gtk或Gdk窗口?
这里要遵循的模式是什么?
现在您问,我要解决什么特定问题?当然,在鼠标移动之后,我尝试在gtk + gdk上方使用cairo + pango绘制文本。问题是,尽管实际绘图似乎执行得很快,但我无法完全按照鼠标移动来进行绘制。在我的
motion_notify_event
中,我只调用了gtk_widget_queue_draw(GtkWidget)
,但是即使在移动阶段绘制单个字符时,该字符与鼠标指针未对齐,并且仅在鼠标移动后才捕获它,但实际鼠标在屏幕上的移动仍存在明显的滞后。停了我试图通过调用
gdk_window_process_updates(GDK_WINDOW(window), false);
加快更新速度,编译器将其吃掉,但是我得到了运行时断言:Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed
。我找不到有关此宏以及如何/何时使用它的任何信息。包括
#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;
}
最佳答案
窗口管理器(X11,Wayland,Windows的user32.dll,以及Mac OS X中我不记得其名称的窗口管理器)自身(不一定)提供了很多功能。他们给你的是:
创建屏幕区域(称为窗口)的功能,您可以在该窗口上进行绘制,移动,调整大小,重塑形状,最小化,隐藏在其他窗口后面,并以其他基本方式进行控制-但在我们的讨论中,最重要的是“画在”
窗口的鼠标事件处理:当鼠标移入或移出窗口,在窗口内部或在鼠标光标悬停在窗口上方时单击鼠标按钮时的通知
接收键盘输入(焦点窗口)和该窗口的键盘事件的窗口的概念:当用户键入窗口时
其他功能(例如,绘制鼠标光标)
当与将矢量图形和文本呈现到窗口中的工具(通常由其他库,例如cairo和pango提供)结合使用时,GUI工具包就起作用了。这就是将窗口管理器窗口划分为您所熟悉的所有小控件的过程:按钮,文本字段,列表,选项卡,网页渲染器等。
在这种情况下,GTK +是GUI工具箱。它提供了您在程序中使用的过多控件。
使用GUI工具箱时,通常不会直接与窗口管理器进行交互。因此,GUI工具包提供了自己的窗口。创建GUI工具箱窗口时,GUI工具箱会创建基础的窗口管理器窗口,然后控制所有图形和事件,以便它可以处理在该窗口中为您提供所有这些整洁控件的工作。
对于GTK +,这是GtkWindow。
GTK +的设计人员不想让GTK +本身在GTK +所支持的每个平台上都拥有所有的窗口管理器交互代码。相反,他们创建了一个单独的库(包含在GTK +源代码中),称为GDK。 GDK围绕特定于底层平台的窗口管理器功能提供了一致的可移植API。
因此,GdkWindow是包裹在窗口管理器窗口中并提供GTK +使用的可移植接口的类型。创建GdkWindow时,是在创建这些低级窗口管理器窗口之一,而不是要放置控件的更丰富的GtkWindow。
X11历史上一直非常资源紧张。 GTK +不会为每个控件创建一个窗口管理器窗口。它只会为GtkWindow,GtkPopover和其他类似控件创建这些控件,这些控件就像我们作为用户的窗口一样。
有了所有这些知识,您现在就可以找到问题的答案:您几乎总是想使用GtkWindow,而几乎从来不想使用GdkWindow。 GdkWindow仅对某些GTK +控件的实现非常有用。
并且GdkWindow和GtkWindow不可互换。
(这是对正在发生的事情的一种仍然合理准确的过度简化。并非在所有环境中都适用。例如,编写本机Windows程序的人通常会为每个控件创建窗口管理器窗口,并且窗口管理器会提供一些基本控件,例如按钮。在上述说明中,我可能也得到了一些细节错误。)
GDK和GTK +之间的分离还具有其他一些优点。例如,添加Wayland支持并不需要(据我所知;我对此很可能错了),不需要对GTK +本身进行很多更改,并且有一个名为broadway的GDK层,可以让普通的GTK +程序在网页浏览器。
更新,因为我似乎对此链接很多:
曾经有一段时间,大多数GtkWidget实际上都拥有自己的GdkWindows。 here's what happened。现在,我描述的情况就是如此。