所有QGIS开发人员都应该遵循这些标准。
类成员名称以小写m开头,并使用混合大小写形成。
mMapCanvas
mCurrentExtent
所有的类成员都应该是私有的。公众阶层的成员强烈反对。当可能需要从python子类访问成员时,应避免使用受保护的成员,因为不能从python绑定中使用受保护的成员。
可变静态类成员名称应以小写开头 s
,但常量静态类成员名称应全部大写:
sRefCounter
DEFAULT_QUEUE_SIZE
类成员值应该通过accesssor函数获得。函数的命名不应使用get前缀。上面两个私有成员的访问函数是:
mapCanvas()
currentExtent()
确保访问器正确标记为 const
. 在适当的情况下,这可能需要将缓存值类型成员变量标记为 mutable
.
函数名以小写字母开头,由混合大小写组成。函数名应该传达一些关于函数用途的信息。
updateMapExtent()
setUserOptions()
为了与现有的qgis api和qt api保持一致,应避免使用缩写。例如。 setDestinationSize
而不是 setDestSize
, setMaximumValue
而不是 setMaxVal
.
为了保持一致性,缩写词也应该采用驼色大小写。例如。 setXml
而不是 setXML
.
函数参数应使用描述性名称。不要使用单字母参数(例如 setColor( const QColor& color )
而不是 setColor( const QColor& c )
)
注意什么时候应该通过引用传递参数。除非参数对象很小并且被复制(如qpoint对象),否则它们应该通过const引用传递。为了与qt api保持一致,即使是隐式共享的对象也通过const引用传递(例如 setTitle( const QString& title )
而不是 setTitle( QString title )
.
以值的形式返回复制的小对象。较大的对象应通过常量引用返回。唯一的例外是隐式共享对象,它总是按值返回。返回 QObject
或将对象子类化为指针。
int maximumValue() const
const LayerSet& layers() const
QString title() const
(QString
is implicitly shared)QList< QgsMapLayer* > layers() const
(QList
is implicitly shared)QgsVectorLayer *layer() const;
(QgsVectorLayer
inherits QObject
)QgsAbstractGeometry *geometry() const;
(QgsAbstractGeometry
is
abstract and will probably need to be casted)需要为公共API中可用的每个类、方法、枚举和其他代码编写API文档。
qgis使用doxygen作为文档。写一些描述性的、有意义的评论,给读者提供关于期望值、在边缘情况下发生的事情的信息,并给出关于他可能正在寻找的其他接口、最佳实践和代码示例的提示。
方法说明应使用第三人以描述性的形式书写。方法需要 \since
定义引入时间的标记。您应该添加其他 \since
稍后介绍的重要更改的标记。
/**
* Cleans the laundry by using water and fast rotation.
* It will use the provided \a detergent during the washing programme.
*
* \returns True if everything was successful. If false is returned, use
* \link error() \endlink to get more information.
*
* \note Make sure to manually call dry() after this method.
*
* \since QGIS 3.0
* \see dry()
*/
成员变量通常应位于 private
并通过getter和setter提供。一个例外是数据容器,比如错误报告。在这种情况下,不要在成员前面加上 m
.
/**
* \ingroup core
* Represents points on the way along the journey to a destination.
*
* \since QGIS 2.20
*/
class QgsWaypoint
{
/**
* Holds information about results of an operation on a QgsWaypoint.
*
* \since QGIS 3.0
*/
struct OperationResult
{
QgsWaypoint::ResultCode resultCode; //!< Indicates if the operation completed successfully.
QString message; //!< A human readable localized error message. Only set if the resultCode is not QgsWaypoint::Success.
QVariant result; //!< The result of the operation. The content depends on the method that returned it. \since QGIS 3.2
};
};
C++实现和头文件应该分别有.CPP和.H扩展。文件名应该全部是小写的,如果是类,则与类名匹配。
实例:类 QgsFeatureAttribute
源文件是 qgsfeatureattribute.cpp
和 qgsfeatureattribute.h
注解
如果上面的语句不清楚,那么对于与类名匹配的文件名,它隐式地意味着每个类都应该在自己的文件中声明和实现。这使得新手更容易识别代码与特定类相关的位置。
每个源文件都应该包含一个标题部分,该标题部分在下面的示例之后有图案:
/***************************************************************************
qgsfield.cpp - Describes a field in a layer or table
--------------------------------------
Date : 01-Jan-2004
Copyright: (C) 2004 by Gary E.Sherman
Email: sherman at mrcc.com
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
注解
在Git中有一个Qt Creator模板。要使用它,请从 doc/qt_creator_license_template
到本地位置,调整邮件地址和(如果需要)名称,并将qtcreator配置为使用它: .
枚举类型应在camelcase中命名,并使用一个前导大写,例如:
enum UnitType
{
Meters,
Feet,
Degrees,
UnknownUnit
};
不要使用将与其他类型冲突的泛型类型名。例如使用 UnkownUnit
而不是 Unknown
所有信号/插槽连接应使用qt5中提供的“新样式”连接。有关此要求的更多信息,请访问 QEP #77 .
避免使用Qt自动连接插槽(即 void on_mSpinBox_valueChanged
)如果重构对话框,自动连接插槽很脆弱,容易在没有警告的情况下损坏。
只要满足以下要求,任何文本编辑器/IDE都可以用于编辑QGIS代码。
有 API documentation 对于C++。
我们试图保持API的稳定和向后兼容。对API的清理应以类似于qt源代码的方式进行,例如
class Foo
{
public:
/**
* This method will be deprecated, you are encouraged to use
* doSomethingBetter() rather.
* \deprecated doSomethingBetter()
*/
Q_DECL_DEPRECATED bool doSomething();
/**
* Does something a better way.
* \note added in 1.1
*/
bool doSomethingBetter();
signals:
/**
* This signal will is deprecated, you are encouraged to
* connect to somethingHappenedBetter() rather.
* \deprecated use somethingHappenedBetter()
*/
#ifndef Q_MOC_RUN
Q_DECL_DEPRECATED
#endif
bool somethingHappened();
/**
* Something happened
* \note added in 1.1
*/
bool somethingHappenedBetter();
}
一些SIP文件是使用专用脚本自动生成的。
正确构建SIP文件的所有信息都必须在C++头文件中找到。某些宏可用于此类定义:
#ifdef SIP_RUN
只在SIP文件中生成代码或 #ifndef SIP_RUN
仅供C++代码使用。 #else
两种情况下都处理语句。SIP_SKIP
放弃一行SIP_FACTORY
: /Factory/
SIP_OUT
: /Out/
SIP_INOUT
: /In,Out/
SIP_TRANSFER
: /Transfer/
SIP_PYNAME(name)
: /PyName=name/
SIP_KEEPREFERENCE
: /KeepReference/
SIP_TRANSFERTHIS
: /TransferThis/
SIP_TRANSFERBACK
: /TransferBack/
private
sections are not displayed, except if you use a #ifdef SIP_RUN
statement in this block.SIP_PYDEFAULTVALUE(value)
can be used to define an alternative default
value of the python method. If the default value contains a comma ,
,
the value should be surrounded by single quotes '
SIP_PYTYPE(type)
can be used to define an alternative type for an argument
of the python method. If the type contains a comma ,
, the type should be
surrounded by single quotes '
演示文件可在 tests/scripts/sipifyheader.h
.
可以使用专用脚本生成SIP文件。例如:
scripts/sipify.pl src/core/qgsvectorlayer.h > python/core/qgsvectorlayer.sip
一旦将SIP文件添加到某个源文件中( python/core/core.sip
, python/gui/gui.sip
或 python/analysis/analysis.sip
)将被视为自动生成。Travis上的测试将确保该文件及其相应的头是最新的。
尚未启用自动创建的旧文件列在 python/auto_sip.blacklist
.
如果sipify脚本需要一些改进,请将缺少的位添加到演示文件中 tests/scripts/sipifyheader.h
并创建预期的标题 tests/scripts/sipifyheader.expected.si
. 这也将作为脚本本身的单元测试在Travis上自动测试。
下面介绍一些编程提示和技巧,希望能够减少错误、开发时间和维护。
如果要剪切n-pasting代码,或者多次编写相同的代码,请考虑将代码合并为单个函数。
这将:
倾向于将常量放在谓词的第一位。
0 == value
instead of value == 0
这将有助于防止程序员意外使用 =
当他们打算使用 ==
这会导致非常微妙的逻辑错误。如果不小心使用 =
而不是 ==
因为常量本身不能赋值,所以无法进行比较。
在运算符、语句和函数之间添加空格使人更容易分析代码。
更容易阅读的是:
if (!a&&b)
或者:
if ( ! a && b )
注解
scripts/prepare-commit.sh
will take care of this.
在读取代码时,如果命令不在行的开头,很容易遗漏命令。当快速阅读代码时,如果行看起来不像您在前几个字符中要查找的那样,则通常跳过行。在类似于 if
.
考虑:
if (foo) bar();
baz(); bar();
很容易错过控制流程的一部分。代替使用
if (foo)
bar();
baz();
bar();
访问修饰符将类结构为公共API、受保护API和私有API的各个部分。访问修饰符本身将代码分组到这个结构中。缩进访问修饰符和声明。
class QgsStructure
{
public:
/**
* Constructor
*/
explicit QgsStructure();
}
您还应该阅读qt Quarterly上的这篇文章 designing Qt style (APIs)
鼓励新职能的贡献者通过以下方式让人们了解他们的贡献:
在包含代码的第一个版本的changelog中添加注释,类型为:
This feature was funded by: Olmiomland https://olmiomland.ol
This feature was developed by: Chuck Norris https://chucknorris.kr
writing an article about the new feature on a blog, and add it to the QGIS planet https://plugins.qgis.org/planet/
将其名称添加到: