This document describes the coding conventions for QGroundControl. For complete examples, see the reference files:
- CodingStyle.h - C++ header example
- CodingStyle.cc - C++ implementation example
- CodingStyle.qml - QML example
- Indentation: 4 spaces (no tabs)
- Line endings: LF (Unix-style)
- File encoding: UTF-8
- Max line length: No hard limit, use judgment
| Element | Convention | Example |
|---|---|---|
| Classes | PascalCase | VehicleManager |
| Methods/Functions | camelCase | getActiveVehicle() |
| Variables | camelCase | activeVehicle |
| Private members | _leadingUnderscore | _vehicleList |
| Constants | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| Enums | PascalCase (scoped) | enum class FlightMode |
| Files | ClassName.h/.cc | Vehicle.h, Vehicle.cc |
#pragma once
// System headers first
#include <algorithm>
#include <span>
// Qt headers second (use full paths)
#include <QtCore/QObject>
#include <QtCore/QString>
// Project headers last
#include "Vehicle.h"class MyClass : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(...)
public:
// Constructors/destructor
// Enums
// Public methods
// Getters/setters
signals:
// Signals
public slots:
// Public slots (only if connected externally)
protected:
// Protected members (only for base classes)
private slots:
// Private slots
private:
// Private methods (prefixed with _)
// Private members (prefixed with _)
};QGroundControl uses C++20. Prefer modern features:
// Use [[nodiscard]] for functions with important return values
[[nodiscard]] bool isValid() const;
// Use std::string_view for read-only string parameters (non-Qt code)
bool validate(std::string_view input);
// Use std::span instead of pointer + size
void processData(std::span<const int> data);
// Use ranges for cleaner algorithms
auto filtered = data | std::views::filter([](int n) { return n > 0; });
// Use designated initializers for structs
Config config{.timeout = 30, .retries = 3};
// Use constexpr for compile-time constants
static constexpr int MaxRetries = 5;// Always null-check pointers
Vehicle* vehicle = _manager->activeVehicle();
if (!vehicle) {
qCWarning(MyLog) << "No active vehicle";
return;
}
// Validate inputs early
if (param.isEmpty()) {
return;
}
// Avoid Q_ASSERT in production - use defensive checks instead
// Q_ASSERT is removed in release builds// Declare in header
Q_DECLARE_LOGGING_CATEGORY(MyComponentLog)
// Define in source (use QGC macro for runtime configuration)
QGC_LOGGING_CATEGORY(MyComponentLog, "qgc.component.name")
// Use categorized logging
// qCDebug is used for general logging. These logs only display when turned on.
// Do not use qCInfo, always use qCDebug.
qCDebug(MyComponentLog) << "Debug message";
// qCWarning is used for logging of error flows which are handled but unusual.
// For example the vehicle failed to respond to a request.
// These logs will display even when the category is not enabled to display.
qCWarning(MyComponentLog) << "Warning message";
// qCCritical is used to indicate a coding error.
// Example: An internal Fact is using an unsupported Fact type.
// These logs will cause unit tests to fail if they are hit.
// These logs will display even when the category is not enabled to display.
qCCritical(MyComponentLog) << "Internal Error: ...";
// Never use uncategorized logging
qDebug() << "..."; // This is wrongclass MyClass : public QObject
{
Q_OBJECT
QML_ELEMENT // For QML-creatable types
QML_UNCREATABLE("C++ only") // For C++-only instantiation
QML_SINGLETON // For singletons
Q_MOC_INCLUDE("Vehicle.h") // For forward-declared types in Q_PROPERTY
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(Vehicle* vehicle READ vehicle CONSTANT)
};void MyClass::setValue(int newValue)
{
if (_value != newValue) {
_value = newValue;
emit valueChanged(_value); // Always emit when property changes
}
}import QtQuick
import QtQuick.Controls
import QGroundControl
import QGroundControl.Controls
Item {
id: root
// 1. Property bindings (width, height, anchors)
width: ScreenTools.defaultFontPixelHeight * 10
// 2. Public properties
property int myProperty: 0
// 3. Private properties (underscore prefix)
readonly property bool _isValid: myProperty > 0
// 4. Signals
signal clicked()
// 5. Functions
function doSomething() { }
// 6. Visual children
QGCButton {
text: qsTr("Click Me")
onClicked: root.clicked()
}
// 7. Connections (use function syntax)
Connections {
target: someObject
function onSignalName() { } // NOT: onSignalName: { }
}
// 8. Component.onCompleted
Component.onCompleted: { }
}- No hardcoded sizes: Use
ScreenTools.defaultFontPixelHeight/Width - No hardcoded colors: Use
QGCPalettefor theming - Use QGC controls:
QGCButton,QGCLabel,QGCTextField, etc. - Translations: Wrap user-visible strings with
qsTr() - Null checks: Always check
_activeVehiclebefore use
// CORRECT - Qt6 function syntax
Connections {
target: vehicle
function onArmedChanged() {
console.log("Armed state changed")
}
}
// DEPRECATED - Old Qt5 syntax (triggers pre-commit warning)
Connections {
target: vehicle
onArmedChanged: { } // Don't use this
}- Assuming single vehicle - Always null-check
activeVehicle() - Accessing Facts before ready - Wait for
parametersReadysignal - Bypassing FirmwarePlugin - Use plugin for firmware-specific behavior
- Using Q_ASSERT in production - Use defensive checks instead
- Mixing cookedValue/rawValue - Understand the difference
- Hardcoded QML sizes/colors - Use ScreenTools and QGCPalette
The repository includes configuration for automatic formatting:
.clang-format- C++ formatting.clang-tidy- C++ static analysis.qmlformat.ini- QML formatting.qmllint.ini- QML linting.editorconfig- Editor settings
Run pre-commit checks:
pre-commit run --all-files