我目前正在构建游戏引擎。
UML-图:
[MainWindow]
[CNode]
[CNode2D]
[CSprite2D]
每个节点都有自己的属性(例如"名称","宽度","高度"),其中每个node-type
有不同的属性。
现在,我想显示我的节点属性(右下角):
为了实现这一点,我有一个struct
代表
struct propertyTemplate {
propertyTemplate (QString namei, QString valuei, QString expectedi, bool changedi = false) {
name = namei;
value = valuei;
expected = expectedi;
changed = changedi;
}
QString name;
QString value;
QString expected; //What the programm expects;
bool changed = false; //if these are the default values
};
CNode有一个vector of propertyTemplate
,它被填入CSprite2D的构造函数
properties.push_back(propertyTemplate("Name", getName(), "string"));
properties.push_back(propertyTemplate("Sprite-link", "", "link"));
properties.push_back(propertyTemplate("Height", "100", "float"));
properties.push_back(propertyTemplate("Width", "100", "float"));
properties.push_back(propertyTemplate("Position X", "0", "float"));
properties.push_back(propertyTemplate("Position Y", "0", "float"));
properties.push_back(propertyTemplate("Rotation", "0", "string"));
当必须显示属性时,我运行此函数:
void MainWindow::listProperties () {
if (ui->treeWidget_2->currentItem()->text(ui->treeWidget_2->columnAt(100)) == "Sprite2D") {
CSprite2D *sprite = static_cast< CSprite2D* >(getNodeByName(ui->treeWidget_2->currentItem()->text(ui->treeWidget_2->columnAt(0)))); //gets a pointer to the string judging by nam
if (sprite == NULL) { //if the return value is NULL
} else {
int counter = 0; //counter for the while-loop
//for ( auto momItem : propertyItems) delete momItem; //item
ui->treeWidget_3->clear();
propertyItems.clear();
while (counter < sprite->properties.size()) {
propertyTemplate prop = sprite->properties[counter]; //gets the current item in the property-array
propertyItems.push_back(new QTreeWidgetItem); //gets filled by the while-loop
propertyItems[propertyItems.size()-1]->setText(0, prop.name); //sets the text of the item
propertyItems[propertyItems.size()-1]->setText(1, prop.value);//set the text of the other item
propertyItems[propertyItems.size()-1]->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);;
ui->treeWidget_3->insertTopLevelItem(ui->treeWidget_3->topLevelItemCount(), propertyItems[propertyItems.size()-1]); //appends the items
counter ++;
}
}
}
}
问题:当用户想要更改属性时,程序真的不知道要调用的setter,因为real properties
存储在变量中... propertyTemplate的数组真的很多只是为了显示QTreeWidget内的属性。
我很难说你可以在初始化数组时添加一个函数指针,但我不能,因为指针在函数内部...我也试过一个lambda,但是
properties.push_back(propertyTemplate("Rotation", "0", "string",[&this] () {setName()};));
给了我一个编译错误(因此我更新了propertyTemplate的构造函数,所以不要责怪构造函数;)
我已经和我的橡皮鸭和朋友聊过了,他们都告诉我要用另一种方法,但我无法想到更好的方法。
另外:我是C ++ / Qt的新手,所以我可能只是琐碎错误的受害者。在这种情况下抱歉。
答案 0 :(得分:1)
我认为你这是错误的做法。你应该真的使用Qt属性系统有很多原因,但主要是那两个:
首先,Qt有MOC--元对象编译器,它为每个对象生成元信息。该信息包含属性的数量,它们的名称等。您可以迭代属性并访问有关它们的详细信息,您可以使用它来通过模型填充属性编辑器。这样它就可以处理任何对象的任意属性,而不是有一些静态配置,你必须返回并为每个新类型或类型更改做。
第二 - 对于Qt属性,您有QObject::property()
和QObject::setProperty()
与QVariant
协同工作,在大多数情况下,这些属性可以处理类型转换。因此,您只需要拥有属性名称和QVariant
保持兼容的值,您不需要知道要调用的调用者等等。这使得获取和设置属性值变得更加容易,无论其类型如何。
您需要查看的课程是QMetaObject和QMetaProperty,可能还有QVariant和QAbstractListModel。
另外,我发现你正在使用GUI元素进行数据存储,这是一个很大的 NO-NO 。不要将数据放入GUI中,您将来会遇到麻烦。将数据保存在数据层中,并仅从GUI访问该数据。将节点放在向量中,然后为该向量实现模型适配器,然后在GUI中使用model-view-delegate。
所以结构应该是这样的:
node
|
nodes vector
|
nodes model <- GUI nodes view <- node delegate
|
selected node
|
QMetaObject/QMetaProperty query
|
property model <- GUI property view <- property delegate
|
set/get