效果
设置页面控制截图区域的主题,如图所示,通过Tab页的设置可以改变截图区域边界的颜色,宽度和线条样式
20220723-001611
原理
页面修改相关参数,比如宽度或者颜色,本质是利用QJson往json文件里写,在绘制截图区域时,又可以从json文件中读,这就是实现设置页面控制截图区域的原理。
相关实现
原理实现
先说明QJson和Json的不同,QJson属于QT自带的一个模块,Json属于开源库;QJson相比于Json,Json很多方法都已经写好了,最重要的一个方法就是
auto root = json::parse("{}");
通过它可以解析json文件,并实现set和get(通过[][][]级联的方式实现对子节点的读写,无论其有多深),例如
Json::Reader reader;
Json::Value root;
ifstream file("demo.json", ios::binary);
reader.parse(file, root);
// 读取
string friend_name = root["friends"]["friend_name"].asString();
// 写入
root["friends"]["friend_name"] = Json::Value("man");
但是QJson并没有类似于parse的方法,这个是最核心的,因此单纯使用QJson自带的的函数,是无法做到读写深层次的子节点数据。
这是我本地环境的json文件
{
"signalflag": {
"ar": {
"anchor": {
"color": "#ff55ff7f"
},
"border": {
"color": "#ffaa0000",
"linetype": "4",
"width": "3"
}
},
"clipboard": "F2",
"screenshot": "F1",
"trayiconcolor": "2"
}
}
可见,如果想要读写border节点下的相关数据,就必须实现类似于Json下parse的功能。
方法:递归
// 写 使用递归获取sPath对应的节点信息
void JsonPrivate::SetValue(QJsonObject& parent, const QString& sPath, const QJsonValue& newValue)
{
const int indexOfDot = sPath.indexOf('.'); // 解析“.”
const QString sProperty = sPath.left(indexOfDot); // 获取节点对应的属性
const QString sRestPath = (indexOfDot > 0) ? path.mid(indexOfDot + 1) : QString();
QJsonValue fieldValue = parent[sProperty];
if (sRestPath.isEmpty())
{
return; // 不存在直接返回
}
else
{
// 路径中间的属性,递归访问它的子属性
QJsonObject child = parent[sProperty].toObject();
setValue(child, sRestPath , newValue);
parent[sProperty] = child;
}
}
// 读 不用使用递归 常规方法即可
QJsonValue JsonPrivate::GetValue(const QString& sPath, const QJsonObject& fromNode) const
{
QJsonObject parent = fromNode.isEmpty() ? root : fromNode;
QStringList names = sPath.split(QRegularExpression("\\.")); // 正则表达式解析
int iSize = names.size();
for (int i = 0; i < iSize - 1; ++i)
{
if (parent.isEmpty())
{
return QJsonValue();
}
parent = parent.value(names.at(i)).toObject(); // 重点 QJsonObject可以直接赋值
}
// [4] 返回 parent 中属性名为倒数第一个属性名字对应的属性值
return parent.value(names.last());
}
通过以上方法可以实现在QJson中对任意深度节点的json文件实现读写
界面实现
主要利用模块QTabWidget实现Tab页的切换,目前有四个Tab页
以第一个页面为例,代码简述,其余均类似
void Settings::SetupGeneralDisplay()
{
auto index = m_Tabwidget->addTab(new QWidget(), tr("General"));
auto layout = new QVBoxLayout();
layout->setSpacing(15);
// 语言
auto tempLanguageLy = new QHBoxLayout();
auto tempLanguage = new QLabel(tr("Language: "));
auto ctrlLanguage = new QComboBox();
ctrlLanguage->setView(new QListView());
ctrlLanguage->view()->window()->setWindowFlag(Qt::NoDropShadowWindowHint);
ctrlLanguage->addItem("English");
QString sTemp = "Chinese";
ctrlLanguage->addItem(sTemp);
tempLanguageLy->addWidget(tempLanguage);
tempLanguageLy->addWidget(ctrlLanguage);
tempLanguageLy->addStretch();
// 锚点颜色
auto ctrlAnchorColorLy = new QHBoxLayout();
auto tempAnchorColor = new QLabel(tr("AnchorColor: "));
auto ctrlAnchorColor = new ColorDialogButton(config.GetJsonValue("signalflag.ar.anchor.color"));
connect(ctrlAnchorColor, &ColorDialogButton::eChange, [this](auto&& color)
{
QString temp = ConvertColor2Str(color);
config.SetJsonValue("signalflag.ar.anchor.color", temp);
});
ctrlAnchorColor->setFixedSize(23, 23);
ctrlAnchorColorLy->addWidget(tempAnchorColor);
ctrlAnchorColorLy->addWidget(ctrlAnchorColor);
ctrlAnchorColorLy->addStretch();
// 托盘图标颜色
auto trayIconColorLy = new QHBoxLayout();
auto tempTrayIconColor = new QLabel(tr("TrayIconColor: "));
auto chooseTrayIconColorBlock = new QButtonGroup();
chooseTrayIconColorBlock->setExclusive(true);
auto TrayIconColorAuto = new QRadioButton();
TrayIconColorAuto->setText("Auto");
TrayIconColorAuto->setChecked(1); // 默认选中薯条
auto TrayIconColorRGB = new QRadioButton();
TrayIconColorRGB->setText("RGB");
//TrayIconColorRGB->setIcon();
//TrayIconColorRGB->setIconSize();
chooseTrayIconColorBlock->addButton(TrayIconColorAuto, 1);
chooseTrayIconColorBlock->addButton(TrayIconColorRGB, 2);
trayIconColorLy->addWidget(tempTrayIconColor);
trayIconColorLy->addWidget(TrayIconColorAuto);
trayIconColorLy->addWidget(TrayIconColorRGB);
trayIconColorLy->addStretch();
connect(chooseTrayIconColorBlock, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, [this](int id)
{
config.SetJsonValue("signalflag.trayiconcolor", QString::number(id));
});
// 子Layout添加到总Layout
layout->addLayout(tempLanguageLy);
layout->addLayout(ctrlAnchorColorLy);
layout->addLayout(trayIconColorLy);
layout->addStretch();
m_Tabwidget->widget(index)->setLayout(layout);
}
功能实现
原理肯定是QT的信号槽,信号槽如何使用请自行百度,这里不做讲解。
功能实现以截图区域的边界颜色为例
// 写入
auto ctrlARBorderColorLy = new QHBoxLayout();
auto tempARBorderColor = new QLabel(tr("ARBorderColor: "));
// 获取颜色
auto ctrlARBorderColor = new ColorDialogButton(config.GetJsonValue("signalflag.ar.border.color"));
// 颜色改变时触发
connect(ctrlARBorderColor, &ColorDialogButton::eChange, [this](auto&& color)
{
QString temp = ConvertColor2Str(color); // RGBA转换为16进制 便于json中存储
config.SetJsonValue("signalflag.ar.border.color", temp); // 写入json文件中
});
// 读取
// 边界颜色 线宽 线条
// 锚点大小和颜色
void ActiveRegion::rUpdateTheme()
{
auto& config = Config::instance(GetJsonPath(eJsonPath::ChangedPath)); // 单例模式
auto sSelectorBorderColor = config.GetJsonValue("signalflag.ar.border.color"); // 从json文件中获取对应的属性
rSetBorderColor(ConvertStr2Color(sSelectorBorderColor));
//auto iWidth = config.GetJsonValue("signalflag.ar.border.width").toInt();
//rSetBorderWidth(iWidth);
//auto iLineType = config.GetJsonValue("signalflag.ar.border.linetype").toInt();
//rSetBorderStyle(Qt::PenStyle(iLineType));
//auto sSelectorAnchorColor = config.GetJsonValue("signalflag.ar.anchor.color");
//rSetAnchorBorderColor(ConvertStr2Color(sSelectorAnchorColor));
//m_ActiveRegionBox.SetARAnchorWidth(iWidth);
}
总结
以上就是”QT截图系列1-配置文件改变区域主题“的核心内容,代码很多,不便展开。后续会陆续更新QT截图的博客,欢迎大家广泛提意见,我也可以做相关的修改。