]>
Commit | Line | Data |
---|---|---|
1 | \chapter{Drawing on device contexts}\label{chapdrawing} | |
2 | \pagenumbering{arabic}% | |
3 | \setheader{{\it CHAPTER \thechapter: DRAWING ON DEVICE CONTEXTS}}{}{}{}{}{{\it CHAPTER \thechapter: DRAWING ON DEVICE CONTEXTS}}% | |
4 | \setfooter{\thepage}{}{}{}{}{\thepage}% | |
5 | ||
6 | \section{The concept of device contexts} | |
7 | ||
8 | Device contexts, commonly referred as DCs, represent more or less anything | |
9 | you can draw into, i.e. a window, a bitmap, the screen, a printer, a Postscript | |
10 | file, most recently even an SVG file. There is one abstract base class (wxDC) | |
11 | which defines the interface for all other classes so that drawing code for | |
12 | one device context can be used for all others as well - with certain limitation | |
13 | as the hardware specifies (e.g. you cannot read a pixel from a printer). | |
14 | ||
15 | \section{Drawing into windows} | |
16 | ||
17 | Let's start with the most simple case: you want to draw a line in a window. | |
18 | Or rather not the window, but its client area, the usually white or grey | |
19 | large area that is surrounded by the window's decorations such as its border | |
20 | which you normally would not want to draw over. | |
21 | ||
22 | In addition to defining classes that represent devices, wxWindows has a few | |
23 | of classes that define colours and so-called pens and brushes. A pen is used | |
24 | for drawing lines (which can be a curve or a rectangle) whereas brushes are | |
25 | used to paint areas, such as a filled rectangle or a filled circle. Indeed, | |
26 | you can use both at the same time for drawing a rectangle which is both filled | |
27 | and has a border. If you want to draw a red rectangle with a black border, | |
28 | you will do this: | |
29 | ||
30 | \begin{verbatim} | |
31 | void MyWindow::DrawSomething() | |
32 | { | |
33 | wxClientDC dc(this); | |
34 | ||
35 | dc.SetPen( *wxBLACK_PEN ); | |
36 | dc.SetBrush( *wxRED_BRUSH ); | |
37 | ||
38 | dc.DrawRectangle( 0, 0, 100, 100 ); | |
39 | } | |
40 | \end{verbatim} | |
41 | ||
42 | If you want to draw a rectangle without any border, you can use the special | |
43 | oen wxTRANSPARENT_PEN, if the rectangle is not supposed to be filled with | |
44 | any colour, you use the special brush wxTRANSPARENT_BRUSH. When using both | |
45 | these special classes, you could draw an invisible rectangle like this: | |
46 | ||
47 | \begin{verbatim} | |
48 | void MyWindow::DrawNothing() | |
49 | { | |
50 | wxClientDC dc(this); | |
51 | ||
52 | dc.SetPen( *wxTRANSPARENT_PEN ); | |
53 | dc.SetBrush( *wxTRANSPARENT_BRUSH ); | |
54 | ||
55 | dc.DrawRectangle( 0, 0, 100, 100 ); | |
56 | } | |
57 | \end{verbatim} | |
58 | ||
59 | Now what happens when you window gets obscured by another window and | |
60 | then returns to the surface again? The rectangle will not appear again | |
61 | because a window does not remember what has been drawn into it. Instead, | |
62 | your program has to remember what to draw and where and it will receive | |
63 | a so called wxPaintEvent indicating that some region has been unobscured | |
64 | and needs repainting. In order to catch such an event so that you can | |
65 | react appropriately to it, you will have to set up an event handler | |
66 | like this: | |
67 | ||
68 | \begin{verbatim} | |
69 | BEGIN_EVENT_TABLE(MyWindow, wxWindow) | |
70 | EVT_PAINT (MyWindow::OnPaint) | |
71 | END_EVENT_TABLE() | |
72 | ||
73 | void MyWindow::OnPaint( wxPaintEvent &event ) | |
74 | { | |
75 | wxPaintDC dc(this); | |
76 | ||
77 | dc.SetPen( *wxBLACK_PEN ); | |
78 | dc.SetBrush( *wxRED_BRUSH ); | |
79 | ||
80 | dc.DrawRectangle( 0, 0, 100, 100 ); | |
81 | } | |
82 | \end{verbatim} | |
83 | ||
84 | Note that this time, you have to use a wxPaintDC as these are used | |
85 | in connection with wxPaintEvents. Note also, that every such handler | |
86 | has to use a wxPaintDC even of you (for the moment) don't draw anything. | |
87 | If there is no such wxPaintDC, your program will not work under Windows. | |
88 | ||
89 | One difference between a wxPaintDC and a wxClientDC is that the wxPaintDC | |
90 | always sets a clipping region to the region of the window that was | |
91 | unobscured with the effect that all drawing commands will be clipped to | |
92 | that region. This leads to a reduction of flicker as only those | |
93 | areas of the window get redrawn, which actually need to get redrawn. | |
94 | ||
95 | \section{Querying the update region} | |
96 | ||
97 | Call me lazy: | |
98 | ||
99 | \begin{verbatim} | |
100 | BEGIN_EVENT_TABLE(MyWindow, wxWindow) | |
101 | EVT_PAINT (MyWindow::OnPaint) | |
102 | END_EVENT_TABLE() | |
103 | ||
104 | void MyWindow::OnPaint( wxPaintEvent &event ) | |
105 | { | |
106 | wxPaintDC dc(this); | |
107 | ||
108 | if (IsExposed( 0, 0, 100, 100)) | |
109 | { | |
110 | dc.SetPen( *wxBLACK_PEN ); | |
111 | dc.SetBrush( *wxRED_BRUSH ); | |
112 | ||
113 | dc.DrawRectangle( 0, 0, 100, 100 ); | |
114 | } | |
115 | } | |
116 | \end{verbatim} | |
117 | ||
118 |