]>
Commit | Line | Data |
---|---|---|
1 | \section{wxRichTextCtrl overview}\label{wxrichtextctrloverview} | |
2 | ||
3 | Classes: \helpref{wxRichTextCtrl}{wxrichtextctrl}, \helpref{wxRichTextBuffer}{wxrichtextbuffer}, | |
4 | \helpref{wxRichTextAttr}{wxrichtextattr}, \helpref{wxTextAttrEx}{wxtextattrex}, | |
5 | \helpref{wxRichTextCharacterStyleDefinition}{wxrichtextcharacterstyledefinition}, | |
6 | \helpref{wxRichTextParagraphStyleDefinition}{wxrichtextparagraphstyledefinition}, | |
7 | \helpref{wxRichTextStyleSheet}{wxrichtextstylesheet}, | |
8 | \helpref{wxRichTextStyleListBox}{wxrichtextstylelistbox}, | |
9 | \helpref{wxRichTextEvent}{wxrichtextevent}, \helpref{wxRichTextRange}{wxrichtextrange}, | |
10 | \helpref{wxRichTextFileHandler}{wxrichtextfilehandler}, \helpref{wxRichTextHTMLHandler}{wxrichtexthtmlhandler}, | |
11 | \helpref{wxRichTextXMLHandler}{wxrichtextxmlhandler} | |
12 | ||
13 | wxRichTextCtrl provides a generic implementation of a rich text editor that can handle different character | |
14 | styles, paragraph formatting, and images. It's aimed at editing 'natural' language text - if you need an editor that supports code editing, | |
15 | wxStyledTextCtrl is a better choice. | |
16 | ||
17 | Despite its name, it cannot currently read or write RTF (rich text format) files. Instead, it | |
18 | uses its own XML format, and can also read and write plain text. In future we expect to provide | |
19 | RTF file capabilities. Custom file formats can be supported by creating additional | |
20 | file handlers and registering them with the control. | |
21 | ||
22 | wxRichTextCtrl is largely compatible with the wxTextCtrl API, but extends it where necessary. | |
23 | The control can be used where the native rich text capabilities of wxTextCtrl are not | |
24 | adequate (this is particularly true on Windows) and where more direct access to | |
25 | the content representation is required. It is difficult and inefficient to read | |
26 | the style information in a wxTextCtrl, whereas this information is readily | |
27 | available in wxRichTextCtrl. Since it's written in pure wxWidgets, any customizations | |
28 | you make to wxRichTextCtrl will be reflected on all platforms. | |
29 | ||
30 | There are of course a few disadvantages to using wxRichTextCtrl. It is not native, | |
31 | so does not behave exactly as a native wxTextCtrl, although common editing conventions | |
32 | are followed. Users may miss the built-in spelling correction on Mac OS X, or any | |
33 | special character input that may be provided by the native control. It would also | |
34 | be a bad choice if intended users rely on screen readers that would be unhappy | |
35 | with non-native text input implementation. You might mitigate this by providing | |
36 | the choice between wxTextCtrl and wxRichTextCtrl, with fewer features in the | |
37 | former case. | |
38 | ||
39 | wxRichTextCtrl does not yet support printing directly, but content can be converted | |
40 | to HTML which can then be used with \helpref{wxHtmlEasyPrinting}{wxhtmleasyprinting}. | |
41 | ||
42 | The following screenshot shows the wxRichTextCtrl sample in action: | |
43 | ||
44 | $$\image{8cm;0cm}{richtextctrl.gif}$$ | |
45 | ||
46 | \wxheading{Example}\label{wxrichtextctrlexample} | |
47 | ||
48 | The following code is taken from the sample, and adds text and styles to a rich text control programmatically. | |
49 | ||
50 | {\small | |
51 | \begin{verbatim} | |
52 | wxRichTextCtrl* richTextCtrl = new wxRichTextCtrl(splitter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS); | |
53 | ||
54 | wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL); | |
55 | wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD); | |
56 | wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL); | |
57 | ||
58 | wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL); | |
59 | ||
60 | m_richTextCtrl->SetFont(font); | |
61 | ||
62 | wxRichTextCtrl& r = richTextCtrl; | |
63 | ||
64 | r.BeginSuppressUndo(); | |
65 | ||
66 | r.BeginParagraphSpacing(0, 20); | |
67 | ||
68 | r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE); | |
69 | r.BeginBold(); | |
70 | ||
71 | r.BeginFontSize(14); | |
72 | r.WriteText(wxT("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images")); | |
73 | r.EndFontSize(); | |
74 | r.Newline(); | |
75 | ||
76 | r.BeginItalic(); | |
77 | r.WriteText(wxT("by Julian Smart")); | |
78 | r.EndItalic(); | |
79 | ||
80 | r.EndBold(); | |
81 | ||
82 | r.Newline(); | |
83 | r.WriteImage(wxBitmap(zebra_xpm)); | |
84 | ||
85 | r.EndAlignment(); | |
86 | ||
87 | r.Newline(); | |
88 | r.Newline(); | |
89 | ||
90 | r.WriteText(wxT("What can you do with this thing? ")); | |
91 | r.WriteImage(wxBitmap(smiley_xpm)); | |
92 | r.WriteText(wxT(" Well, you can change text ")); | |
93 | ||
94 | r.BeginTextColour(wxColour(255, 0, 0)); | |
95 | r.WriteText(wxT("colour, like this red bit.")); | |
96 | r.EndTextColour(); | |
97 | ||
98 | r.BeginTextColour(wxColour(0, 0, 255)); | |
99 | r.WriteText(wxT(" And this blue bit.")); | |
100 | r.EndTextColour(); | |
101 | ||
102 | r.WriteText(wxT(" Naturally you can make things ")); | |
103 | r.BeginBold(); | |
104 | r.WriteText(wxT("bold ")); | |
105 | r.EndBold(); | |
106 | r.BeginItalic(); | |
107 | r.WriteText(wxT("or italic ")); | |
108 | r.EndItalic(); | |
109 | r.BeginUnderline(); | |
110 | r.WriteText(wxT("or underlined.")); | |
111 | r.EndUnderline(); | |
112 | ||
113 | r.BeginFontSize(14); | |
114 | r.WriteText(wxT(" Different font sizes on the same line is allowed, too.")); | |
115 | r.EndFontSize(); | |
116 | ||
117 | r.WriteText(wxT(" Next we'll show an indented paragraph.")); | |
118 | ||
119 | r.BeginLeftIndent(60); | |
120 | r.Newline(); | |
121 | ||
122 | r.WriteText(wxT("Indented paragraph.")); | |
123 | r.EndLeftIndent(); | |
124 | ||
125 | r.Newline(); | |
126 | ||
127 | r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40).")); | |
128 | ||
129 | r.BeginLeftIndent(100, -40); | |
130 | r.Newline(); | |
131 | ||
132 | r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter.")); | |
133 | r.EndLeftIndent(); | |
134 | ||
135 | r.Newline(); | |
136 | ||
137 | r.WriteText(wxT("Numbered bullets are possible, again using subindents:")); | |
138 | ||
139 | r.BeginNumberedBullet(1, 100, 60); | |
140 | r.Newline(); | |
141 | ||
142 | r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be added later.")); | |
143 | r.EndNumberedBullet(); | |
144 | ||
145 | r.BeginNumberedBullet(2, 100, 60); | |
146 | r.Newline(); | |
147 | ||
148 | r.WriteText(wxT("This is my second item.")); | |
149 | r.EndNumberedBullet(); | |
150 | ||
151 | r.Newline(); | |
152 | ||
153 | r.WriteText(wxT("The following paragraph is right-indented:")); | |
154 | ||
155 | r.BeginRightIndent(200); | |
156 | r.Newline(); | |
157 | ||
158 | r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable.")); | |
159 | r.EndRightIndent(); | |
160 | ||
161 | r.Newline(); | |
162 | ||
163 | wxArrayInt tabs; | |
164 | tabs.Add(400); | |
165 | tabs.Add(600); | |
166 | tabs.Add(800); | |
167 | tabs.Add(1000); | |
168 | wxTextAttrEx attr; | |
169 | attr.SetFlags(wxTEXT_ATTR_TABS); | |
170 | attr.SetTabs(tabs); | |
171 | r.SetDefaultStyle(attr); | |
172 | ||
173 | r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab")); | |
174 | ||
175 | r.Newline(); | |
176 | r.WriteText(wxT("Other notable features of wxRichTextCtrl include:")); | |
177 | ||
178 | r.BeginSymbolBullet(wxT('*'), 100, 60); | |
179 | r.Newline(); | |
180 | r.WriteText(wxT("Compatibility with wxTextCtrl API")); | |
181 | r.EndSymbolBullet(); | |
182 | ||
183 | r.WriteText(wxT("Note: this sample content was generated programmatically from within the MyFrame constructor in the demo. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!")); | |
184 | ||
185 | r.EndSuppressUndo(); | |
186 | \end{verbatim} | |
187 | } | |
188 | ||
189 | \subsection{Programming with wxRichTextCtrl} | |
190 | ||
191 | You need to include {\tt <wx/richtext/richtextctrl.h>} in your source, and link | |
192 | with the appropriate wxWidgets library with {\tt richtext} suffix. Put the rich text | |
193 | library first in your link line to avoid unresolved symbols. | |
194 | ||
195 | Then you can create a wxRichTextCtrl, with the wxWANT\_CHARS style if you want tabs to | |
196 | be processed by the control rather than being used for navigation between controls. | |
197 | ||
198 | It's helpful to have a model of how styling works. Any piece of text can have its | |
199 | style changed, but there also two global notions of style. The control's {\it basic} style | |
200 | is the fundamental style for the whole control, to which other character and paragraph styles are | |
201 | applied. For example, you can change the control's overall font by either calling SetBasicStyle with | |
202 | the appropriate font style, or by calling SetFont. | |
203 | ||
204 | The {\it default} style, on the other hand, is applied to subsequently inserted | |
205 | content. You might click on a Bold formatting tool, which sets bold as one of the default | |
206 | attributes, and typing will appear in bold. Then when you select Italic, both | |
207 | bold and italic attributes are applied as you type. The default attribute | |
208 | is set with \helpref{SetDefaultStyle}{wxrichtextctrlsetdefaultstyle}. | |
209 | ||
210 | (To be finished.) | |
211 | ||
212 | \subsection{How wxRichTextCtrl is implemented} | |
213 | ||
214 | Data representation is handled by wxRichTextBuffer, and a wxRichTextCtrl | |
215 | always has one such buffer. | |
216 | ||
217 | The content is represented by a hierarchy of objects, all derived from | |
218 | wxRichTextObject. An object might be an image, a fragment of text, a paragraph, | |
219 | or a whole buffer. Objects store a wxRichTextAttr containing style information; | |
220 | although it contains both paragraph formatting and character style, the | |
221 | paragraph style information is ignored by children of a paragraph (only | |
222 | character style is relevant to these objects). | |
223 | ||
224 | The top of the hierarchy is the buffer, a kind of wxRichTextParagraphLayoutBox. | |
225 | containing further wxRichTextParagraph objects, each of which can include text and | |
226 | images. | |
227 | ||
228 | Each object maintains a range (start and end position) measured | |
229 | from the start of the main parent box. | |
230 | ||
231 | When Layout is called on an object, it is given a size which the object | |
232 | must limit itself to, or one or more flexible directions (vertical | |
233 | or horizontal). So, for example, a centered paragraph is given the page | |
234 | width to play with (minus any margins), but can extend indefinitely | |
235 | in the vertical direction. The implementation of Layout caches the calculated | |
236 | size and position. | |
237 | ||
238 | When the buffer is modified, a range is invalidated (marked as requiring | |
239 | layout), so that only the minimum amount of layout is performed. | |
240 | ||
241 | A paragraph of pure text with the same style contains just one further | |
242 | object, a wxRichTextPlainText object. When styling is applied to part of | |
243 | this object, the object is decomposed into separate objects, one object | |
244 | for each different character style. So each object within a paragraph always has | |
245 | just one wxRichTextAttr object to denote its character style. Of course, this can | |
246 | lead to fragmentation after a lot of edit operations, potentially leading | |
247 | to several objects with the same style where just one would do. So | |
248 | a Defragment function is called when updating the control's display, to ensure that | |
249 | the minimum number of objects is used. | |
250 | ||
251 | (To be finished.) | |
252 | ||
253 | \subsection{wxRichTextCtrl roadmap} | |
254 | ||
255 | \wxheading{Bugs} | |
256 | ||
257 | This is an incomplete list of bugs. | |
258 | ||
259 | \begin{itemize} | |
260 | \item Moving the caret up at the beginning of a line sometimes incorrectly positions the | |
261 | caret. | |
262 | \end{itemize} | |
263 | ||
264 | \wxheading{Features} | |
265 | ||
266 | This is a list of some of the features that have yet to be implemented. Help with them will be appreciated. | |
267 | ||
268 | \begin{itemize} | |
269 | \item Printing | |
270 | \item RTF input and output | |
271 | \item Floating images, with content wrapping around them | |
272 | \item A ruler control | |
273 | \item Standard editing toolbars | |
274 | \item Automatic list numbering | |
275 | \item Standard dialogs for paragraph/character formatting | |
276 | \item Tables | |
277 | \item Text frames | |
278 | \item Add ability to show images in wxHTML output (currently uses | |
279 | \item More complete stylesheet viewer, plus style sheet editing dialogs | |
280 | \item Ability to store style sheets with documents | |
281 | embedded images suitable only for browsers). | |
282 | \end{itemize} | |
283 | ||
284 | There are also things that could be done to take advantage of the underlying text capabilities of the platform; | |
285 | higher-level text formatting APIs are available on some platforms, such as Mac OS X, and some of translation from | |
286 | high level to low level wxDC API is unnecessary. However this would require additions to the wxWidgets API. |