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

📄 gtk_tut_it-20.html

📁 gtk是linux一款强大的夸平台的图形化开发工具
💻 HTML
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD> <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9"> <TITLE>GTK Tutorial: Scribble, Un semplice esempio di Programma di Disegno</TITLE> <LINK HREF="gtk_tut_it-21.html" REL=next> <LINK HREF="gtk_tut_it-19.html" REL=previous> <LINK HREF="gtk_tut_it.html#toc20" REL=contents></HEAD><BODY BGCOLOR="#FFFFFF"><A HREF="gtk_tut_it-21.html">Avanti</A><A HREF="gtk_tut_it-19.html">Indietro</A><A HREF="gtk_tut_it.html#toc20">Indice</A><HR NOSHADE><H2><A NAME="s20">20. Scribble, Un semplice esempio di Programma di Disegno</A></H2><H2><A NAME="ss20.1">20.1 Panoramica</A></H2><P>In questa sezione, creeremo un semplice programma di disegno. Durantequesto processo, esamineremo come gestire gli eventi generati dal mouse,come disegnare all'interno di una finestra e come disegnare in modo miglioreusando una pixmap di supporto. Dopo averlo creato, lo amplieremo aggiungendoil supporto per i dispositivi XInput, per esempio le tavolette grafiche.Il GTK fornisce delle routine di supporto grazie alle quali risulta  piuttostosemplice ottenere informazioni estese, come la pressione o l'inclinazione.<P><H2><A NAME="ss20.2">20.2 Gestione degli Eventi</A></H2><P>I segnali di GTK che abbiamo discusso finora si riferivano ad azioni dialto livello, ad esempio la selezione di un elemento di un men&ugrave;. Per&ograve;, a volte&egrave; utile sapere qualcosa su cose che si svolgono a livello pi&ugrave; basso livello,come possono essere il movimento del mouse o la pressione di un tasto.Ci sono segnali di GTK anche per questi <EM>eventi</EM> di basso livello.I gestori di questo tipo di segnali hanno un parametro caratteristico in pi&ugrave;,che &egrave; il puntatore ad una struttura che contiene informazioni riguardoall'evento. Per esempio, ai gestori di eventi che riguardano dei movimenti,si passa un puntatore ad una struttura GdkEventMotion, che &egrave; fatta (in parte)cos&igrave;:<P><BLOCKQUOTE><CODE><PRE>struct _GdkEventMotion{  GdkEventType type;  GdkWindow *window;  guint32 time;  gdouble x;  gdouble y;  ...  guint state;  ...};</PRE></CODE></BLOCKQUOTE><P><CODE>type</CODE> avr&agrave; il valore del tipo di evento, in questo caso <CODE>GDK_MOTION_NOTIFY</CODE>, <CODE>window</CODE> rappresenta la finestra in cui l'eventosi &egrave; verificato. <CODE>x</CODE> e <CODE>y</CODE> forniscono le coordinate dell'evento e<CODE>state</CODE> specifica lo stato dei modificatori nel momento in cui l'eventosi &egrave; verificato (cio&egrave;, specifica quali tasti modificatori e tasti del mouseerano premuti in quel momento). E' un OR bit per bit dei seguenti valori:<P><BLOCKQUOTE><CODE><PRE>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></CODE></BLOCKQUOTE><P><P>Come succede per gli altri segnali, per determinare cosa deve accadere incorrispondenza di un evento, si chiama <CODE>gtk_signal_connect()</CODE>. Ma&egrave; anche necessario far s&igrave; che GTK sappia di quali eventi vogliamo essereinformati. A questo fine, chiamiamo la funzione:<P><BLOCKQUOTE><CODE><PRE>void  gtk_widget_set_events (GtkWidget *widget, gint events);</PRE></CODE></BLOCKQUOTE><P>Il secondo campo specifica gli eventi che ci interessano. Si tratta dell'ORbit per bit delle costanti che identificano i diversi tipi di eventi. La listadei tipi di eventi &egrave; la seguente:<P><BLOCKQUOTE><CODE><PRE>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></CODE></BLOCKQUOTE><P>Per chiamare <CODE>gtk_widget_set_events()</CODE>, si devono fare alcune osservazionisottili. In primo luogo, la si deve chiamare prima che sia stata creata lafinestra X per il widget GTK. In pratica, ci&ograve; significa che la si devechiamare subito dopo aver creato il widget. In secondo luogo, il widgetdeve avere una finestra X associata. Molti widget, per ragioni diefficienza, non hanno una propria finetra, e vengono mostrati nellafinestra madre. Questi widget sono:<P><BLOCKQUOTE><CODE><PRE>GtkAlignmentGtkArrowGtkBinGtkBoxGtkImageGtkItemGtkLabelGtkPixmapGtkScrolledWindowGtkSeparatorGtkTableGtkAspectFrameGtkFrameGtkVBoxGtkHBoxGtkVSeparatorGtkHSeparator</PRE></CODE></BLOCKQUOTE><P>Per catturare degli eventi per questo tipo di widget, si deve fare uso del widget EventBox. Si veda a questo proposito la sezione su<A HREF="gtk_tut_it-13.html#sec_The_EventBox_Widget">The EventBox Widget</A>.<P><P>Per il nostro programma di disegno, vogliamo sapere quando il pulsante delmouse &egrave; premuto e quando viene mosso, quindi specificheremo<CODE>GDK_POINTER_MOTION_MASK</CODE> e <CODE>GDK_BUTTON_PRESS_MASK</CODE>. Vogliamo ancheessere informati su quando &egrave; necessario ridisegnare la nostra finestra,quindi specifichiamo <CODE>GDK_EXPOSURE_MASK</CODE>. Anche se vogliamo essereavvertiti con un evento ``Configure'' se la dimensione della nostra finestracambia, non &egrave; necessario specificare il flag <CODE>GDK_STRUCTURE_MASK</CODE>, dalmomento che questo viene specificato automaticamente per tutte le finestre.<P><P>Risulta, conunque, che specificando semplicemente <CODE>GDK_POINTER_MOTION_MASK</CODE>si crea un problema. Ci&ograve; infatti fa s&igrave; che il server aggiunga nella coda unun nuovo evento di movimento ogni volta che l'utente muovoe il mouse. Immaginateche ci vogliano 0.1 secondi per gestire uno di questi eventi, e che il serverX metta in coda un nuovo evento ogni 0.05 secondi. Rimarremo ben presto indietrorispetto al disegno dell'utente. Se l'utente disegna per 5 secondi, ci metteremmoaltri 5 secondi prima di finire dopo che l'utente ha rilasciato il pulsante delmouse! Vorremmo quindi che venga notificato un solo evento di movimento perogni evento che processiamo. Il modo per farlo &egrave; di specificare <CODE>GDK_POINTER_MOTION_HINT_MASK</CODE>. <P><P>Quando specifichiamo <CODE>GDK_POINTER_MOTION_HINT_MASK</CODE>, il server ci notificaun evento di movimento la prima volta che il puntatore si muove dopo essereentrato nella nostra finestra, oppure dopo ogni rilascio di un pulsante delmouse. Gli altri eventi di movimento verranno soppressi finch&eacute; non richiediamoesplicitamente la posizione del puntatore con la funzione:<P><BLOCKQUOTE><CODE><PRE>GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,                                          gint            *x,                                          gint            *y,                                          GdkModifierType *mask);</PRE></CODE></BLOCKQUOTE><P>(c'&egrave; anche un'altra funzione, <CODE>gtk_widget_get_pointer()</CODE>, che haun'interfaccia pi&ugrave; semplice, ma che non risulta molto utile dal momentoche restituisce solo la posizione del puntatore, senza dettagli sullosato dei pulsanti.)<P><P>Quindi, il codice per assegnare gli eventi per la nostra finestra, avr&agrave; l'aspetto:<P><BLOCKQUOTE><CODE><PRE>  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></CODE></BLOCKQUOTE><P>Teniamo per dopo i gestori di  ``expose_event'' e  ``configure_event''. Quelli di``motion_notify_event'' e ``button_press_event'' sono piuttosto semplici: <P><BLOCKQUOTE><CODE><PRE>static gintbutton_press_event (GtkWidget *widget, GdkEventButton *event){  if (event->button == 1 &amp;&amp; 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, &amp;x, &amp;y, &amp;state);  else    {      x = event->x;      y = event->y;      state = event->state;    }      if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)    draw_brush (widget, x, y);    return TRUE;}</PRE></CODE></BLOCKQUOTE><P><H2><A NAME="ss20.3">20.3 Il widget Area di Disegno (DrawingArea) e il procedimento per Disegnare</A></H2><P>Vediamo ora il procedimento per disegnare sullo schermo. Ilwidget da usare &egrave; l'Area di Disegno (DrawingArea). Essenzialmente sitratta di una finestra X e nient'altro. E' una tela bianca su cui possimodisegnare tutto quello che vogliamo. Per crearne una usiamo la chiamata:<P><BLOCKQUOTE><CODE><PRE>GtkWidget* gtk_drawing_area_new        (void);</PRE></CODE></BLOCKQUOTE><P>Per specificare una dimensione predefinita, si puo fare:<P><BLOCKQUOTE><CODE><PRE>void       gtk_drawing_area_size       (GtkDrawingArea      *darea,                                        gint                 width,                                        gint                 height);</PRE></CODE></BLOCKQUOTE><P>Come &egrave; vero per tutti i widget, si pu&ograve; modificare questa dimensionepredefinita, tramite la chamata a <CODE>gtk_widget_set_usize()</CODE>, equesta a sua volta pu&ograve; essere modificata dall'utente ridimensionandomanualmente la finestra che contiene l'area di disegno.<P><P>Si deve notare che nel momento in cui creiamo un widget DrawingArea, siamo<EM>completamente</EM> responsabili di disegnarne il contenuto. Se ad esempio la nostra finestra viene prima nascosta e poi dinuovo portata inprimo piano, otteniamo un evento di ``esposizione'' e doppiamo ridisegnareci&ograve; che era stato precedente nascosto.<P><P>Dover ricordare tutto quello che era disegnato sulla finestra in modo dapoterlo ridisegnare successivamente, pu&ograve; essere, come minimo, noioso.In pi&ugrave;, pu&ograve; essere spiacevole dal punto di vista visivo, se delle porzionidello schermo vengono prima cancellate e poi ridisegnate passo per passo.La soluzione per questo problema &egrave; di usare una <EM>pixmap di supporto</EM>.Invece di disegnare direttamente sullo schermo, disegnamo su un'iimagineconservata nella memoria del server ma che non viene mostrata; quindi, quandol'immagine cambia o ne vengono mostrate nuove porzioni, copiamo sullo schermo

⌨️ 快捷键说明

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