用户属性是后面新增加的一个功能,自定义控件如果采用的Q_PROPERTY修饰的属性,会自动识别到属性栏中,这个一般称为控件属性,在组态设计软件中,光有控件本身的控件属性还是不够的,毕竟这些属性仅仅是以外观为主,并不能表示某个设备的属性,所以需要除了这个控件属性以外增加用户属性来存储该控件关联的设备属性,比如设备编号、设备名称、地理位置等信息,而这些信息也要和控件属性一样,都能导入导出到xml文件,同时能支持多个用户属性,用户自己填写名字和值,名字和值都支持中文描述,在xml文件中为了区分用户属性和控件属性,特意在用户属性前面加上user-前缀来表示,这样在读取xml文件加载控件的时候,识别到user-开头的都存储到该控件的用户属性列表中。自从有了用户属性的机制,大大拓展了控件的现有功能,相当于可以绑定N个自定义的数据,而这些用户属性直接采用setProperty来设置即可,然后通过property来读取就行,为了支持中文的属性名称,需要设置属性的时候转换一下:widget->setProperty(name.toStdString().c_str(), value);
体验地址:https://gitee.com/feiyangqingyun/QUCSDK
https://github.com/feiyangqingyun/qucsdk
void frmMain::openFile(const QString &fileName)
{
//如果控件列表没有则不用继续
if (ui->listWidget->count() == 0) {
return;
}
//打开文件
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
return;
}
//将文件填充到dom容器
QDomDocument doc;
if (!doc.setContent(&file)) {
file.close();
return;
}
file.close();
listSelect.clear();
listUserProperty.clear();
xmlName = fileName;
//先清空原有控件
QList widgets = ui->centralwidget->findChildren();
qDeleteAll(widgets);
widgets.clear();
//先判断根元素是否正确
QDomElement docElem = doc.documentElement();
if (docElem.tagName() == "canvas") {
QDomNode node = docElem.firstChild();
QDomElement element = node.toElement();
while(!node.isNull()) {
//控件名称
QString name = element.tagName();
//取出当前控件在控件列表中的索引,如果不存在则意味着配置文件中的该控件不存在了
int index = listNames.indexOf(name);
if (index < 0) {
continue;
}
//存储控件的坐标位置和宽度高度
int x, y, width, height;
//存储自定义控件属性
QList > propertys;
//存储控件自定义属性
QStringList userProperty;
//节点名称不为空才继续
if (!name.isEmpty()) {
//遍历节点的属性名称和属性值
QDomNamedNodeMap attrs = element.attributes();
for (int i = 0; i < attrs.count(); i++) {
QDomNode node = attrs.item(i);
QString nodeName = node.nodeName();
QString nodeValue = node.nodeValue();
//qDebug() << name << nodeName << nodeValue;
//优先取出坐标+宽高属性,这几个属性不能通过设置弱属性实现
if (nodeName == "x") {
x = nodeValue.toInt();
} else if (nodeName == "y") {
y = nodeValue.toInt();
} else if (nodeName == "width") {
width = nodeValue.toInt();
} else if (nodeName == "height") {
height = nodeValue.toInt();
} else if (nodeName.startsWith("user-")) {
//取出user-开头的自定义属性
nodeName = nodeName.split("-").last();
userProperty << QString("%1|%2").arg(nodeName).arg(nodeValue);
} else {
QVariant value = QVariant(nodeValue);
//为了兼容Qt4,需要将颜色值的rgba分别取出来,因为Qt4不支持16进制字符串带透明度
//#6422a3a9 这种格式依次为 argb 带了透明度的才需要特殊处理
if (nodeValue.startsWith("#") && nodeValue.length() == 9) {
bool ok;
int alpha = nodeValue.mid(1, 2).toInt(&ok, 16);
int red = nodeValue.mid(3, 2).toInt(&ok, 16);
int green = nodeValue.mid(5, 2).toInt(&ok, 16);
int blue = nodeValue.mid(7, 2).toInt(&ok, 16);
value = QColor(red, green, blue, alpha);
}
propertys.append(qMakePair(nodeName, value));
}
}
}
//qDebug() << name << x << y << width << height;
//根据不同的控件类型实例化控件
int countWidget = listWidgets.count();
int countProperty = propertys.count();
for (int i = 0; i < countWidget; i++) {
QString className = listWidgets.at(i)->name();
if (name == className) {
//生成对应的控件
QWidget *widget = createWidget(i);
//逐个设置自定义控件的属性
for (int j = 0; j < countProperty; j++) {
QPair property = propertys.at(j);
QString name = property.first;
QVariant value = property.second;
widget->setProperty(name.toStdString().c_str(), value);
}
//设置控件坐标及宽高
widget->setGeometry(x, y, width, height);
//实例化选中窗体跟随控件一起
newSelect(widget, userProperty);
break;
}
}
//移动到下一个节点
node = node.nextSibling();
element = node.toElement();
}
}
}
void frmMain::saveFile(const QString &fileName)
{
//如果控件列表没有则不用继续
if (ui->listWidget->count() == 0) {
return;
}
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) {
return;
}
//以流的形式输出文件
QTextStream stream(&file);
//构建xml数据
QStringList list;
//添加固定头部数据
list << "";
//添加canvas主标签,保存宽高和背景图片,还可以自行添加其他属性
list << QString("";
//写入文件
QString data = list.join("\n");
stream << data;
file.close();
}