📄 gtk_tut-20.html
字号:
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_user_data (widget->window, widget); gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);}</PRE></CODE></BLOCKQUOTE><P><H3>大小的设定</H3><P>在所有视窗被显示出来之前, GTK会先问每个子物件的大小.该事件是由<CODE>gtk_dial_size_request()</CODE>所处理的. 既然我们的物件不是container物件, 而且没什麽大小约束,就用个合理的数字就行了.<P><BLOCKQUOTE><CODE><PRE>static void gtk_dial_size_request (GtkWidget *widget, GtkRequisition *requisition){ requisition->width = DIAL_DEFAULT_SIZE; requisition->height = DIAL_DEFAULT_SIZE;}</PRE></CODE></BLOCKQUOTE><P><P>最後所有物件都有理想的大小.一般会尽可能用原定大小,但使用者会改变它的大小.大小的改变是由<CODE>gtk_dial_size_allocate()</CODE>. <P><BLOCKQUOTE><CODE><PRE>static voidgtk_dial_size_allocate (GtkWidget *widget, GtkAllocation *allocation){ GtkDial *dial; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_DIAL (widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) { dial = GTK_DIAL (widget); gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); dial->radius = MAX(allocation->width,allocation->height) * 0.45; dial->pointer_width = dial->radius / 5; }}</PRE></CODE></BLOCKQUOTE>.<P><H3><CODE>gtk_dial_expose()</CODE></H3><P>就如之前所提到的一样,所有物件的绘出都是由expose事件来处理.没什麽可多提的, 除了用<CODE>gtk_draw_polygon</CODE> 来画出三维阴影.<P><BLOCKQUOTE><CODE><PRE>static gintgtk_dial_expose (GtkWidget *widget, GdkEventExpose *event){ GtkDial *dial; GdkPoint points[3]; gdouble s,c; gdouble theta; gint xc, yc; gint tick_length; gint i; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (event->count > 0) return FALSE; dial = GTK_DIAL (widget); gdk_window_clear_area (widget->window, 0, 0, widget->allocation.width, widget->allocation.height); xc = widget->allocation.width/2; yc = widget->allocation.height/2; /* Draw ticks */ for (i=0; i<25; i++) { theta = (i*M_PI/18. - M_PI/6.); s = sin(theta); c = cos(theta); tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2; gdk_draw_line (widget->window, widget->style->fg_gc[widget->state], xc + c*(dial->radius - tick_length), yc - s*(dial->radius - tick_length), xc + c*dial->radius, yc - s*dial->radius); } /* Draw pointer */ s = sin(dial->angle); c = cos(dial->angle); points[0].x = xc + s*dial->pointer_width/2; points[0].y = yc + c*dial->pointer_width/2; points[1].x = xc + c*dial->radius; points[1].y = yc - s*dial->radius; points[2].x = xc - s*dial->pointer_width/2; points[2].y = yc - c*dial->pointer_width/2; gtk_draw_polygon (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, points, 3, TRUE); return FALSE;}</PRE></CODE></BLOCKQUOTE><P><H3>事件处理</H3><P><P>最後一段程式处理各种事件,跟我们之前所做的没有什麽太大的不同.有两种事件会发生, 使用者滑鼠的动作及其它因素所造成的物件参数调整. <P><P>当使用者在物件上按钮时, 我们检查是否靠近我们的指标,如果是, 将资料存到<CODE>button</CODE>一栏,并用<CODE>gtk_grab_add()</CODE>将所有滑鼠事件抓住. 接下来的滑鼠的动作将会被<CODE>gtk_dial_update_mouse</CODE>所接管.. 接下来就看我们是如何做的,"value_changed"事件可以用(<CODE>GTK_UPDATE_CONTINUOUS</CODE>)来产生, 或用<CODE>gtk_timeout_add()</CODE>来延迟一下(<CODE>GTK_UPDATE_DELAYED</CODE>), 或仅在按钮按下时反应(<CODE>GTK_UPDATE_DISCONTINUOUS</CODE>).<P><BLOCKQUOTE><CODE><PRE>static gintgtk_dial_button_press (GtkWidget *widget, GdkEventButton *event){ GtkDial *dial; gint dx, dy; double s, c; double d_parallel; double d_perpendicular; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); dial = GTK_DIAL (widget); /* Determine if button press was within pointer region - we do this by computing the parallel and perpendicular distance of the point where the mouse was pressed from the line passing through the pointer */ dx = event->x - widget->allocation.width / 2; dy = widget->allocation.height / 2 - event->y; s = sin(dial->angle); c = cos(dial->angle); d_parallel = s*dy + c*dx; d_perpendicular = fabs(s*dx - c*dy); if (!dial->button && (d_perpendicular < dial->pointer_width/2) && (d_parallel > - dial->pointer_width)) { gtk_grab_add (widget); dial->button = event->button; gtk_dial_update_mouse (dial, event->x, event->y); } return FALSE;}static gintgtk_dial_button_release (GtkWidget *widget, GdkEventButton *event){ GtkDial *dial; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); dial = GTK_DIAL (widget); if (dial->button == event->button) { gtk_grab_remove (widget); dial->button = 0; if (dial->policy == GTK_UPDATE_DELAYED) gtk_timeout_remove (dial->timer); if ((dial->policy != GTK_UPDATE_CONTINUOUS) && (dial->old_value != dial->adjustment->value)) gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); } return FALSE;}static gintgtk_dial_motion_notify (GtkWidget *widget, GdkEventMotion *event){ GtkDial *dial; GdkModifierType mods; gint x, y, mask; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); dial = GTK_DIAL (widget); if (dial->button != 0) { x = event->x; y = event->y; if (event->is_hint || (event->window != widget->window)) gdk_window_get_pointer (widget->window, &x, &y, &mods); switch (dial->button) { case 1: mask = GDK_BUTTON1_MASK; break; case 2: mask = GDK_BUTTON2_MASK; break; case 3: mask = GDK_BUTTON3_MASK; break; default: mask = 0; break; } if (mods & mask) gtk_dial_update_mouse (dial, x,y); } return FALSE;}static gintgtk_dial_timer (GtkDial *dial){ g_return_val_if_fail (dial != NULL, FALSE); g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE); if (dial->policy == GTK_UPDATE_DELAYED) gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); return FALSE;}static voidgtk_dial_update_mouse (GtkDial *dial, gint x, gint y){ gint xc, yc; gfloat old_value; g_return_if_fail (dial != NULL); g_return_if_fail (GTK_IS_DIAL (dial)); xc = GTK_WIDGET(dial)->allocation.width / 2; yc = GTK_WIDGET(dial)->allocation.height / 2; old_value = dial->adjustment->value; dial->angle = atan2(yc-y, x-xc); if (dial->angle < -M_PI/2.) dial->angle += 2*M_PI; if (dial->angle < -M_PI/6) dial->angle = -M_PI/6; if (dial->angle > 7.*M_PI/6.) dial->angle = 7.*M_PI/6.; dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) * (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.); if (dial->adjustment->value != old_value) { if (dial->policy == GTK_UPDATE_CONTINUOUS) { gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); } else { gtk_widget_draw (GTK_WIDGET(dial), NULL); if (dial->policy == GTK_UPDATE_DELAYED) { if (dial->timer) gtk_timeout_remove (dial->timer); dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, (GtkFunction) gtk_dial_timer, (gpointer) dial); } } }}static voidgtk_dial_update (GtkDial *dial){ gfloat new_value; g_return_if_fail (dial != NULL); g_return_if_fail (GTK_IS_DIAL (dial)); new_value = dial->adjustment->value; if (new_value < dial->adjustment->lower) new_value = dial->adjustment->lower; if (new_value > dial->adjustment->upper) new_value = dial->adjustment->upper; if (new_value != dial->adjustment->value) { dial->adjustment->value = new_value; gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); } dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. / (dial->adjustment->upper - dial->adjustment->lower); gtk_widget_draw (GTK_WIDGET(dial), NULL);}static voidgtk_dial_adjustment_changed (GtkAdjustment *adjustment, gpointer data){ GtkDial *dial; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); dial = GTK_DIAL (data); if ((dial->old_value != adjustment->value) || (dial->old_lower != adjustment->lower) || (dial->old_upper != adjustment->upper)) { gtk_dial_update (dial); dial->old_value = adjustment->value; dial->old_lower = adjustment->lower; dial->old_upper = adjustment->upper; }}static voidgtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data){ GtkDial *dial; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); dial = GTK_DIAL (data); if (dial->old_value != adjustment->value) { gtk_dial_update (dial); dial->old_value = adjustment->value; }}</PRE></CODE></BLOCKQUOTE><P><H3>有可能的增强之处</H3><P><P>这个Dial物件到目前为止有670行.这看起来好像有不少了,不过我们真正完成的只有一点点,因为大部份都是标头及模子.还是有许多可以加强的地方:<P><UL><LI> 如果您试过这个物件,您会发现滑鼠指标会一闪一闪的.这是因为整个物件每次都重画一次.当然了最好的方式是在offscreen pixmap上画完以後,然後整个复制到萤幕上.</LI><LI> 使用者应该可以用up及down按键来增加或减少其值.</LI><LI> 如果有个按钮来增加或减少其值, 那是再好不过的了.虽然可也以用embedded Button widgets来做,但我们会想要按钮有auto-repeat的功能.所有要做这一类功能的程式可以在GtkRange物件中发现.</LI><LI> 这个Dial物件可再做进一个container物件, 带有一个子物件, 位於按钮与最下面之间.使用者可以增加一个标签或整个物件来显示目前的值.</LI></UL><P><H2><A NAME="ss20.5">20.5 更多一点</A></H2><P>关於产生一个新的物件的细部资讯在以上被提供出来.如果您想要写一个属於自己的物件, 我想最好的范例就是GTK本身了.<P>问问您自己一些关於您想要写的物件:<PRE>它是否是个Container物件?它是否有自己的视窗?是否是个现有物件的修改?找出一个相近的物件, 然後开始动工.</PRE>祝好运!<P><H2><A NAME="ss20.6">20.6 版权</A></H2><P>This section on of the tutorial on writing widgets is Copyright (C) 1997 Owen Taylor<P>This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.<P>This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.<P>You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.<P><HR><A HREF="gtk_tut-19.html" tppabs="http://extend.hk.hi.cn/%7ehusuyu/http/beginner/gtk/gtk_tut-19.html"><IMG SRC="prev.gif" tppabs="http://extend.hk.hi.cn/%7ehusuyu/http/beginner/gtk/prev.gif" ALT="Previous"></A><A HREF="gtk_tut-21.html" tppabs="http://extend.hk.hi.cn/%7ehusuyu/http/beginner/gtk/gtk_tut-21.html"><IMG SRC="next.gif" tppabs="http://extend.hk.hi.cn/%7ehusuyu/http/beginner/gtk/next.gif" ALT="Next"></A><A HREF="gtk_tut.html#toc20" tppabs="http://extend.hk.hi.cn/%7ehusuyu/http/beginner/gtk/gtk_tut.html#toc20"><IMG SRC="toc.gif" tppabs="http://extend.hk.hi.cn/%7ehusuyu/http/beginner/gtk/toc.gif" ALT="Contents"></A></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -