1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="highlight.min.css">
<script src="highlight.min.js"></script><script>
hljs.configure({languages: ['cpp']});
hljs.highlightAll();
</script><title>Chapter 18. The DrawingArea Widget</title>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="index.html" title="Programming with gtkmm 4">
<link rel="up" href="index.html" title="Programming with gtkmm 4">
<link rel="prev" href="sec-dialogs-windowdialog.html" title="Custom Dialog">
<link rel="next" href="sec-cairo-drawing-lines.html" title="Drawing Straight Lines">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">Chapter 18. The DrawingArea Widget</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="sec-dialogs-windowdialog.html"><img src="icons/prev.png" alt="Prev"></a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="sec-cairo-drawing-lines.html"><img src="icons/next.png" alt="Next"></a>
</td>
</tr>
</table>
<hr>
</div>
<div class="chapter">
<div class="titlepage"><div><div><h1 class="title">
<a name="chapter-drawingarea"></a>Chapter 18. The DrawingArea Widget</h1></div></div></div>
<div class="toc">
<p><b>Table of Contents</b></p>
<ul class="toc">
<li><span class="section"><a href="chapter-drawingarea.html#sec-cairo-drawing-model">The Cairo Drawing Model</a></span></li>
<li><span class="section"><a href="sec-cairo-drawing-lines.html">Drawing Straight Lines</a></span></li>
<li><span class="section"><a href="sec-cairo-curved-lines.html">Drawing Curved Lines</a></span></li>
<li><span class="section"><a href="sec-cairo-drawing-arcs.html">Drawing Arcs and Circles</a></span></li>
<li><span class="section"><a href="sec-drawing-text.html">Drawing Text</a></span></li>
<li><span class="section"><a href="sec-draw-images.html">Drawing Images</a></span></li>
<li><span class="section"><a href="sec-drawing-clock-example.html">Example Application: Creating a Clock with Cairo</a></span></li>
</ul>
</div>
<p>
The <code class="classname">DrawingArea</code> widget is a blank window that gives
you the freedom to create any graphic you desire. Along with that freedom
comes the responsibility to draw on the widget. When a
widget is first shown, or when it is covered and then uncovered again it
needs to redraw itself. Most widgets have code to do this, but the
<code class="classname">DrawingArea</code> does not, allowing you to write your own
draw function to determine how the contents of the widget will be drawn.
This is done by setting a draw function with a call to the
<code class="methodname">set_draw_func()</code> member function.
</p>
<p>
GTK uses the <a class="ulink" href="http://cairographics.org" target="_top">Cairo</a> drawing API.
With <span class="application">gtkmm</span>, you may use the <a class="ulink" href="http://www.cairographics.org/cairomm/" target="_top">cairomm</a> C++ API for cairo.
</p>
<p>
You can draw very sophisticated shapes using Cairo, but the methods to do
so are quite basic. Cairo provides methods for drawing straight lines,
curved lines, and arcs (including circles). These basic shapes can be
combined to create more complex shapes and paths which can be filled with
solid colors, gradients, patterns, and other things. In addition, Cairo
can perform complex transformations, do compositing of images, and render
antialiased text.
</p>
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note: Cairo and Pango">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="icons/note.png"></td>
<th align="left">Cairo and Pango</th>
</tr>
<tr><td align="left" valign="top">
<p>Although Cairo can render text, it's not meant to be a replacement for
Pango. Pango is a better choice if you need to perform more advanced
text rendering such as wrapping or ellipsizing text. Drawing text with
Cairo should only be done if the text is part of a graphic.</p>
</td></tr>
</table></div>
<p>
In this section of the tutorial, we'll cover the basic Cairo drawing
model, describe each of the basic drawing elements in some detail (with
examples), and then present a simple application that uses Cairo to draw
a custom clock widget.
</p>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="sec-cairo-drawing-model"></a>The Cairo Drawing Model</h2></div></div></div>
<p>
The basic concept of drawing in Cairo involves defining 'invisible'
paths and then stroking or filling them to make them visible.
</p>
<p>
To do any drawing in <span class="application">gtkmm</span> with Cairo, you must first get a
<code class="classname">Cairo::Context</code> object. This class holds all of the graphics state parameters that
describe how drawing is to be done. This includes information such as
line width, color, the surface to draw to, and many other things. This
allows the actual drawing functions to take fewer arguments to simplify
the interface. Usually, you use the <code class="classname">Cairo::Context</code>
that you get as input data to the draw function that you set with the call to
<code class="methodname">set_draw_func()</code>. It's also possible to create
a <code class="classname">Cairo::Context</code> by calling the
<code class="methodname">Gdk::Surface::create_cairo_context()</code> and
<code class="methodname">Gdk::CairoContext::cairo_create()</code> functions.
Since Cairo contexts are reference-counted objects, <code class="methodname">cairo_create()</code>
returns a <code class="classname">Cairo::RefPtr<Cairo::Context></code> object.
(Note the difference between <code class="classname">Gdk::CairoContext</code>
and <code class="classname">Cairo::Context</code>.)
</p>
<p>
The following example shows how to set up a Cairo context with a
foreground color of red and a width of 2. Any drawing functions that
use this context will use these settings.
</p>
<pre class="programlisting"><code class="code">Gtk::DrawingArea myArea;
auto gdkCairoContext = myArea.get_surface()->create_cairo_context();
auto myContext = gdkCairoContext->cairo_create();
myContext->set_source_rgb(1.0, 0.0, 0.0);
myContext->set_line_width(2.0);
</code></pre>
<p>
Each <code class="classname">Cairo::Context</code> is associated with a
particular <code class="classname">Gdk::Surface</code>, so the first line of the
above example creates a <code class="classname">Gtk::DrawingArea</code> widget
and the next two lines use its associated <code class="classname">Gdk::Surface</code>
to create a <code class="classname">Cairo::Context</code> object. The final
two lines change the graphics state of the context.
</p>
<p>
There are a number of graphics state variables that can be set for a
Cairo context. The most common context attributes are color (using
<code class="methodname">set_source_rgb()</code> or
<code class="methodname">set_source_rgba()</code> for translucent colors), line
width (using <code class="methodname">set_line_width()</code>), line dash pattern
(using <code class="methodname">set_dash()</code>), line cap style (using
<code class="methodname">set_line_cap()</code>), and line join style (using
<code class="methodname">set_line_join()</code>), and font styles (using
<code class="methodname">set_font_size()</code>,
<code class="methodname">set_font_face()</code> and others).
There are many other settings as well, such as transformation matrices,
fill rules, whether to perform antialiasing, and others. For further
information, see the <a class="ulink" href="http://www.cairographics.org/cairomm/" target="_top">cairomm</a> API documentation.
</p>
<p>
The current state of a <code class="classname">Cairo::Context</code> can be
saved to an internal stack of saved states and later be restored to the
state it was in when you saved it. To do this, use the
<code class="methodname">save()</code>
method and the <code class="methodname">restore()</code> method. This can be
useful if you need to temporarily change the line width and color (or
any other graphics setting) in order to draw something and then return
to the previous settings. In this situation, you could call
<code class="methodname">Cairo::Context::save()</code>, change the graphics
settings, draw the lines, and then call
<code class="methodname">Cairo::Context::restore()</code> to restore the original
graphics state. Multiple calls to <code class="methodname">save()</code> and
<code class="methodname">restore()</code> can be nested; each call to
<code class="methodname">restore()</code> restores the state from the
matching paired <code class="methodname">save()</code>.
</p>
<div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="icons/tip.png"></td>
<th align="left">Tip</th>
</tr>
<tr><td align="left" valign="top">
<p>It is good practice to put all modifications to the graphics state
between <code class="methodname">save()</code>/<code class="methodname">restore()</code>
function calls. For example, if you have a function that takes a
<code class="classname">Cairo::Context</code> reference as an argument, you
might implement it as follows:
</p>
<pre class="programlisting"><code class="code">void doSomething(const Cairo::RefPtr<Cairo::Context>& context, int x)
{
context->save();
// change graphics state
// perform drawing operations
context->restore();
}</code></pre>
</td></tr>
</table></div>
<p>
</p>
<p>
The draw function that you set with a call to <code class="methodname">set_draw_func()</code>
is called with a Cairo context that you shall use for drawing in the
<code class="classname">Gtk::DrawingArea</code> widget. It is not necessary to
save and restore this Cairo context in the draw function.
</p>
</div>
</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="sec-dialogs-windowdialog.html"><img src="icons/prev.png" alt="Prev"></a> </td>
<td width="20%" align="center"> </td>
<td width="40%" align="right"> <a accesskey="n" href="sec-cairo-drawing-lines.html"><img src="icons/next.png" alt="Next"></a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Custom Dialog </td>
<td width="20%" align="center"><a accesskey="h" href="index.html"><img src="icons/home.png" alt="Home"></a></td>
<td width="40%" align="right" valign="top"> Drawing Straight Lines</td>
</tr>
</table>
</div>
</body>
</html>
|