QGroundControlソースコードの学習シリーズ - 3

QGroundControlソースコードの学習シリーズ - 3

QGCApplication

QGCApplicationはかなりのQApplicationよりも、QGuiApplicationから継承されました。QQmlApplicationEngineエンジンQGCApplicationで管理する必要があるので、QMLとQtQuickを使用してQGroundControlインターフェイスコンポーネントは、行って。もちろん、それはまた、QGCToolboxオブジェクトを維持するなどの別の役割を有し、システムの言語などを設定(すなわち、使用される他の管理手順にアクセスするために使用することができます)。

アプリケーションでは、アプリケーションは通常、いくつかのグローバルオペレーションを完了することができるだけオブジェクト。QGCApplicationシングルトンパターンは、ターゲットQGCApplicationを得るための同様の方法を提供します。

/// @brief Returns the QGCApplication object singleton.
QGCApplication* qgcApp(void);

/// @brief Returns the QGCApplication object singleton.
QGCApplication* qgcApp(void)
{
    return QGCApplication::_app;
}

static QGCApplication*  _app;   ///< Our own singleton. Should be reference directly by qgcApp

通話qgcApp機能がグローバルにアクセスすることができ应用对象、ここでQGCApplicationです:: _アプリが公開されて(したがってqgcApp機能にアクセスすることができます)が、命名は、(プライベートで書かれた_接頭辞)、そのポインタへの直接呼び出しを避けるようにしてください。

以下は、コード内のコメントです:公共のが、これらの方法は内部にあり、唯一のunittestのコードによって呼び出されなければなりません

私のQtアプリケーションの開発プロセスでは、我々は勉強しなかったQApplication、上記の例のほとんどのように、演技を作成しQApplicationたオブジェクトを、その後、イベントループを実行します。小さなプロジェクト、プログラム実行プロセス簡単な単語の例に従うように問題はないが、ときにプログラムの実行プロセスの複雑さのために、物事はそう単純ではありません。例えば、簡単な例でapp.exec()カスタムした後、いくつかの操作の実装、そして私たちは、コードの流れを変更する必要があり、主な機能は、簡単ではありませんでしたreturn app.exec();、私たちはこれを行うことができます:

int main(int argc, char *argv[]) 
{
    Something *something;
    ...

    int ret = app.exec();
    delete something;
    return ret;
}

アプリケーションは、より複雑ではQApplicationによって継承され、外部インターフェイスシングルトンパターンを提供する場合、操作の他のタイプは、カスタムアプリケーションに特定のグローバル変数のユニークな組み合わせとして、簡略化され、その後、対象アプリケーションによって取得することができます。これは、シングルトンの過度の使用を防止します。

:実際には、このクラスのQtのパッケージには、我々はウィジェットアプリケーションの全体のサブクラスを得ることができるようにいくつかの方法を提供してデスクトップアプリケーションを開発、より厄介な分野のいくつかで私たちに良い解決策になることができますQWidgetList allWidgets():デスクトップコンポーネントに戻るQDesktopWidget *desktop()場合は、そうと明らかに、デスクトップアプリケーションを使用してQWidgetのコンポーネント開発QApplication、より良いです。

私はより良いすべてのマネージャはこの方法によるストレージとアクセスウィンドウオブジェクトを介しQMapを設定したウィンドウマネージャを構築シングルトンと、プログラムにアクセスすることができ、いくつかの窓部材を持っているQMapウィンドウポインタ。しかし、ポイントは多くの困難があることである:ウィンドウオブジェクトのために、私は登録された各オブジェクトのウィンドウマネージャにコードの行を追加する必要がありました、非常に複雑な(コンストラクタでウィンドウマネージャといくつかのレジスタだけでなく、非常に面倒)です。その後、要件が変更されたとき、あなたは新しい機能/インターフェイスを追加する必要があり、このモデルは開発に適していないことが判明し、最終的に放棄されました。もちろん、あなたが使用して、既存のウィジェット・アプリケーションにアクセスしたい場合QApplicationの方法は、より便利に提供しています。

QGCApplicationそこに他の多くの機能がありますが、私は、このような効率は正直に低すぎると言って、ラインの読みによってコードの行を入力するつもりはない、効果はおそらく良くありません。私はあなたがおそらく既にあなたが知っているか、私のノートに記録されていないしたい内容を知って、前に見たことがない記録するためにいくつか書かれたコードや使用方法を選ぶだろうが、内容は私が学ぶことのために十分です。あなたが大規模なソフトウェアプロジェクトの開発を理解したい場合は、QGroundControlソースを学ぶために彼らの実際の状況に応じてお勧めします。言及する価値があるもう一つのポイントは、QGroundControlすでに何年かは、そのコードの一部が放棄された可能性があります。私が使用しようとするCMakeプロジェクトをビルドすることができない建築プロジェクト、あるいは状況を、関係者はそれにのみ使用され、CMakeLists.txtの内容が古い確認QMake構築します。

QGCLoggingCategory

  • このセクションでは、非常に関連AppMessagesの一つ。

私はQGroundControlはウィジェットとどのようにログを保存するにログをエクスポートする方法、カスタムメッセージハンドラを達成することであるかについて話しましたAppMessages。このプロジェクトでは、時間の比較的小さい、シンプルな構造なので、まったく問題カスタムメッセージハンドラを使用しない、結局、何がそんなにに出力します。しかし、関心の千万ログ部分から複雑なプロジェクト、モジュールアセンブリとよりは、見つけるのは難しいがあります。このように、ログを表示するときに機能をフィルタリングするための必要性。

小型でQGCLoggingCategoryコンテンツは、2つのクラスが含まれていますQGCLoggingCategoryし、QGCLoggingCategoryRegister前者は非常に簡単です:

class QGCLoggingCategory
{
public:
    QGCLoggingCategory(const char* category) { QGCLoggingCategoryRegister::instance()->registerCategory(category); }
};

それだけでするコンストラクタで、コンストラクタでQGCLoggingCategoryRegisterのログカテゴリを登録します。QGCLoggingCategoryRegister、登録した管理者である、比較的単純である、現在のアプリケーションのすべてのログカテゴリを維持する責任がある(ログインカテゴリ)、我々は底がまだFilterRulesのLoggingCategoryのこのクラスでのQtを使用して(ログレベル制御とフィルタリングを実現しました)。

QLoggingCategoryを使用する場合は、頻繁に2つの非常に重要なマクロが使用されますQ_DECLARE_LOGGING_CATEGORYQ_LOGGING_CATEGORY、マクロがマクロを定義するために使用されて宣言するために、次の二つのマクロのマクロ定義です:

// qloggingcategory.h  Qt5.12
#define Q_DECLARE_LOGGING_CATEGORY(name) \
    extern const QLoggingCategory &name();

#define Q_LOGGING_CATEGORY(name, ...) \
    const QLoggingCategory &name() \
    { \
        static const QLoggingCategory category(__VA_ARGS__); \
        return category; \
    }

マクロ展開を見つけることができた後、二人はマクロは宣言と関数を定義し、実際にあるので、ヘッダファイルで使用する公式の説明として追従することを確認しQ_DECLARE_LOGGING_CATEGORY、対応するソースファイルを使用しますQ_LOGGING_CATEGORY

また、注意するあなたは、ダイナミックリンクライブラリを使用している場合ということですQLoggingCategory、そしてあなたが外部に露出し、このLoggingCategoryを使用したい、あなたはそれが宣言された時にマクロを追加する必要がありDLL_EXPORT、DLLをビルドするとき、一般的には、マクロが設定されているQ_DECL_EXPORT;およびDLL、通常はマクロを参照しましたQ_DECL_IMPORTこの原則は、DLLのクラスが同じである内部に露出同様です。コンパイラのない同じバージョンのDLLにloggingCategoryはそれの外で使用することができ、エクスポートつながらない場合でも、一般的には、コンパイル時にCPPコンパイラは、関数名のC関数を変更しますか?見つけるために行くことができます興味を持っています。

QGCLoggingCategory中央マクロの長時間使用があります。

// QGCLoggingCategory.h  Stable_v3.5.1

/// @def QGC_LOGGING_CATEGORY
/// This is a QGC specific replacement for Q_LOGGING_CATEGORY. It will register the category name into a
/// global list. It's usage is the same as Q_LOGGING_CATEOGRY.
#define QGC_LOGGING_CATEGORY(name, ...) \
    static QGCLoggingCategory qgcCategory ## name (__VA_ARGS__); \
    Q_LOGGING_CATEGORY(name, __VA_ARGS__)

コメントは、マクロとの役割説明Q_LOGGING_CATEGORY同じことを、しかし、C / C ++のマクロプロセッサがあるに精通していない、static QGCLoggingCategory qgcCategory ## name (__VA_ARGS__);この部分は少し奇妙に思える、奇妙な部分があります##
これは##実際にはトークンで、何の意味がない、前処理後に削除されます。トークン貼り付けるオペレータいくつかの例があります。

#define type i##nt
type a; // same as int a; since i##nt pastes together to "int"

プリプロセッサマクロの結果を使用することができます見てみたいcpp file.cか、gcc -E file.c私は、ファイルに次のように入力します:

// testmacro.h
#define QGC_LOGGING_CATEGORY(name, ...) \
    static QGCLoggingCategory qgcCategory ## name (__VA_ARGS__);

#define type i##nt
type a; // same as int a; since i##nt pastes together to "int"

#define DECLARE_AND_SET(type, varname, value) type varname = value; type orig_##varname = varname;
DECLARE_AND_SET( int, area, 2 * 6 );

class QGCLoggingCategory {}

QGC_LOGGING_CATEGORY(FirmwareUpgradeLog,            "FirmwareUpgradeLog")

そして、CPPによる治療の結果を見てみましょうcpp testmacro.h

# 1 "testmacro.h"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "testmacro.h"





int a;


int area = 2 * 6; int orig_area = area;;

class QGCLoggingCategory {}

static QGCLoggingCategory qgcCategoryFirmwareUpgradeLog ("FirmwareUpgradeLog");

それは、治療後に見ることができ、マクロ定義は、特定の文字に拡張され、マクロが消えました。マクロ定義に##加えた後に拡大する署名(左右のスペースと一緒に)除去しました。この効果次のマクロは、理解が容易であり、それが構成QGCLoggingCategoryの例で使用され、各インスタンスに先行するqgcCategory接頭辞。

#define QGC_LOGGING_CATEGORY(name, ...) \
    static QGCLoggingCategory qgcCategory ## name (__VA_ARGS__);

次に、見てQGCLoggingCategoryRegister実装QGCLoggingCategoryRegisterすることにより、単回使用の実施の形態ではinstance()、外来(したがって、クラスのコンストラクタがために宣言された固有のオブジェクトインスタンス提供private修飾を)。それに、留意されたinstance()メソッド、オブジェクト・インスタンスの構成は_instance = new QGCLoggingCategoryRegister();後にも使用Q_CHECK_PTR(_instance);(メモリ割り当ての失敗を防ぐために)チェックします。

QGCLoggingCategoryRegister 各モジュールログのフィルタリングルールはQSettingsによって保存および復元されます。

void QGCLoggingCategoryRegister::setCategoryLoggingOn(const QString& category, bool enable)
{
    QSettings settings;

    settings.beginGroup(_filterRulesSettingsGroup);
    settings.setValue(category, enable);
}

bool QGCLoggingCategoryRegister::categoryLoggingOn(const QString& category)
{
    QSettings settings;

    settings.beginGroup(_filterRulesSettingsGroup);
    return settings.value(category, false).toBool();
}

構築上記の二つの機能がありますQSettingsオブジェクトのドメインが同じで、何のためのパラメータQSettingsオブジェクト構築の目的で、Qtの公式文書では、それは言わない:構築A QSettingsは設定ファイルアプリケーションのオブジェクトにアクセスするために行い、組織QCoreApplicationを呼び出して予め設定
:: setOrganizationName()、QCoreApplication :: setOrganizationDomain()、及びQCoreApplication :: setApplicationName() 内のQGCApplicationプログラムがドメインQSettingsに対応するように、コンストラクタ定義された組織名とOrganizationDomain彼らは同じです。

しかし、少し悪いがあります:beginGroupの後に呼び出すことはありませんendGroupパケットを閉鎖する方法。内部これは、settingsオブジェクトは自動的に機能が戻るとき、それは問題ではないかもしれない破壊、ヒープ上に割り当てられています。しかし、あなたはプログラムの設定を保存するために来た場合、そのアプリケーションにグローバルオブジェクト経由で設定を呼び出してbeginGroup、彼らが呼び出すことを忘れ後にendGroup大きな問題が表示されることがあります。のでグループはネストすることができ、これはおそらくあなたが最後に格納された値を読み出すことができない通常の場合になります。

参照

見-拡大-C-マクロ
トークン貼り付けるオペレータ

おすすめ

転載: www.cnblogs.com/brifuture/p/11707317.html