4

デバイスと通信して変数の読み取り/書き込みを行い、それらを構造体に配置/取得し、表示/編集の両方の目的で GUI に表示するC++ / QTを使用してアプリケーションを作成しました。

1)デバイスには、次のような通信プロトコルも(非常に悪い方法で)定義するサンプルcコードが付属しています。

#define VALUE_1 0x12345678
#define VALUE_2 0xDEADBEEF
#define MY_DEVICE_VAR (VALUE_1 << 4) & (VALUE_2 >> 6)
#define MY_DEVICE_VAR_1 (MY_DEVICE_VAR & (VALUE_1 << 2)
#define MY_DEVICE_VAR_2 (MY_DEVICE_VAR & (VALUE_2 << 4)
#define MY_DEVICE_VAR_2 (MY_DEVICE_VAR & (VALUE_2 << 4)
// .. and 300 more lines like above

したがって、変数VAR_1は次のように表されますMY_DEVICE_VAR_1

2)デバイスのすべての変数を保持する構造体があります。

struct MyDeviceData
{
    int var1;
    double var2;
    char var3;
    bool var4;
        .
        .
};

基本的には、デバイスから読み取ったデータのストレージ/投影です。POD 変数には 4 つの異なるタイプがあります。

3)最後に、私の GUI には、MyDeviceData のインスタンスを表示および編集するための GUI 要素があります。

class MyGuI
{
    QLineEdit var1;
    QLineEdit var2;
    QComboBox var3;
    QCheckBox var4;
       .
       .
};

今私の質問は次のとおりです。

1)MY_DEVICE_VAR1 -> MyDeviceData::var1-> MyGUI::var1with ifandステートメントのマッピングを行っていますが、switch/caseこれは誇りに思っていません。マッピングを行うためのより良い「プログラムによる」方法は何でしょうか?

2) GUI 要素の値が変更された場合、更新された値のみをカードに送信したい。textChanged「 、 」などのイベントのハンドラー関数をオーバーライドする以外にselectedIndexChanged、「よりスマートな」メソッドはありますか? (QSignalMapper?)

3)この種のプロジェクトでは、ドラッジ作業全体を一般化できますか? (コード生成ツール? テンプレート?)

4

1 に答える 1

2

私は最近、まったく同じ問題に直面しましたが、デバイス、そのファームウェア、および通信プロトコルも設計しました。

正気を保つためにはモデル/ビューを使わなければならないと思います。

から派生したデータモデルクラスの要素としてすべての変数がありますQAbstractTableModel。これは、単純なパラメーター(行)の数が固定されており、各デバイス(列)ごとに同じであるためです。ただし、すぐにツリーモデルに移行する必要があります。これは、一部のパラメーターが内部的にリスト、ベクトル、またはマトリックスとして構造化されているためです。これらのパラメーターは、フォーマットされた文字列としてだけでなく、直接ビューに公開すると便利です。 。

モデルクラスには便利なゲッター/セッターもいくつかあるので、行/列でパラメーターを参照する必要はありません。aを介した行/列へのアクセスQModelIndexは、ビューのみが使用できます。

直接表現された値(ほとんどの場合、SI単位で2倍)にUserRoleを使用し、フォーマット/スケーリングされたデータをウィジェットに表示するために表示および編集の役割を使用することを選択しました。

ビュー以外のコントロールの場合、バインダーオブジェクトが必要です。QDataWidgetMapperQtによって提供され、理想的にはそれを使用する必要があります。

しばらく前、ウィジェットマッパーがあることに気づかなかったので、GUIコントロールごとにインスタンス化されるカスタムバインダーオブジェクト(QObjectから派生)を作成して、モデルの特定のインデックスを非ビューQtにバインドしました。コントロールウィジェット。もう1つのアプローチは、を使用しQListView、ビューごとに1つの要素のみを公開するプロキシモデルを用意し、デリゲートを適切に割り当てることです。ただし、これにより多くのオーバーヘッドが発生します。バインダーオブジェクトのアプローチは非常に軽量です。

モデルビューアプローチにより、各コントロールの最新の表示を簡単に除外することもできます。

  • アプリケーションが最初に起動されたとき、モデルは(専用の役割を介して)値が無効であることを示すことができます。これにより、コントロールにXクロスまたは理髪店の看板ポールを配置して、そこに有効な値がないことを明確に示すことができます。

  • デバイスがアクティブで、ユーザーがコントロールを変更すると、別の役割で、モデルで値が変更されたが、まだデバイスに伝達されていないことを示すことができます。

  • デバイス通信コードがモデルから変更を取得してデバイスにコミットすると、モデルにその変更を通知でき、ビュー(実際にはバイナー)が自動的に取得してコントロールを更新します。

  • モデルにメソッドを追加するModel * clone() constか、シリアル化/逆シリアル化演算子を追加すると、モデルのスナップショットを簡単に作成し、元に戻す/やり直し、コミット/元に戻すなどを実装できます。

バインダーの関連スニペットは次のとおりです。

// constructor
Binder::Binder(QAbstractItemModel * model_, const QModelIndex & index_, QObject * object) :
   QObject(object),
   model(model_),
   index(index_),
   sourceRole(Qt::DisplayRole),
   property(""),
   target(object),
   lockout(false)
{
   Q_ASSERT(index.isValid());
   // replicate for each type of control
   if (qobject_cast<QDoubleSpinBox*>(object)) {
      connect(object, SIGNAL(valueChanged(double)), SLOT(doubleSpinBoxGet(double)));
      connect(index.model(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(doubleSpinBoxSet(QModelIndex, QModelIndex)));
   }
   else if (....) 
}

// getter/setter for QDoubleSpinBox

void Binder::doubleSpinBoxGet(double val)
{
   if (lockout) return;
   QScopedValueRollback<bool> r(lockout);
   lockout = true;
   model->setData(index, val, sourceRole);
}

void Binder::doubleSpinBoxSet(const QModelIndex & tl, const QModelIndex & br)
{
   if (lockout) return;
   if (! isTarget(tl, br)) return;
   QScopedValueRollback<bool> r(lockout);
   lockout = true;
   if (! index.data().canConvert<double>()) return;
   qobject_cast<QDoubleSpinBox*>(target)->setValue(index.data(sourceRole).toDouble());
}

// helper

bool Binder::isTarget(const QModelIndex & topLeft, const QModelIndex & bottomRight)
{
   return topLeft.parent() == bottomRight.parent()
          && topLeft.parent() == index.parent()
          && topLeft.row() <= index.row()
          && topLeft.column() <= index.column()
          && bottomRight.row() >= index.row()
          && bottomRight.column() >= index.column();
}
于 2012-06-25T02:23:33.053 に答える