gpt4 book ai didi

c++ - 映射多变量/层系统的泛化

转载 作者:太空狗 更新时间:2023-10-29 23:07:55 26 4
gpt4 key购买 nike

我用 C++/QT 编写了一个应用程序,它与设备通信以读取/写入其变量,将它们放入/获取到一个结构中,并在 gui 中显示它们用于查看/编辑目的。

1) 该设备附带一个示例 C 代码,该代码还定义了通信协议(protocol)(以非常糟糕的方式),例如:

#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;
.
.
};

它基本上是从设备读取的数据的存储/投影。有 4 种不同类型的 POD 变量。

3) 最后我的 gui 有 gui 元素来显示和编辑 MyDeviceData 的实例

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

现在我的问题是:

1) 我正在做 MY_DEVICE_VAR1 的映射 -> MyDeviceData::var1 -> MyGUI::var1ifswitch/case 语句,我对此并不感到自豪。什么是更好的“程序化”映射方式?

2) 当 gui 元素的值发生变化时,我想 向卡片发送更新后的值。除了重写“textChangedselectedIndexChanged”等事件的处理函数之外,还有什么“更聪明”的方法吗? (QSignalMapper?)

3) 在这种项目中,是否可以将整个苦差事泛化? (代码生成器工具?模板?)

最佳答案

我最近遇到了完全相同的问题,尽管我是设计设备、固件和通信协议(protocol)的人。

我认为必须使用模型/ View 来保持理智。

我将所有变量作为派生自 QAbstractTableModel 的数据模型类中的元素。这是因为有固定数量的简单参数(行),并且每个设备(列)的参数都是相同的。不过,很快,我将不得不转向树模型,因为一些参数在内部被构造为列表、 vector 或矩阵,将它们直接暴露给 View 会很有帮助,而不仅仅是格式化字符串.

模型类还有一些方便的 getter/setter,这样您就不必通过行/列来引用参数。通过 QModelIndex 进行的行/列访问仅供 View 使用。

我选择将 UserRole 用于直接表示的值(通常是 SI 单位的两倍),并使用 Display 和 Edit 角色将格式化/缩放数据呈现给小部件。

对于非 View 控件,需要一个 Binder 对象。 QDataWidgetMapper是Qt提供的,最好使用它。

前一段时间我没有注意到有小部件映射器,所以我编写了一个自定义的 Binder 对象(派生自 QObject),它为每个 GUI 控件实例化,以将模型的某个索引绑定(bind)到非- 查看 Qt 控件小部件。另一种方法是使用 QListView,每个 View 都有一个只公开一个元素的代理模型,并正确分配委托(delegate)。不过,这会带来很多开销。 Binder 对象方法非常轻量级。

模型 View 方法还使人们能够轻松地分解出每个控件的最新指示。

  • 当应用程序首次启动时,模型可以(通过专用角色)指示值无效。这可以在控件上放置一个 x 十字或理发杆,以清楚地表明那里没有有效值。

  • 当设备处于事件状态并且用户修改控件时,不同的角色可以指示模型中的值已更改,但尚未传播到设备。

  • 当设备通信代码从模型中获取更改并将其提交给设备时,它可以将相关信息告知模型,而 View (实际上是 biner)将自动获取并更新控制。

  • 向模型添加 Model * clone() const 方法,或添加序列化/反序列化运算符,允许您轻松拍摄模型快照,并实现撤消/重做、提交/还原等

Binder 的相关片段在这里:

// 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();
}

关于c++ - 映射多变量/层系统的泛化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11173378/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com