Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.
Writing Qt Examples: Difference between revisions
No edit summary |
(→Writing Example Documentation: Link relevant style page) |
||
(12 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
[[Category:Writing Guidelines]] | |||
This page is part of the [[QtWritingGuidelines | Qt Writing Guidelines]]. | |||
This page is part of the [[QtWritingGuidelines|Qt Writing Guidelines]]. | |||
'''Note:''' This document was originally written by a Trolltech technical writer under supervision of the Qt documentation manager and describes the aims of the documentation team in late 2005. Despite this, many of these practices are still considered to be good guidelines for example code in Qt. | '''Note:''' This document was originally written by a Trolltech technical writer under supervision of the Qt documentation manager and describes the aims of the documentation team in late 2005. Despite this, many of these practices are still considered to be good guidelines for example code in Qt. | ||
Line 7: | Line 6: | ||
'''Note:''' The Wiki markup is incorrect in places in this document. We are working on a fix for this. | '''Note:''' The Wiki markup is incorrect in places in this document. We are working on a fix for this. | ||
'''Note:''' Right now, some recommendations are different from Qt/Qt Creator Coding style, see | '''Note:''' Right now, some recommendations are different from Qt/Qt Creator Coding style, see https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html | ||
'''Note:''' Additional prelude: | '''Note:''' Additional prelude: | ||
The writing of good examples is challenged by having competing goals. On one side, an example should be concise, only containing code relevant to make one point. To show one feature, or one aspect of code. On the other hand we know that examples serve as seeds for real applications. People do start off with code from examples to create real applications, and just keep existing patterns. So the right patterns should be there, but often enough the patterns are inside "boilerplate code", contradicting the first goal. So a balance is needed. The "rules" here are based on a simpilfied version Qt Creator's coding style. As always, the rules are not set in stone. Break them if you have a ''good'' reason. | |||
This document is about how to write an example for Qt. When you have finished writing an example and its documentation, see the [[ | This document is about how to write an example for Qt. When you have finished writing an example and its documentation, see the [[Integrating Qt Examples]] page for information on making it work with Qt's build and documentation systems. | ||
==File Names== | == File Names == | ||
The examples are as modularized as Qt itself. Each submodule can have a <code>examples</code> directory containing examples. Examples within a submodule are organized in a directory hierarchy, ''e.g.'' <code>qtbase/examples/itemviews/dirview</code> or <code>qtbase/examples/widgets/tetrix</code>. The hierarchy is there only to group related examples together. The examples should have unique names even if the hierarchy | The examples are as modularized as Qt itself. Each submodule can have a <code inline>examples</code> directory containing examples. Examples within a submodule are organized in a directory hierarchy, ''e.g.'' <code inline>qtbase/examples/itemviews/dirview</code> or <code inline>qtbase/examples/widgets/tetrix</code>. The hierarchy is there only to group related examples together. The examples should have unique names even if the hierarchy didn't exist. All examples should be at the same depth in the hierarchy. | ||
The | The example's <code inline>.pro</code> file should have the same name as the directory it's in (''e.g.'' <code inline>tetrix.pro</code> for <code inline>widgets/tetrix</code>). The example name should only contain lowercase letters and digits, no hyphens, no underscores. | ||
In general, each class should be defined in its own header file and implemented in a corresponding .cpp file, ''e.g.'' MainWindow in mainwindow.h and mainwindow.cpp. Try to avoid defining more than one class per header file, since it confuses Java people and | In general, each class should be defined in its own header file and implemented in a corresponding .cpp file, ''e.g.'' MainWindow in mainwindow.h and mainwindow.cpp. Try to avoid defining more than one class per header file, since it confuses Java people and it's usually unnecessary, unless you have lots of small classes (''e.g.'' an undo/redo framework, with one class per type of action). | ||
Local classes may be defined in a .cpp file. Do not use the <code>#include | Local classes may be defined in a .cpp file. Do not use the <code inline>#include "foo.moc"</code> trick in an example. (Don't worry if you don't understand what I'm talking about.) | ||
Always put your main() function in a separate file called main.cpp, and try to keep it as simple as possible. Most users have understood that main() is usually boring and seldom take the time to read it. | Always put your main() function in a separate file called main.cpp, and try to keep it as simple as possible. Most users have understood that main() is usually boring and seldom take the time to read it. It's therefore not the place to do unusual stuff. | ||
* '''Exception:''' If your example is very simple and requires only one file containing a main() function and (hopefully) a few other functions, call this file the same as your example (''e.g.'' tetrix.cpp), not main.cpp. | * '''Exception:''' If your example is very simple and requires only one file containing a main() function and (hopefully) a few other functions, call this file the same as your example (''e.g.'' tetrix.cpp), not main.cpp. | ||
Line 29: | Line 29: | ||
If you need images or other resources, use the resource mechanism. Call the resource file the same thing as the example, but with the .qrc extension (''e.g.'' tetrix.qrc). See the mainwindows/application example for an example of how to do this right. | If you need images or other resources, use the resource mechanism. Call the resource file the same thing as the example, but with the .qrc extension (''e.g.'' tetrix.qrc). See the mainwindows/application example for an example of how to do this right. | ||
==Include Files and Forward Declarations== | == Include Files and Forward Declarations == | ||
Use the Qt 4/Qt 5 syntax for #include files, and order them alphabetically: | Use the Qt 4/Qt 5 syntax for #include files, and order them alphabetically: | ||
In your .h files, try to include as few headers as possible, using forward declarations when feasible in alphabetical order. Unless the example is meant to be a very simple one, appealing to a novice programmer, make your the example | <code> | ||
#include <QApplication> | |||
#include <QComboBox> | |||
#include <QStringList> | |||
</code> | |||
In your .h files, try to include as few headers as possible, using forward declarations when feasible in alphabetical order. Unless the example is meant to be a very simple one, appealing to a novice programmer, make your the example "Qt namespace aware" by wrapping the declarations of Qt classes in QT_BEGIN_NAMESPACE/QT_END_NAMESPACE: | |||
<code> | |||
#include <QDialog> | |||
class MyClass; | |||
class YourClass; | |||
QT_BEGIN_NAMESPACE | |||
class QCheckBox; | |||
class QLineEdit; | |||
class QPushButton; | |||
QT_END_NAMESPACE | |||
</code> | |||
Best practice is to avoid "module includes", such as <code inline>#include <QtGui></code>, and use individual <code inline>#include <QClass></code> preprocessor directives instead. However, as the module includes reduces visual clutter you may use the <code inline><QtGui></code>, <code inline><QtXml></code>, etc., headers. | |||
If you need standard C++ headers, use the new style of headers (''e.g.'' <code inline><iostream></code>) and put a <code inline>using namespace std;</code> after all the includes in .cpp files. Never use <code inline>using</code> directives in global namespace in header files. | |||
* '''Exception:''' For C headers, check whether you have use the .h name (<code inline><math.h></code>, not <code inline><cmath></code>) because the new name isn't supported by all compilers. | |||
== Include order == | |||
Arrange <code inline>#includes</code>in blocks, from most-specfic to most-common to make sure your headers are as self-contained as possible. Within a block of similar <code inline>#includes</code>, try to keep the order alphabetically. | |||
<code> | |||
#include "mydialog.h" | |||
#include "yourdialog.h" | |||
#include <QtGui> | |||
#include <QtNetwork> | |||
#include <iostream> | |||
using namespace std; | |||
</code> | |||
== Variable Names == | |||
In non-trivial projects there are often special rules on the naming of member variables, like prefixing them with "_" or "m_", or suffixing with "_". If your example can live without such markers, that's fine. If it can't, use the "m_" convention. | |||
<code> | |||
void MyClass::setColor(const QColor &color) | |||
{ | |||
m_color = color; | |||
} | |||
</code> | |||
or | or | ||
Use the same variable name for parameters in header files as in the implementation. | <code> | ||
void MyClass::setColor(const QColor &c) | |||
{ | |||
color = c; | |||
} | |||
</code> | |||
Use the same variable name for parameters in header files as in the implementation. Don't drop the parameter names even if C++ lets you do so. | |||
==C++ Preprocessor== | == C++ Preprocessor == | ||
Use the preprocessor exclusively to protect against multiple inclusion, ''e.g.'' | Use the preprocessor exclusively to protect against multiple inclusion, ''e.g.'' | ||
<code> | |||
#ifndef FOO_H | |||
#define FOO_H | |||
… | |||
#endif | |||
</code> | |||
Don't use the QT_NO_xxx macros in examples. Instead, disable the example if it doesn't compile. We don't want the example source code, which is supposed to reflect end-user application code and be a model of clarity, to be littered with that junk. | |||
==Breaking Long Lines== | == Breaking Long Lines == | ||
Example code should wrap at 80 characters, because | Example code should wrap at 80 characters, because it's often quoted in the documentation and not all web browsers can display (or print) many more characters than that. This limit is stricter than the standard Trolltech limit of 100. | ||
The 80 character limit is liveable with. After all, Qt Quarterly is wrapped at 58 characters, and the entire Qt book is wrapped at 68 characters. | The 80 character limit is liveable with. After all, Qt Quarterly is wrapped at 58 characters, and the entire Qt book is wrapped at 68 characters. | ||
Line 67: | Line 121: | ||
When breaking long lines, break right ''before'' an operator and try to align the lines in the standard Trolltech way: | When breaking long lines, break right ''before'' an operator and try to align the lines in the standard Trolltech way: | ||
Use a monospaced font when editing code. Never attempt to align code if | <code> | ||
int xxxxxx = alpha + (beta | |||
* gamma); | |||
</code> | |||
Use a monospaced font when editing code. Never attempt to align code if you're using a proportional font. | |||
This rule applies to basically all operators: | This rule applies to basically all operators: | ||
One exception: With <code>if</code> and <code>& | <code> | ||
outStream << "Foo" | |||
<< "Bar"; | |||
</code> | |||
One exception: With <code inline>if</code> and <code inline>&&</code> or <code inline>||</code>, you can rapidly end up having an unfortunate alignment problem: | |||
<code> | |||
if (dsfljfsfskjldsjkljklsjdk | |||
&& fdsljsjdsdljklsjsjkdfs | |||
&& dsfljkdfjkldksdfjdjkfdksfdkjld) | |||
sadjdjddadhsad; | |||
</code> | |||
The problem is that it's not clear where the if condition ends (the third line) and where the if body starts (the fourth line). My ad hoc solution is to add four spaces to the continuation lines: | |||
<code> | |||
if (dsfljfsfskjldsjkljklsjdk | |||
&& fdsljsjdsdljklsjsjkdfs | |||
&& dsfljkdfjkldksdfjdjkfdksfdkjld) | |||
sadjdjddadhsad; | |||
</code> | |||
Fortunately, you don't need to do this for <code inline>else if</code> or <code inline>while</code>; unlike <code inline>if</code>, these aren't two-letter words. | |||
<code> | |||
while (dsfljfsfskjldsjkljklsjdk | |||
&& fdsljsjdsdljklsjsjkdfs | |||
&& dsfljkdfjkldksdfjdjkfdksfdkjld) | |||
sadjdjddadhsad; | |||
</code> | |||
==Spaces, Blank Lines, and Comments== | == Spaces, Blank Lines, and Comments == | ||
Apart when breaking lines, avoid aligning things together. This looks really bad with proportional fonts and actually looks bad with monospaced fonts as well. ''I.e.'' avoid | Apart when breaking lines, avoid aligning things together. This looks really bad with proportional fonts and actually looks bad with monospaced fonts as well. ''I.e.'' avoid | ||
<code> | |||
x = rect.x(); | |||
y = rect.y(); | |||
width = rect.width(); | |||
height = rect.height(); | |||
</code> | |||
Use blank lines consistently in your source files to separate functions in the .cpp file. Never use more than one blank line in a row, as this normally leads to inconsistent style. | Use blank lines consistently in your source files to separate functions in the .cpp file. Never use more than one blank line in a row, as this normally leads to inconsistent style. | ||
Avoid comments. Documentation belongs exclusively in the | Avoid comments. Documentation belongs exclusively in the example's walkthrough. (We don't have the resources to document the examples twice!) One case were comments are useful is when a parameter is unused: | ||
<code> | |||
void MandelbrotWidget::paintEvent(QPaintEvent * /* event */) | |||
</code> | |||
This is better than | This is better than | ||
==Braces== | <code> | ||
void MandelbrotWidget::paintEvent(QPaintEvent *) | |||
</code> | |||
== Braces == | |||
If syntax: | If syntax: | ||
<code> | |||
if (x) | |||
y; | |||
</code> | |||
Never: | Never: | ||
<code> | |||
if (x) y; | |||
</code> | |||
If y is complicated, you can use braces to make it clearer: | If y is complicated, you can use braces to make it clearer: | ||
<code> | |||
if (x) { | |||
// do something strange | |||
yyyyyyyyy = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy | |||
''zzzzzzzzzzzzzzzzzzzzzz; | |||
} | |||
</code> | |||
Same thing applies to for and while loops: | Same thing applies to for and while loops: | ||
<code> | |||
for (int i = 0; i < n;i) | |||
qDebug() << i; | |||
</code> | |||
In the interest of readability, use braces whenever things start getting sightly complicated: | In the interest of readability, use braces whenever things start getting sightly complicated: | ||
<code> | |||
for (int i = 0; i < n;i) { | |||
for (int j = 0; j < n;j) { | |||
for (int k = 0; k < n;k) { | |||
data[i][j][k] = i'' j * k; | |||
} | |||
} | |||
} | |||
</code> | |||
If you put braces around one case, do it around all: | If you put braces around one case, do it around all: | ||
<code> | |||
if (x) { | |||
foo; | |||
} else if (y) { | |||
bar; | |||
baz; | |||
} else { | |||
blah; | |||
} | |||
</code> | |||
The advantage of this style is that you get nicely aligned braces at the bottom of the code, corresponding to the indentation level. | The advantage of this style is that you get nicely aligned braces at the bottom of the code, corresponding to the indentation level. | ||
==Signal-Slot Connections== | == Signal-Slot Connections == | ||
Always use the four- or five-parameter overload of the | |||
<code inline>QObject::connect()</code> call: | |||
<code> | |||
connect(obj1, SIGNAL (foo()), this, SLOT (bar())); | |||
</code> | |||
This is clearer than | This is clearer than | ||
Beginners might think that | <code> | ||
connect(obj1, SIGNAL (foo()), SLOT (bar())); | |||
</code> | |||
Beginners might think that we're connecting to obj1's bar() signal, when we actually are connecting to <code inline>this</code>. | |||
Always specify the full types of the arguments, ''i.e.'' <code>const | Always specify the full types of the arguments, ''i.e.'' <code inline>const QString &</code> instead of <code inline>QString</code>, in the interest of keeping things simple for beginners. We'll mention that you can write the latter in the documentation, but stick to a consistent, simple subset of the Qt language in examples. | ||
==Writing Example Documentation== | == Writing Example Documentation == | ||
These are the guidelines for documenting Qt examples. These guidelines are not intended to be ironclad rules, but can be seen as good advice or rules of thumb. | These are the guidelines for documenting Qt examples. These guidelines are not intended to be ironclad rules, but can be seen as good advice or rules of thumb. See also [[Documentation Style for Examples]]. | ||
We wish our examples to follow a somewhat strict style of writing and composition. This is mainly because examples are easier to follow when their style is familiar to the reader (we shamelessly assume that all readers will come in touch with at least a few examples). | We wish our examples to follow a somewhat strict style of writing and composition. This is mainly because examples are easier to follow when their style is familiar to the reader (we shamelessly assume that all readers will come in touch with at least a few examples). | ||
===Composition=== | === Composition === | ||
It is a good idea to teach only one (or a few closely related) concepts or techniques. Examples that show more often function better as demos. The documentation should focus on this and avoid commenting and showing code not relevant to what the example is teaching. In basic examples or tutorials, one might still wish to go through the entire code in detail. | It is a good idea to teach only one (or a few closely related) concepts or techniques. Examples that show more often function better as demos. The documentation should focus on this and avoid commenting and showing code not relevant to what the example is teaching. In basic examples or tutorials, one might still wish to go through the entire code in detail. | ||
The bulk of Qt examples have two main parts: an introduction and a walkthrough of the | The bulk of Qt examples have two main parts: an introduction and a walkthrough of the example's code. Let's look at these parts in separate sections. | ||
====Introduction==== | ==== Introduction ==== | ||
Most examples start with one line that describes in as few words as possible what the example wants to teach the reader. Then a picture of the | Most examples start with one line that describes in as few words as possible what the example wants to teach the reader. Then a picture of the example's GUI is shown. | ||
The rest of the introduction can describe how to use the example, e.g., by listing what the widgets in the | The rest of the introduction can describe how to use the example, e.g., by listing what the widgets in the GUI do. Then the classes of the example are listed, and one describes how they work together on a high-level, perhaps including how they fit into or use the Qt framework. | ||
For examples that teach advanced issues, it is also common to introduce the underlying Qt architecture and refer to overviews, the | For examples that teach advanced issues, it is also common to introduce the underlying Qt architecture and refer to overviews, the API, or other documents. | ||
====Code Walkthrough==== | ==== Code Walkthrough ==== | ||
We usually follow the top-down principle when documenting examples. So when the reader encounters a new class or function, he/she already knows how it is used in the grand scheme of things, and can concentrate on the implementation details. | We usually follow the top-down principle when documenting examples. So when the reader encounters a new class or function, he/she already knows how it is used in the grand scheme of things, and can concentrate on the implementation details. | ||
Line 141: | Line 293: | ||
All examples should contain snippets from the example source code with accompanying comments. As with the examples themselves, code snippets work best when they show one or a few related issues or implementation details that need to be elaborated. This consequently often results in one snippet per function. But for large functions, it may be advantageous to split the function in more than one snippet. | All examples should contain snippets from the example source code with accompanying comments. As with the examples themselves, code snippets work best when they show one or a few related issues or implementation details that need to be elaborated. This consequently often results in one snippet per function. But for large functions, it may be advantageous to split the function in more than one snippet. | ||
===Writing Style=== | === Writing Style === | ||
What is considered good writing style is inherently subjective. There is still some good advice that it normally pays to follow. | What is considered good writing style is inherently subjective. There is still some good advice that it normally pays to follow. Let's look at a few issues when Qt example documentation is concerned. | ||
Try not to simply state what the code does line for line (the reader can easily figure that out by looking at the code and refer to the | Try not to simply state what the code does line for line (the reader can easily figure that out by looking at the code and refer to the API documentation if he/she needs to). Focus on how things work behind the scenes and on issues that it is not easy to read from the code. On the other hand, we do not leave snippets uncommented; if you have nothing to say about a particular snippet, it is better to state what the code does line for line than leaving the space between two snippets empty. When implementing an advanced example, you can generally assume that the reader is familiar with basic Qt programming and concepts. So there is no need to explain everything in detail; again, focus on what the example tries to teach. For instance, an example that shows how to paint items in an item view does not need to explain what an item view is. There are no absolute rules to follow when deciding what needs explaining and what does not. | ||
Don't use terms not already introduced or not considered knowledge the reader should have. Nothing is more frustrating than reading documentation when you constantly run into terms that are not explained to you. If you follow the top-down approach mentioned earlier, it is less likely that you fall into this trap. | |||
For general tips about composition and writing style, I trust in | For general tips about composition and writing style, I trust in 'The Elements of Style' by Strunk and White. An early edition is found online: http://www.bartleby.com/141/. | ||
===Conclusion=== | === Conclusion === | ||
Some Qt examples include a section that wraps up the example by describing possibilities for extending the example (i.e., all the stuff you wished to implement, but could not because you follow the principle that examples should teach only a few concepts or techniques). Other examples do not have a summary at all, and silently stop after the code walkthrough of the last class. | Some Qt examples include a section that wraps up the example by describing possibilities for extending the example (i.e., all the stuff you wished to implement, but could not because you follow the principle that examples should teach only a few concepts or techniques). Other examples do not have a summary at all, and silently stop after the code walkthrough of the last class. | ||
Latest revision as of 12:31, 10 June 2021
This page is part of the Qt Writing Guidelines.
Note: This document was originally written by a Trolltech technical writer under supervision of the Qt documentation manager and describes the aims of the documentation team in late 2005. Despite this, many of these practices are still considered to be good guidelines for example code in Qt.
Note: The Wiki markup is incorrect in places in this document. We are working on a fix for this.
Note: Right now, some recommendations are different from Qt/Qt Creator Coding style, see https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html
Note: Additional prelude: The writing of good examples is challenged by having competing goals. On one side, an example should be concise, only containing code relevant to make one point. To show one feature, or one aspect of code. On the other hand we know that examples serve as seeds for real applications. People do start off with code from examples to create real applications, and just keep existing patterns. So the right patterns should be there, but often enough the patterns are inside "boilerplate code", contradicting the first goal. So a balance is needed. The "rules" here are based on a simpilfied version Qt Creator's coding style. As always, the rules are not set in stone. Break them if you have a good reason.
This document is about how to write an example for Qt. When you have finished writing an example and its documentation, see the Integrating Qt Examples page for information on making it work with Qt's build and documentation systems.
File Names
The examples are as modularized as Qt itself. Each submodule can have a examples
directory containing examples. Examples within a submodule are organized in a directory hierarchy, e.g. qtbase/examples/itemviews/dirview
or qtbase/examples/widgets/tetrix
. The hierarchy is there only to group related examples together. The examples should have unique names even if the hierarchy didn't exist. All examples should be at the same depth in the hierarchy.
The example's .pro
file should have the same name as the directory it's in (e.g. tetrix.pro
for widgets/tetrix
). The example name should only contain lowercase letters and digits, no hyphens, no underscores.
In general, each class should be defined in its own header file and implemented in a corresponding .cpp file, e.g. MainWindow in mainwindow.h and mainwindow.cpp. Try to avoid defining more than one class per header file, since it confuses Java people and it's usually unnecessary, unless you have lots of small classes (e.g. an undo/redo framework, with one class per type of action).
Local classes may be defined in a .cpp file. Do not use the #include "foo.moc"
trick in an example. (Don't worry if you don't understand what I'm talking about.)
Always put your main() function in a separate file called main.cpp, and try to keep it as simple as possible. Most users have understood that main() is usually boring and seldom take the time to read it. It's therefore not the place to do unusual stuff.
- Exception: If your example is very simple and requires only one file containing a main() function and (hopefully) a few other functions, call this file the same as your example (e.g. tetrix.cpp), not main.cpp.
If you need images or other resources, use the resource mechanism. Call the resource file the same thing as the example, but with the .qrc extension (e.g. tetrix.qrc). See the mainwindows/application example for an example of how to do this right.
Include Files and Forward Declarations
Use the Qt 4/Qt 5 syntax for #include files, and order them alphabetically:
#include <QApplication>
#include <QComboBox>
#include <QStringList>
In your .h files, try to include as few headers as possible, using forward declarations when feasible in alphabetical order. Unless the example is meant to be a very simple one, appealing to a novice programmer, make your the example "Qt namespace aware" by wrapping the declarations of Qt classes in QT_BEGIN_NAMESPACE/QT_END_NAMESPACE:
#include <QDialog>
class MyClass;
class YourClass;
QT_BEGIN_NAMESPACE
class QCheckBox;
class QLineEdit;
class QPushButton;
QT_END_NAMESPACE
Best practice is to avoid "module includes", such as #include <QtGui>
, and use individual #include <QClass>
preprocessor directives instead. However, as the module includes reduces visual clutter you may use the <QtGui>
, <QtXml>
, etc., headers.
If you need standard C++ headers, use the new style of headers (e.g. <iostream>
) and put a using namespace std;
after all the includes in .cpp files. Never use using
directives in global namespace in header files.
- Exception: For C headers, check whether you have use the .h name (
<math.h>
, not<cmath>
) because the new name isn't supported by all compilers.
Include order
Arrange #includes
in blocks, from most-specfic to most-common to make sure your headers are as self-contained as possible. Within a block of similar #includes
, try to keep the order alphabetically.
#include "mydialog.h"
#include "yourdialog.h"
#include <QtGui>
#include <QtNetwork>
#include <iostream>
using namespace std;
Variable Names
In non-trivial projects there are often special rules on the naming of member variables, like prefixing them with "_" or "m_", or suffixing with "_". If your example can live without such markers, that's fine. If it can't, use the "m_" convention.
void MyClass::setColor(const QColor &color)
{
m_color = color;
}
or
void MyClass::setColor(const QColor &c)
{
color = c;
}
Use the same variable name for parameters in header files as in the implementation. Don't drop the parameter names even if C++ lets you do so.
C++ Preprocessor
Use the preprocessor exclusively to protect against multiple inclusion, e.g.
#ifndef FOO_H
#define FOO_H
…
#endif
Don't use the QT_NO_xxx macros in examples. Instead, disable the example if it doesn't compile. We don't want the example source code, which is supposed to reflect end-user application code and be a model of clarity, to be littered with that junk.
Breaking Long Lines
Example code should wrap at 80 characters, because it's often quoted in the documentation and not all web browsers can display (or print) many more characters than that. This limit is stricter than the standard Trolltech limit of 100.
The 80 character limit is liveable with. After all, Qt Quarterly is wrapped at 58 characters, and the entire Qt book is wrapped at 68 characters.
When breaking long lines, break right before an operator and try to align the lines in the standard Trolltech way:
int xxxxxx = alpha + (beta
* gamma);
Use a monospaced font when editing code. Never attempt to align code if you're using a proportional font.
This rule applies to basically all operators:
outStream << "Foo"
<< "Bar";
One exception: With if
and &&
or ||
, you can rapidly end up having an unfortunate alignment problem:
if (dsfljfsfskjldsjkljklsjdk
&& fdsljsjdsdljklsjsjkdfs
&& dsfljkdfjkldksdfjdjkfdksfdkjld)
sadjdjddadhsad;
The problem is that it's not clear where the if condition ends (the third line) and where the if body starts (the fourth line). My ad hoc solution is to add four spaces to the continuation lines:
if (dsfljfsfskjldsjkljklsjdk
&& fdsljsjdsdljklsjsjkdfs
&& dsfljkdfjkldksdfjdjkfdksfdkjld)
sadjdjddadhsad;
Fortunately, you don't need to do this for else if
or while
; unlike if
, these aren't two-letter words.
while (dsfljfsfskjldsjkljklsjdk
&& fdsljsjdsdljklsjsjkdfs
&& dsfljkdfjkldksdfjdjkfdksfdkjld)
sadjdjddadhsad;
Spaces, Blank Lines, and Comments
Apart when breaking lines, avoid aligning things together. This looks really bad with proportional fonts and actually looks bad with monospaced fonts as well. I.e. avoid
x = rect.x();
y = rect.y();
width = rect.width();
height = rect.height();
Use blank lines consistently in your source files to separate functions in the .cpp file. Never use more than one blank line in a row, as this normally leads to inconsistent style.
Avoid comments. Documentation belongs exclusively in the example's walkthrough. (We don't have the resources to document the examples twice!) One case were comments are useful is when a parameter is unused:
void MandelbrotWidget::paintEvent(QPaintEvent * /* event */)
This is better than
void MandelbrotWidget::paintEvent(QPaintEvent *)
Braces
If syntax:
if (x)
y;
Never:
if (x) y;
If y is complicated, you can use braces to make it clearer:
if (x) {
// do something strange
yyyyyyyyy = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
''zzzzzzzzzzzzzzzzzzzzzz;
}
Same thing applies to for and while loops:
for (int i = 0; i < n;i)
qDebug() << i;
In the interest of readability, use braces whenever things start getting sightly complicated:
for (int i = 0; i < n;i) {
for (int j = 0; j < n;j) {
for (int k = 0; k < n;k) {
data[i][j][k] = i'' j * k;
}
}
}
If you put braces around one case, do it around all:
if (x) {
foo;
} else if (y) {
bar;
baz;
} else {
blah;
}
The advantage of this style is that you get nicely aligned braces at the bottom of the code, corresponding to the indentation level.
Signal-Slot Connections
Always use the four- or five-parameter overload of the
QObject::connect()
call:
connect(obj1, SIGNAL (foo()), this, SLOT (bar()));
This is clearer than
connect(obj1, SIGNAL (foo()), SLOT (bar()));
Beginners might think that we're connecting to obj1's bar() signal, when we actually are connecting to this
.
Always specify the full types of the arguments, i.e. const QString &
instead of QString
, in the interest of keeping things simple for beginners. We'll mention that you can write the latter in the documentation, but stick to a consistent, simple subset of the Qt language in examples.
Writing Example Documentation
These are the guidelines for documenting Qt examples. These guidelines are not intended to be ironclad rules, but can be seen as good advice or rules of thumb. See also Documentation Style for Examples.
We wish our examples to follow a somewhat strict style of writing and composition. This is mainly because examples are easier to follow when their style is familiar to the reader (we shamelessly assume that all readers will come in touch with at least a few examples).
Composition
It is a good idea to teach only one (or a few closely related) concepts or techniques. Examples that show more often function better as demos. The documentation should focus on this and avoid commenting and showing code not relevant to what the example is teaching. In basic examples or tutorials, one might still wish to go through the entire code in detail.
The bulk of Qt examples have two main parts: an introduction and a walkthrough of the example's code. Let's look at these parts in separate sections.
Introduction
Most examples start with one line that describes in as few words as possible what the example wants to teach the reader. Then a picture of the example's GUI is shown.
The rest of the introduction can describe how to use the example, e.g., by listing what the widgets in the GUI do. Then the classes of the example are listed, and one describes how they work together on a high-level, perhaps including how they fit into or use the Qt framework.
For examples that teach advanced issues, it is also common to introduce the underlying Qt architecture and refer to overviews, the API, or other documents.
Code Walkthrough
We usually follow the top-down principle when documenting examples. So when the reader encounters a new class or function, he/she already knows how it is used in the grand scheme of things, and can concentrate on the implementation details.
Documentation for classes in Qt examples are often divided in two sections: one for its definition and one for its implementation. Exceptions are small classes, classes from which we do not show code snippets, and classes with only inlined functions.
All examples should contain snippets from the example source code with accompanying comments. As with the examples themselves, code snippets work best when they show one or a few related issues or implementation details that need to be elaborated. This consequently often results in one snippet per function. But for large functions, it may be advantageous to split the function in more than one snippet.
Writing Style
What is considered good writing style is inherently subjective. There is still some good advice that it normally pays to follow. Let's look at a few issues when Qt example documentation is concerned.
Try not to simply state what the code does line for line (the reader can easily figure that out by looking at the code and refer to the API documentation if he/she needs to). Focus on how things work behind the scenes and on issues that it is not easy to read from the code. On the other hand, we do not leave snippets uncommented; if you have nothing to say about a particular snippet, it is better to state what the code does line for line than leaving the space between two snippets empty. When implementing an advanced example, you can generally assume that the reader is familiar with basic Qt programming and concepts. So there is no need to explain everything in detail; again, focus on what the example tries to teach. For instance, an example that shows how to paint items in an item view does not need to explain what an item view is. There are no absolute rules to follow when deciding what needs explaining and what does not.
Don't use terms not already introduced or not considered knowledge the reader should have. Nothing is more frustrating than reading documentation when you constantly run into terms that are not explained to you. If you follow the top-down approach mentioned earlier, it is less likely that you fall into this trap.
For general tips about composition and writing style, I trust in 'The Elements of Style' by Strunk and White. An early edition is found online: http://www.bartleby.com/141/.
Conclusion
Some Qt examples include a section that wraps up the example by describing possibilities for extending the example (i.e., all the stuff you wished to implement, but could not because you follow the principle that examples should teach only a few concepts or techniques). Other examples do not have a summary at all, and silently stop after the code walkthrough of the last class.