📄 x2379.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><HTML><HEAD><TITLE>事件处理</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+"><LINKREL="HOME"TITLE="GTK+ 2.0 教程"HREF="book1.html"><LINKREL="UP"TITLE="涂鸦板,一个简单的绘图程序"HREF="c2370.html"><LINKREL="PREVIOUS"TITLE="涂鸦板,一个简单的绘图程序"HREF="c2370.html"><LINKREL="NEXT"TITLE="绘图区构件和绘图"HREF="x2418.html"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">GTK+ 2.0 教程</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="c2370.html"ACCESSKEY="P"><<< Previous</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">涂鸦板,一个简单的绘图程序</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="x2418.html"ACCESSKEY="N">Next >>></A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="SEC-EVENTHANDLING">事件处理</H1><P>我们已经讨论了 GTK 信号中的高级的事件,如单选菜单项。然而,有时学习一些低级的事件也是有好用的,如鼠标移动或按一个键。在 GTK 中有信号与这些低级<ICLASS="EMPHASIS">事件</I>联系。这些信号的处理函数有额外的参数,该函数是一个结构指针,包含事件的信息。例如,传递给移动事件处理函数的参数是一个 GdkEventMotion 类型的结构指针,如下:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">struct _GdkEventMotion{ GdkEventType type; GdkWindow *window; guint32 time; gdouble x; gdouble y; ... guint state; ...};</PRE></TD></TR></TABLE><P><TTCLASS="LITERAL">type</TT>会设置为事件的类型,如移动事件是<TTCLASS="LITERAL">GDK_MOTION_NOTIFY</TT>,window是发生事件的窗口。<TTCLASS="LITERAL">x</TT>和<TTCLASS="LITERAL">y</TT>给出事件的座标。<TTCLASS="LITERAL">state</TT>指出事件发生时的状态(按下了那个修正键或鼠标键)。它是如下值的位或:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GDK_SHIFT_MASK GDK_LOCK_MASK GDK_CONTROL_MASKGDK_MOD1_MASK GDK_MOD2_MASK GDK_MOD3_MASK GDK_MOD4_MASK GDK_MOD5_MASK GDK_BUTTON1_MASKGDK_BUTTON2_MASKGDK_BUTTON3_MASKGDK_BUTTON4_MASKGDK_BUTTON5_MASK</PRE></TD></TR></TABLE><P>至于其它信号,我们调用函数<TTCLASS="LITERAL">gtk_signal_connect()</TT>来决定事件发生时调用的处理函数。但是我们也需要让 GTK 知道我们想接收的事件。可以用如下函数:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">void gtk_widget_set_events (GtkWidget *widget, gint events);</PRE></TD></TR></TABLE><P>第二个参数为我们感兴趣的事件。它为不同类型事件的位或。事件类型的列表如下:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GDK_EXPOSURE_MASKGDK_POINTER_MOTION_MASKGDK_POINTER_MOTION_HINT_MASKGDK_BUTTON_MOTION_MASK GDK_BUTTON1_MOTION_MASK GDK_BUTTON2_MOTION_MASK GDK_BUTTON3_MOTION_MASK GDK_BUTTON_PRESS_MASK GDK_BUTTON_RELEASE_MASK GDK_KEY_PRESS_MASK GDK_KEY_RELEASE_MASK GDK_ENTER_NOTIFY_MASK GDK_LEAVE_NOTIFY_MASK GDK_FOCUS_CHANGE_MASK GDK_STRUCTURE_MASK GDK_PROPERTY_CHANGE_MASK GDK_PROXIMITY_IN_MASK GDK_PROXIMITY_OUT_MASK </PRE></TD></TR></TABLE><P>当调用函数<TTCLASS="LITERAL">gtk_widget_set_events()</TT>时,有几点需注意。首先,该函数必须在一个 GTK 构件的 X 窗口创建之前调用。实际上,意味者你应该在创建一个构件之后立即调用该函数。其次,构件必须有一个相关联的 X 窗口。为了提高效益,许多构件类型没有属于自己的窗口,它们绘制在父窗口上。这些构件是:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GtkAlignmentGtkArrowGtkBinGtkBoxGtkImageGtkItemGtkLabelGtkPixmapGtkScrolledWindowGtkSeparatorGtkTableGtkAspectFrameGtkFrameGtkVBoxGtkHBoxGtkVSeparatorGtkHSeparator</PRE></TD></TR></TABLE><P>为了捕获这些构件的事件,你需要使用事件盒构件。详见 <AHREF="c1289.html#SEC-EVENTBOX">事件盒</A>。</P><P>对于我们的绘图程序,我们想知道什么时候鼠标键按下和什么时候鼠标移动,因此我们要用<TTCLASS="LITERAL">GDK_POINTER_MOTION_MASK</TT>和<TTCLASS="LITERAL">GDK_BUTTON_PRESS_MASK</TT>。我们也想知道什么时候窗口需要重新绘制,因此我们也要用<TTCLASS="LITERAL">GDK_EXPOSURE_MASK</TT>。虽然我们也想在窗口尺寸改变时得到消息,不过我们不必用<TTCLASS="LITERAL">GDK_STRUCTURE_MASK</TT>标志,因为所有的窗口都自动设了该标志。</P><P>只用<TTCLASS="LITERAL">GDK_POINTER_MOTION_MASK</TT>是有问题的。这会使服务器在每次用户移动鼠标时向事件队列添加一个移动事件。假设处理一个移动事件需要0.1秒,但是X服务器每0.05秒添加一个新的移动事件。如果用户绘制要花5秒,那么在释放鼠标键后我们的程序会中断5秒!我们所需要的只是为我们处理的每个事件的获取一个移动事件。解决这个问题的方法是要用<TTCLASS="LITERAL">GDK_POINTER_MOTION_HINT_MASK</TT>。</P><P>当我们用<TTCLASS="LITERAL">GDK_POINTER_MOTION_HINT_MASK</TT>时,在指针进入我们的窗口之后、或在一个按钮按下或释放事件之后,服务器在指针首次移动时向我们发送一个移动事件。后发的移动事件都会被压制,直到我们用如下函数去获取鼠标指针的位置:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GdkWindow* gdk_window_get_pointer (GdkWindow *window, gint *x, gint *y, GdkModifierType *mask);</PRE></TD></TR></TABLE><P>(还有另外一个函数<TTCLASS="LITERAL">gtk_widget_get_pointer()</TT>,它有相似的接口,不过它不是很有用,因为它仅仅获取鼠标指针的位置,而不管按下了那个键。)</P><P>设置我们的窗口事件的代码如下:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", (GtkSignalFunc) expose_event, NULL); gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", (GtkSignalFunc) configure_event, NULL); gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", (GtkSignalFunc) motion_notify_event, NULL); gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", (GtkSignalFunc) button_press_event, NULL); gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);</PRE></TD></TR></TABLE><P>我们对在下一节讲解"expose_event"和"configure_event"的处理函数。"motion_notify_event"和"button_press_event"的处理函数很简单:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">static gintbutton_press_event (GtkWidget *widget, GdkEventButton *event){ if (event->button == 1 && pixmap != NULL) draw_brush (widget, event->x, event->y); return TRUE;}static gintmotion_notify_event (GtkWidget *widget, GdkEventMotion *event){ int x, y; GdkModifierType state; if (event->is_hint) gdk_window_get_pointer (event->window, &x, &y, &state); else { x = event->x; y = event->y; state = event->state; } if (state & GDK_BUTTON1_MASK && pixmap != NULL) draw_brush (widget, x, y); return TRUE;}</PRE></TD></TR></TABLE></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="c2370.html"ACCESSKEY="P"><<< Previous</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="book1.html"ACCESSKEY="H">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="x2418.html"ACCESSKEY="N">Next >>></A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">涂鸦板,一个简单的绘图程序</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="c2370.html"ACCESSKEY="U">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">绘图区构件和绘图</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -