传统操作都是通过qtCreator 手动画界面,托按钮建立处理槽函数
这样做有以下不好:
- 改界面比较麻烦
- 如果把一个widget的按钮,移动到另一个widget,而且这2个widget是不同人写的,移动按钮位置会特别麻烦,因为按钮响应的处理函数里,可能用到一些类的成员变量。。。
效果
image.png image.png分享一下我的代码,我的项目暂时只用到QToolButton,所以下面写的比较简单
1. 创建xml,解析xml接口
XmlRecipe.h
#ifndef XMLRECIPE_H
#define XMLRECIPE_H
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QMap>
#include <QVector>
#include <QDebug>
typedef struct
{
QString _Type; /* 按钮类型 */
QString _Text; /* 按钮显示文字 */
QString _Size; /* 按钮大小 */
QString _Cmd; /* 点击按钮发送的command*/
QString _Group; /* 按钮属于哪个组 */
}UI_Config;
class XmlRecipe
{
public:
XmlRecipe();
public:
/** 写xml, 一个ui对应一个xml */
/* 文件 */
static bool xmlWrite_fileOperation(QString path);
public:
/** 读xml,一个ui对应一个xml*/
static bool xmlReader(QString path, QString &widgetTitle, QMap<int, QVector<UI_Config>> &retMap);
//每个按钮的节点遍历
static void ParseButton(QXmlStreamReader &reader, UI_Config &obj);
};
#endif // XMLRECIPE_H
XmlRecipe.cpp
#include "XmlRecipe.h"
#include <QFile>
XmlRecipe::XmlRecipe()
{
}
/***********************************************************************************
生成一个界面的xml
***********************************************************************************/
bool XmlRecipe::xmlWrite_fileOperation(QString path)
{
QFile f(path);
if(!f.open(QIODevice::WriteOnly | QIODevice::Text))
return false;
QXmlStreamWriter writer(&f);
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement("JQRecipe");
writer.writeAttribute("Title", "文件" );
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "打开" );
writer.writeTextElement("Command", "OPEN_FILE");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "文件编辑_1"); //这个加个后缀1是为了后面排序
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "新建" );
writer.writeTextElement("Command", "NEW_FILE");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "文件编辑_1");
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "保存" );
writer.writeTextElement("Command", "SAVE_FILE");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "文件编辑_1");
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "另存" );
writer.writeTextElement("Command", "SAVEAS_FILE");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "文件编辑_1");
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "撤销" );
writer.writeTextElement("Command", "BACKWARD");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "操作_2");
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "恢复" );
writer.writeTextElement("Command", "ForWARD");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "操作_2");
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "导入CAD" );
writer.writeTextElement("Command", "IMPORT_CAD");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "导入_3");
writer.writeEndElement();
writer.writeStartElement("Button");
writer.writeTextElement("Type", "QToolButton");
writer.writeTextElement("Text", "缩放" );
writer.writeTextElement("Command", "CAD_ZOOM");
writer.writeTextElement("Size", "60,60");
writer.writeTextElement("Group", "导入_3");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
f.close();
return true;
}
/***********************************************************************************
解析一个界面的xml
***********************************************************************************/
bool XmlRecipe::xmlReader(QString path, QString &widgetTitle, QMap<int, QVector<JQ_UI_Config>> &retMap)
{
retMap.clear();
QFile f(path);
if(!f.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
QXmlStreamReader reader(&f);
while(!reader.atEnd())
{
QXmlStreamReader::TokenType type=reader.readNext();
if (type == QXmlStreamReader::StartElement && reader.name() == "JQRecipe")
{
QXmlStreamAttributes attributes = reader.attributes();
if (attributes.hasAttribute("Title")) {
widgetTitle = attributes.value("Title").toString();
}
}
if(type == QXmlStreamReader::StartElement && reader.name() == "Button")
{
UI_Config obj;
ParseButton(reader, obj);
int key = obj._Group.split('_').at(1).toInt();
if (retMap.find(key) == retMap.end())
{
QVector<UI_Config> vec;
vec.push_back(obj);
retMap.insert(key, vec);
}
else
{
retMap.find(key).value().push_back(obj);
}
}
}
reader.clear();
f.close();
return true;
}
/***********************************************************************************
解析QToolButton节点数据
***********************************************************************************/
void XmlRecipe::ParseButton(QXmlStreamReader &reader, UI_Config &obj)
{
while (!reader.hasError())
{
if (reader.isEndElement() && reader.name() == "Button")
break;
if (reader.isStartElement() && reader.name() == "Type")
{
obj._Type = reader.readElementText();
}
else if (reader.isStartElement() && reader.name() == "Text")
{
obj._Text = reader.readElementText();
}
else if (reader.isStartElement() && reader.name() == "Command")
{
obj._Cmd = reader.readElementText();
}
else if (reader.isStartElement() && reader.name() == "Size")
{
obj._Size = reader.readElementText();
}
else if (reader.isStartElement() && reader.name() == "Group")
{
obj._Group = reader.readElementText();
}
reader.readNext();
}
}
2. 解析上面读取xml获取的数据,生成QWidget
JQWidgetgenerate .h
#ifndef JQWIDGETGENERATE_H
#define JQWIDGETGENERATE_H
#include "core/doc/JQXmlRecipe.h"
#include <QWidget>
/**
* @brief The JQWidgetgenerate class
* #构建xml数据获取的Widget
*/
class JQWidgetgenerate : public QWidget
{
Q_OBJECT
public:
JQWidgetgenerate(QWidget *parent = nullptr);
void setupJQUi(QMap<int, QVector<JQ_UI_Config>> &map, QString windowTitle);
signals:
void sendCMD(QString);
};
#endif // JQWIDGETGENERATE_H
JQWidgetgenerate .cpp
#include "JQWidgetgenerate.h"
#include <QGridLayout>
#include <QToolButton>
#include <QLabel>
#include <QFrame>
#include <QCoreApplication>
JQWidgetgenerate::JQWidgetgenerate(QWidget *parent) : QWidget(parent)
{
}
void JQWidgetgenerate::setupJQUi(QMap<int, QVector<JQ_UI_Config>> &map, QString windowTitle)
{
//图片路径
#ifdef Q_OS_MAC
QString currentExeDir = QCoreApplication::applicationDirPath() +"/../Resources/Images/";
#else
QString currentExeDir = QCoreApplication::applicationDirPath() +"/Resources/Images/";
#endif
QString style =
"QToolButton{ border-style:flat;}"
"QToolButton:hover{color:rgb(75,0,130); min-height:40; border-style:solid; "
" border-top-left-radius:2px;"
" border-top-right-radius:2px;"
" border:1px;"
" border-radius:5px;padding:2px 4px;"
;
QWidget *retWidget = this;
retWidget->setObjectName(windowTitle);
retWidget->resize(700, 110);
QGridLayout *gridLayout = new QGridLayout(retWidget);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
gridLayout->setSizeConstraint(QLayout::SetFixedSize);
gridLayout->setHorizontalSpacing(0);
gridLayout->setVerticalSpacing(10);
//左上右后
gridLayout->setContentsMargins(0, -1, 0, 0);
int index_btn = 0;
int index_label = 0;
for (auto iter = map.begin(); iter != map.end(); iter++)
{
QVector<JQ_UI_Config> &vec = iter.value();
int count = 0;
for (const auto &it : vec)
{
if (it._Type == "QToolButton")
{
QToolButton *toolBtn = new QToolButton();
toolBtn->setText(it._Text);
QSize btnSize(it._Size.split(',').at(0).toInt(), it._Size.split(',').at(1).toInt());
toolBtn->setFixedSize(btnSize);
toolBtn->setAutoRaise(false);
toolBtn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
QString picture = QString("%1%2.svg").arg(currentExeDir).arg(it._Text);
toolBtn-> setIcon(QIcon(QPixmap(picture)));
int width = toolBtn->width();
int height = toolBtn->height();
toolBtn->setIconSize(QSize(width, height-25));
QString cmd = it._Cmd;
toolBtn->setStyleSheet(style);
connect(toolBtn, &QToolButton::clicked, this, [this, cmd](){
qDebug() << "__SCMD: " << cmd;
emit sendCMD(cmd);
});
gridLayout->addWidget(toolBtn, 0, index_btn++, 1, 1);
count++;
}
else
{
//undefine
}
}
QLabel *label = new QLabel(retWidget);
label->setAlignment(Qt::AlignCenter);
QFont font;
font.setBold(true);
font.setWeight(50);
label->setFont(font);
label->setText(vec[0]._Group.split("_").at(0));
label->setFixedHeight(20);
label->setBackgroundRole(QPalette::ColorRole::HighlightedText);
label->setStyleSheet("QLabel{background-color: rgb(222,236,252);}");
gridLayout->addWidget(label, 1, index_label, 1, count);
QFrame *line = new QFrame(retWidget);
line->setFrameShadow(QFrame::Raised);
line->setFrameShape(QFrame::VLine);
gridLayout->addWidget(line, 0, index_label, 2, 1);
index_label = index_btn;
}
retWidget->setLayout(gridLayout);
}
3. 注册command,一个command过来自动回调处理函数
#ifndef COMMANDHANDLER_H
#define COMMANDHANDLER_H
//类成员函数指针
typedef void (commandHandler::*pFunc)();
class commandHandler
{
public:
commandHandler()
{
m_registerMap.clear();
}
void registerCommand()
{//注册, command和xml中按钮的cmd对应
m_registerMap.insert("OPEN_FILE", &commandHandler::handle_openFile);
m_registerMap.insert("SAVE_FILE", &commandHandler::handle_saveFile);
m_registerMap.insert("SAVEAS_FILE", &commandHandler::handle_saveAsFile);
}
void parseCommand(const QString &cmd)
{
if (m_registerMap.isEmpty())
return;
if (m_registerMap.find(cmd) != m_registerMap.end())
{
auto pFunc = m_registerMap.find(cmd).value();
(this->*pFunc)();
}
}
public:
/* 处理函数 */
//打开
void handle_openFile();
//保存
void handle_saveFile();
//另存
void handle_saveAsFile();
//....
private:
QMap<QString, pFunc> m_registerMap;
};
#endif // COMMANDHANDLER_H
网友评论