⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gtk_tut-22.html

📁 gtk是linux一款强大的夸平台的图形化开发工具
💻 HTML
📖 第 1 页 / 共 3 页
字号:
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);}</PRE></CODE></BLOCKQUOTE><P><H3>Size negotiation</H3><P>Before the first time that the window containing a widget isdisplayed, and whenever the layout of the window changes, GTK askseach child widget for its desired size. This request is handled by thefunction, <CODE>gtk_dial_size_request()</CODE>. Since our widget isn't acontainer widget, and has no real constraints on its size, we justreturn a reasonable default value.<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>After all the widgets have requested an ideal size, the layout of thewindow is computed and each child widget is notified of its actualsize. Usually, this will at least as large as the requested size, butif for instance, the user has resized the window, it may occasionallybe smaller than the requested size. The size notification is handledby the function <CODE>gtk_dial_size_allocate()</CODE>. Notice that as well ascomputing the sizes of some component pieces for future use, thisroutine also does the grunt work of moving the widgets X window intothe new position and size.<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>As mentioned above, all the drawing of this widget is done in thehandler for expose events. There's not much to remark on here exceptthe use of the function <CODE>gtk_draw_polygon</CODE> to draw the pointer withthree dimensional shading according to the colors stored in thewidget's style.<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&lt;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>Event handling</H3><P>The rest of the widget's code handles various types of events, andisn't too different from what would be found in many GTKapplications. Two types of events can occur - either the user canclick on the widget with the mouse and drag to move the pointer, orthe value of the Adjustment object can change due to some externalcircumstance. <P>When the user clicks on the widget, we check to see if the click wasappropriately near the pointer, and if so, store then button that theuser clicked with in the <CODE>button</CODE> field of the widgetstructure, and grab all mouse events with a call to<CODE>gtk_grab_add()</CODE>. Subsequent motion of the mouse causes thevalue of the control to be recomputed (by the function<CODE>gtk_dial_update_mouse</CODE>). Depending on the policy that has beenset, "value_changed" events are either generated instantly(<CODE>GTK_UPDATE_CONTINUOUS</CODE>), after a delay in a timer added with<CODE>gtk_timeout_add()</CODE> (<CODE>GTK_UPDATE_DELAYED</CODE>), or only when thebutton is released (<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 &amp;&amp;      (d_perpendicular &lt; dial->pointer_width/2) &amp;&amp;      (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) &amp;&amp;          (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, &amp;x, &amp;y, &amp;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 &amp; 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 &lt; -M_PI/2.)    dial->angle += 2*M_PI;  if (dial->angle &lt; -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);            }        }    }}</PRE></CODE></BLOCKQUOTE><P>Changes to the Adjustment by external means are communicated to ourwidget by the `changed' and `value_changed' signals. The handlersfor these functions call <CODE>gtk_dial_update()</CODE> to validate thearguments, compute the new pointer angle, and redraw the widget (bycalling <CODE>gtk_widget_draw()</CODE>).<P><BLOCKQUOTE><CODE><PRE>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 &lt; 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>Possible Enhancements</H3><P>The Dial widget as we've described it so far runs about 670 lines ofcode. Although that might sound like a fair bit, we've reallyaccomplished quite a bit with that much code, especially since much ofthat length is headers and boilerplate. However, there are quite a fewmore enhancements that could be made to this widget:<P><UL><LI> If you try this widget out, you'll find that there is someflashing as the pointer is dragged around. This is because the entirewidget is erased every time the pointer is moved before beingredrawn. Often, the best way to handle this problem is to draw to anoffscreen pixmap, then copy the final results onto the screen in onestep. (The ProgressBar widget draws itself in this fashion.)</LI><LI> The user should be able to use the up and down arrow keys toincrease and decrease the value.</LI><LI> It would be nice if the widget had buttons to increase anddecrease the value in small or large steps. Although it would bepossible to use embedded Button widgets for this, we would also likethe buttons to auto-repeat when held down, as the arrows on ascrollbar do. Most of the code to implement this type of behavior canbe found in the GtkRange widget.</LI><LI> The Dial widget could be made into a container widget with asingle child widget positioned at the bottom between the buttonsmentioned above. The user could then add their choice of a label orentry widget to display the current value of the dial.</LI></UL><P><H2><A NAME="ss22.5">22.5 Learning More</A></H2><P>Only a small part of the many details involved in creating widgetscould be described above. If you want to write your own widgets, thebest source of examples is the GTK source itself. Ask yourself somequestions about the widget you want to write: is it a Containerwidget? does it have its own window? is it a modification of anexisting widget? Then find a similar widget, and start making changes.Good luck!<P><HR NOSHADE><A HREF="gtk_tut-23.html">Next</A><A HREF="gtk_tut-21.html">Previous</A><A HREF="gtk_tut.html#toc22">Contents</A></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -