問題
Qtには素晴らしいものがあります-Q_PROPERTYを使用すると、任意のQObjectクラスに必要なプロパティを追加できます。 しかし、場合によってはそれらを使用するのは不便です。
たとえば、多くの異なるオブジェクトがあり(または作成できる)、構成する必要があるアプリケーションがあります(選択したオブジェクトのプロパティを含むダイアログを表示します)。 そのようなアプリケーションの例としては、ほぼすべてのエンジニアリングプログラム、ベクターグラフィックエディター、最終的にはVisual Studioなどがあります。
そのため、ユーザーが「構成」できるオブジェクトは多数あります。 それ以外の場合は、各オブジェクトに独自の設定ダイアログを実装する必要があるため、これに何らかの汎用メカニズムを使用することは論理的です。 Q_PROPERTYはこれに完全に適しているわけではありません。 まず、Q_PROPERTYを編集するための標準ウィジェットがありません。 第二に、これらの目的でサードパーティのウィジェットを使用している場合でも、プロパティとともに標準のウィジェット(少なくともobjectName)が表示されます。 さらに、Q_PROPERTYは階層をサポートしていません(関連するプロパティをグループ化すると便利な場合があります)。 説明なし(このプロパティを説明するテキスト文字列); GUIでQ_PROPERTYの外観をカスタマイズする方法はありません(使いやすさを向上させるため)。
所有者オブジェクトから独立した別個のオブジェクトとしてプロパティを操作することがプログラマにとって便利な場合があります。 これらは、所有者オブジェクト全体を転送することなく、またはプロパティの個別のサブグループを転送することなく、どこかに転送できます。
解決策
便利なプロパティを作成しようとして、 QtnPropertyプロジェクトを作成しました。 さらに、このプロジェクトの目的とこのライブラリの使用方法について説明します。
まず、ライブラリはいくつかの部分で構成されています。
- QtnPropertyCore-非GUI関連クラスのライブラリ
- QtnPropertyWidget-プロパティを編集するためのウィジェットと、外観をカスタマイズしてさまざまなプロパティを編集するためのデリゲート
- QtnPEGは、* .pefファイルからPropertySetのC ++クラスを作成するアプリケーション(mocジェネレーターに似ています)(これはプロパティを記述するより簡単な方法で、構文はQMLに似ています)
- QtnPropertyTests - QtnPropertyCoreライブラリのテスト
- QtnPropertyDemoは、 QtnPropertyWidgetを使用して、スクリプトからプロパティを編集し、文字列「SuperProperty.SubProperty = value」の形式でテキストを設定できるデモアプリケーションです。
QtnPropertyCore
まず、ライブラリは2つのメインクラスQtnPropertyとQtnPropertySetを定義します。 1つ目は、すべてのタイプのプロパティ( QtnPropertyBoolやQtnPropertyFloatなど )の基本であり、2つ目はプロパティのグループを表します。 QtnPropertyとQtnPropertySetの両方には、共通の親であるQtnPropertyBaseがあります。これは、QObjectの子孫です。 QtnPropertyBaseクラスでは、 QtnPropertyとQtnPropertySetに共通するすべてのものが定義されています:
- QString name -nameプロパティまたはpropertyset(objectNameと同じ)
- QString description - QtnPropertyWidgetの下部パネルに表示できるテキストの説明
- qint32 id-グループ内の一意のプロパティID(バイナリ形式で保存するときに使用)
- QtnPropertyState state-プロパティの状態(例:QtnPropertyStateImmutable-編集不可のプロパティまたはQtnPropertyStateInvisible-不可視)
- ロード/保存 -QDataStreamを介した保存/ロード
- fromStr / toStr-プロパティ値を/からQStringに変換する
- fromVariant / toVariant-プロパティ値を/からQVariantに変換する
- propertyWillChange-プロパティが変更される前にトリガーされる信号(値だけでなく、名前、説明、ID、状態などの他の属性も変更する場合)
- propertyDidChange-プロパティの変更後にトリガーされる信号(propertyWillChangeと対称)
QtnPropertySetクラスには、子プロパティとそれらを操作するためのメソッドのリストも含まれています。 プロパティの各タイプ(整数など)には、2つのクラス( QtnPropertyIntおよびQtnPropertyIntCallback )があります。 1つ目は値をクラスに保存し、2つ目は値を取得または保存するための関数を呼び出します。
QtnPropertyCoreモジュールに直接実装されるプロパティのリストは次のとおりです。
- QtnPropertyBool-ブール値を表します。
- QtnPropertyInt-符号付き整数値を表します。
- QtnPropertyUInt-符号なし整数値を表します。
- QtnPropertyFloat-浮動小数点の実数値を表します。
- QtnPropertyDouble-実際の倍精度値を表します。
- QtnPropertyEnum-列挙からの値を表します。
- QtnPropertyEnumFlags-列挙からの値の組み合わせを表します。
- QtnPropertyQString-文字列値を表します。
- QtnPropertyQPoint -QPoint値を表します。
- QtnPropertyQSize -QSize値を表します。
- QtnPropertyQRect -QRect値を表します。
- QtnPropertyQFont -QFont値を表します。
- QtnPropertyQColor -QColor値を表します。
すべての数値プロパティ( QtnPropertyInt 、 QtnPropertyUInt 、 QtnPropertyFloat 、 QtnPropertyDouble )には3つの追加メソッドがあります。
- minValueは最小許容値です。
- maxValueは最大許容値です。
- stepValue-値を変更するステップ。
QtnPropertyWidget
このモジュールには、2つのウィジェットとプロパティデリゲートが含まれています。
QtnPropertyViewクラスは、プロパティセットのツリーウィジェットを実装します。
QtnPropertyWidgetクラスは複合で、下部パネルとしてQtnPropertyViewとQLabelが含まれています。
特定のプロパティの外観または動作を変更するために、デリゲートが導入されました。 たとえば、 QtnPropertyBoolには、 QtnPropertyDelegateBoolCheckとQtnPropertyDelegateBoolComboboxの 2つのデリゲートがあります。 1つ目はチェックボックスを表示し、2つ目は2つのカスタム値(trueおよびfalse)を持つコンボボックスを表示します。 独自のデリゲートを作成してデフォルトとして設定すると、このデリゲートを使用してこのタイプのすべてのプロパティが表示されます。 新しいプロパティタイプよりも新しいデリゲートタイプを作成する方が簡単で便利な場合があります。 たとえば、ファイルパスを保存するためのプロパティは、 QtnPropertyQStringの特別なQtnPropertyDelegateQStringFileデリゲートを介して実装されます。
使い方
たとえば、テキストエディターのプロパティの小さなセットを考えます。
これはユーザーに見せたいものです。
そして、このようなプロパティセットを取得するためにプログラマが行う必要があるのは次のとおりです。
QtnPropertySet* textProperties = new QtnPropertySet(owner); QtnPropertyBool* enableWrapping = new QtnPropertyBool(textProperties); enableWrapping->setName(tr("enableWrapping")); enableWrapping->setDescription(tr("Enable/disable text wrapping")); enableWrapping->setValue(true); QtnPropertyQColor* textColor = new QtnPropertyQColor(textProperties); textColor->setName(tr("textColor")); textColor->setDescription(tr("Foreground text color")); textColor->setValue(QColor(0, 0, 0)); QtnPropertySet* Tabulation = new QtnPropertySet(textProperties) Tabulation->setName(tr("Tabulation")); Tabulation->setDescription(tr("Tabulation settings")); QtnPropertyBool* replaceWithSpaces = new QtnPropertyBool(Tabulation); replaceWithSpaces->setName(tr("replaceWithSpaces"); replaceWithSpaces->setDescription(tr("Automatically replace tabs with spaces")); replaceWithSpaces->setValue(false); QtnPropertyUInt* tabSize = new QtnPropertyUInt(Tabulation); tabSize->setName(tr("tabSize")); tabSize->setDescription(tr("Number of spaces to be placed.")); tabSize->setState(QtnPropertyStateImmutable); tabSize->setValue(4); tabSize->setMinValue(1); tabSize->setMaxValue(10); // propertyDidChange auto lambda = [tabSize, replaceWithSpaces](const QtnPropertyBase* changedProperty, const QtnPropertyBase* firedProperty, QtnPropertyChangeReason reason) { // if (reason & QtnPropertyChangeReasonValue) { if (*replaceWithSpaces) // tabSize tabSize->removeState(QtnPropertyStateImmutable); else // tabSize tabSize->addState(QtnPropertyStateImmutable); }; QObject::connect(replaceWithSpaces, &QtnProperty::propertyDidChange, lambda); // replaceWithSpaces ...
プログラマーの生活を楽にするために(または、プログラマーでない人にプロパティを説明する機会を与えるために)、小さなQtnPEGコードジェネレーターが開発されました 。
Text.pefファイルの例の説明は次のとおりです。
property_set Text { Bool enableWrapping { description = "Enable/disable text wrapping"; value = true; } QColor textColor { description = "Foreground text color"; value = QColor(0, 0, 0); } property_set Tabs Tabulation { description = "Tabulation settings"; Bool replaceWithSpaces { description = "Automatically replace tabs with spaces"; value = false; // delegate ComboBox { // true labelTrue = "On"; // false labelFalse = "Off"; } // replaceWithSpaces.propertyDidChange slot propertyDidChange { tabSize.switchState(QtnPropertyStateImmutable, !replaceWithSpaces); } } UInt tabSize { description = "Number of spaces to be placed."; state = QtnPropertyStateImmutable; value = 4; } } }
シンプルで簡潔。 QtnPEGは2つのファイルを作成します:Text.peg.hとText.peg.cpp、2つのクラスがあります。 QtnPropertySetTextおよびQtnPropertySetTabsはQtnPropertySetから派生したクラスです 。
生成されたクラスでは、たとえばQtnPropertySetTextの次のサブプロパティ宣言を確認できます。
// start children declarations QtnPropertyBool& enableWrapping; QtnPropertyQColor& textColor; QtnPropertySetTabs& Tabulation; // end children declarations
したがって、C ++コードのプログラマは、フィールドを持つ構造体としてこのクラスを操作できます。 例:
void doSomething(const QtnPropertySetText& textParams, QString& text) { if (textParams.Tabulation.replaceWithSpaces) { QString spaces(QChar::Space, textParams.Tabulation.tabSize); text.replace(QChar::Tabulation, spaces); } }
まとめ
私は自分のプロジェクトについて何かアイデアを出せたと思います。
特に多くの設定があり、すべてのためのGUIを開発している場合、それが誰かにとって有用であれば、私はうれしいです。 あなたの意見で、 QtnPropertyを完全に使用するために十分な機能がない場合、コメントしてください。