DialogBase.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #include "DialogBase.h"
  2. #include <QMouseEvent>
  3. #include <QVBoxLayout>
  4. #include <QLabel>
  5. #include <QPushButton>
  6. #include <QBoxLayout>
  7. #include <QStyle>
  8. #include <qsize.h>
  9. #include <QGuiApplication>
  10. #include <QScreen>
  11. #include "OneShadowEffect.h"
  12. DialogBase::DialogBase(QWidget *parent)
  13. : QDialog(parent)
  14. {
  15. m_logger = spdlog::get("ACASetting");
  16. if(m_logger == nullptr)
  17. {
  18. fmt::print("DialogBase: 未发现ACASetting日志记录器,请检查日志记录器是否已初始化。\n");
  19. return;
  20. }
  21. initUI();
  22. initSettings();
  23. /* 设置qss */
  24. connect(&UIStyle, &UIStyleManager::signal_qssChanged, this, &DialogBase::do_setQSS);
  25. /* 设置默认的UI */
  26. setParentQSS();
  27. }
  28. DialogBase::DialogBase(bool isFullScreen, QWidget *parent)
  29. : QDialog(parent), m_isFullScreen(isFullScreen)
  30. {
  31. m_logger = spdlog::get("ACASetting");
  32. if(m_logger == nullptr)
  33. {
  34. fmt::print("DialogBase: 未发现ACASetting日志记录器,请检查日志记录器是否已初始化。\n");
  35. return;
  36. }
  37. initUI();
  38. initSettings();
  39. /* 设置qss */
  40. connect(&UIStyle, &UIStyleManager::signal_qssChanged, this, &DialogBase::do_setQSS);
  41. /* 设置默认的UI */
  42. setParentQSS();
  43. }
  44. DialogBase::~DialogBase()
  45. {
  46. }
  47. /* 设置标题 */
  48. void DialogBase::setTitle(const QString &title, QSize size)
  49. {
  50. m_labelTitle->setText(title);
  51. m_labelTitle->setFixedSize(size);
  52. }
  53. /* 获取标题 */
  54. QString DialogBase::getTitle() const
  55. {
  56. return m_labelTitle ? m_labelTitle->text() : QString();
  57. }
  58. /* 设置内容容器 */
  59. bool DialogBase::setContentWidget(QWidget *widget)
  60. {
  61. if(widget == nullptr)
  62. {
  63. SPDLOG_LOGGER_ERROR(m_logger, "设置内容容器失败,widget为nullptr");
  64. return false;
  65. }
  66. if(m_widgetContent == widget)
  67. {
  68. return true; // 如果已经是这个widget了,就不需要重新设置
  69. }
  70. if(m_widgetContent != nullptr)
  71. {
  72. m_layoutBackground->removeWidget(m_widgetContent);
  73. delete m_widgetContent;
  74. m_widgetContent = nullptr;
  75. }
  76. m_widgetContent = widget;
  77. m_layoutBackground->insertWidget(1, m_widgetContent);
  78. return true;
  79. }
  80. /* 设置低栏容器 */
  81. bool DialogBase::setBottomWidget(QWidget *widget)
  82. {
  83. if(widget == nullptr)
  84. {
  85. SPDLOG_LOGGER_ERROR(m_logger, "设置底部容器失败,widget为nullptr");
  86. return false;
  87. }
  88. if(m_widgetBottom != nullptr)
  89. {
  90. m_layoutBackground->removeWidget(m_widgetBottom);
  91. delete m_widgetBottom;
  92. m_widgetBottom = nullptr;
  93. }
  94. m_widgetBottom = widget;
  95. m_layoutBackground->insertWidget(2, m_widgetBottom);
  96. return true;
  97. }
  98. /* 移除底栏 */
  99. bool DialogBase::removeBottomWidget()
  100. {
  101. if(m_widgetBottom == nullptr)
  102. {
  103. return true;
  104. }
  105. m_layoutBackground->removeWidget(m_widgetBottom);
  106. delete m_widgetBottom;
  107. m_widgetBottom = nullptr;
  108. return true;
  109. }
  110. /* 点击确定按钮之前执行的操作 */
  111. bool DialogBase::isOKClicked()
  112. {
  113. /* 默认返回true,子类可以重载这个函数来实现自定义的逻辑 */
  114. return true;
  115. }
  116. /* 点击关闭按钮之后执行的操作 */
  117. bool DialogBase::isCloseClicked()
  118. {
  119. /* 默认什么都不做,子类可以重载这个函数来实现自定义的逻辑 */
  120. return true;
  121. }
  122. /* 设置一个控件报警,边框显示红色
  123. * 注意:这个功能需要在qss里设置属性[Warn=true],并实现相应的报警样式 */
  124. void DialogBase::setWarn(QWidget* widget, bool isWarn)
  125. {
  126. if(widget == nullptr)
  127. {
  128. SPDLOG_LOGGER_ERROR(m_logger, "设置控件报警失败,widget为nullptr");
  129. return;
  130. }
  131. widget->setProperty("Warn", isWarn);
  132. widget->style()->unpolish(widget);
  133. widget->style()->polish(widget);
  134. widget->update();
  135. }
  136. /* 初始化UI */
  137. void DialogBase::initUI()
  138. {
  139. /*--------------------- 设置对话框的属性 -----------------------*/
  140. this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
  141. this->setAttribute(Qt::WA_TranslucentBackground, true);
  142. // this->setObjectName("DialogBase");
  143. /*--------------------- 初始化背景容器 -----------------------*/
  144. /* 如果需要背后接近透明的全屏遮罩,就设置为true,在this和m_widgetBackground之间添加
  145. * 一层接近透明的遮罩 */
  146. if(m_isFullScreen)
  147. {
  148. auto screenRect = QGuiApplication::screenAt(QCursor::pos())->geometry();
  149. this->resize(screenRect.width(), screenRect.height());
  150. /* 创建最外层的透明背景 */
  151. m_widgetTransparent = new QWidget(this);
  152. m_widgetTransparent->setObjectName("widget_transparent");
  153. m_widgetTransparent->setStyleSheet(R"(
  154. QWidget#widget_transparent {background: rgba(0, 0, 0, 0.01)};
  155. )");
  156. m_widgetTransparent->resize(screenRect.width(), screenRect.height());
  157. m_widgetTransparent->move(0, 0);
  158. }
  159. /* 创建真正的容器 */
  160. m_widgetBackground = new QWidget(this);
  161. m_widgetBackground->setObjectName("widget_content__");
  162. // m_widgetBackground->resize(400, 300);
  163. /* 判断m_widgetBackground是哪一层 */
  164. if(m_isFullScreen)
  165. {
  166. m_widgetBackground->setParent(m_widgetTransparent);
  167. /* 设置设置区域居中显示 */
  168. m_widgetBackground->move(m_widgetTransparent->width() / 2 - m_widgetBackground->width() / 2,
  169. m_widgetTransparent->height() / 2 - m_widgetBackground->height() / 2);
  170. }else {
  171. QVBoxLayout* layout = new QVBoxLayout(this);
  172. /* 设置边距,就是阴影的宽度 */
  173. layout->setContentsMargins(20, 20, 20, 20);
  174. layout->setSpacing(0);
  175. this->setLayout(layout);
  176. layout->addWidget(m_widgetBackground);
  177. }
  178. /* 创建背景容器内部的布局 */
  179. m_layoutBackground = new QVBoxLayout(m_widgetBackground);
  180. m_layoutBackground->setContentsMargins(0, 0, 0, 0);
  181. m_layoutBackground->setSpacing(0);
  182. m_widgetBackground->setLayout(m_layoutBackground);
  183. /*--------------------- 初始顶栏 -----------------------*/
  184. /* 初始化顶部标题栏,高度56,下面分割线高度1 */
  185. m_widgetTop = new QWidget(this);
  186. m_widgetTop->setObjectName("widget_top");
  187. m_widgetTop->setFixedHeight(56);
  188. m_layoutBackground->addWidget(m_widgetTop);
  189. QHBoxLayout* topHBoxLayout = new QHBoxLayout(m_widgetTop);
  190. m_widgetTop->setLayout(topHBoxLayout);
  191. /* 初始化标题栏 */
  192. m_labelTitle = new QLabel(m_widgetTop);
  193. m_labelTitle->setObjectName("label_title");
  194. m_labelTitle->setText("Dialog Title");
  195. m_labelTitle->setFixedSize(120, 18);
  196. m_labelTitle->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
  197. /* 初始化关闭按钮 */
  198. m_pBtn_Close = new QPushButton(m_widgetTop);
  199. m_pBtn_Close->setObjectName("pBtn_Close");
  200. m_pBtn_Close->resize(32, 32);
  201. /* 安装事件过滤器,主要是处理鼠标悬停事件 */
  202. m_pBtn_Close->installEventFilter(this);
  203. /* 重新布局顶栏 */
  204. layoutTop();
  205. /*--------------------- 初始化内容栏 -----------------------*/
  206. // m_widgetContent = new QWidget(this);
  207. // m_widgetContent->resize(400, 300);
  208. // m_layoutBackground->addWidget(m_widgetContent);
  209. /*--------------------- 初始底栏 -----------------------*/
  210. m_widgetBottom = new QWidget(this);
  211. m_widgetBottom->setObjectName("widget_bottom");
  212. m_widgetBottom->setFixedHeight(88);
  213. m_layoutBackground->addWidget(m_widgetBottom);
  214. QHBoxLayout* bottomHBoxLayout = new QHBoxLayout(m_widgetBottom);
  215. m_widgetBottom->setLayout(bottomHBoxLayout);
  216. /* 初始化取消按钮 */
  217. m_pBtn_Cancel = new QPushButton(m_widgetBottom);
  218. m_pBtn_Cancel->setObjectName("pBtn_Cancel");
  219. m_pBtn_Cancel->setText("取消");
  220. m_pBtn_Cancel->setFixedSize(60, 32);
  221. bottomHBoxLayout->addWidget(m_pBtn_Cancel, 0, Qt::AlignRight | Qt::AlignVCenter);
  222. /* 初始化确认按钮 */
  223. m_pBtn_OK = new QPushButton(m_widgetBottom);
  224. m_pBtn_OK->setObjectName("pBtn_OK");
  225. m_pBtn_OK->setText("确定");
  226. m_pBtn_OK->setFixedSize(60, 32);
  227. bottomHBoxLayout->addWidget(m_pBtn_OK, 0, Qt::AlignRight | Qt::AlignVCenter);
  228. /* 添加一个底部横向弹簧 */
  229. bottomHBoxLayout->insertStretch(0, 1);
  230. /* 设置底部按钮的间距 */
  231. bottomHBoxLayout->setContentsMargins(32, 24, 32, 32);
  232. bottomHBoxLayout->setSpacing(16);
  233. /*--------------------- 创建阴影 -----------------------*/
  234. auto pShadow = new OneShadowEffect(this);
  235. m_widgetBackground->setGraphicsEffect(pShadow);
  236. }
  237. /* 初始化其他设置 */
  238. void DialogBase::initSettings()
  239. {
  240. /* 初始化变量 */
  241. m_lastPos = QPoint(0, 0);
  242. /* 连接信号和槽 */
  243. connect(m_pBtn_Close, &QPushButton::clicked, this, &DialogBase::do_pBtn_Close_Clicked);
  244. connect(m_pBtn_OK, &QPushButton::clicked, this, &DialogBase::do_pBtn_OK_Clicked);
  245. connect(m_pBtn_Cancel, &QPushButton::clicked, this, &DialogBase::do_pBtnCancel_clicked);
  246. /* 设置样式表 */
  247. setParentQSS();
  248. }
  249. /* 加载QSS */
  250. void DialogBase::setParentQSS()
  251. {
  252. /* 获取样式表路径 */
  253. QString qssPath = UIStyle.getQSSPath() + "/dialogbase.qss";
  254. QFile file(qssPath);
  255. if(file.open(QFile::ReadOnly))
  256. {
  257. QString qss = file.readAll();
  258. file.close();
  259. m_widgetBackground->setStyleSheet(qss);
  260. } else
  261. {
  262. SPDLOG_LOGGER_ERROR(m_logger, "打开QSS文件失败: {}", qssPath.toStdString());
  263. SPDLOG_LOGGER_ERROR(m_logger, "错误信息: {}", file.errorString().toStdString());
  264. }
  265. }
  266. /* 设置top栏的位置布局,标题和关闭按钮的高度起始位置不一样,不方便使用布局,所有手动修改坐标
  267. * 标题位置32,18,高度18
  268. * 关闭按钮右对齐16,y12,大小32x32 */
  269. void DialogBase::layoutTop()
  270. {
  271. m_labelTitle->move(32, 18);
  272. int x = m_widgetTop->width() - m_pBtn_Close->width() - 16;
  273. m_pBtn_Close->move(x, 12);
  274. }
  275. /* 关闭按钮点击事件 */
  276. void DialogBase::do_pBtn_Close_Clicked()
  277. {
  278. if(!isCloseClicked())
  279. {
  280. /* 如果子类没有重载这个函数,默认返回true */
  281. return;
  282. }
  283. this->close();
  284. }
  285. /* 确认按钮点击事件 */
  286. void DialogBase::do_pBtn_OK_Clicked()
  287. {
  288. if(!isOKClicked())
  289. {
  290. /* 如果子类没有重载这个函数,默认返回true */
  291. return;
  292. }
  293. m_isOK = true;
  294. this->accept();
  295. }
  296. /* 设置QSS */
  297. void DialogBase::do_setQSS(EUIStyle style)
  298. {
  299. setParentQSS();
  300. }
  301. /* 重写鼠标按下事件 */
  302. void DialogBase::mousePressEvent(QMouseEvent *event)
  303. {
  304. m_lastPos = event->globalPos();
  305. event->accept();
  306. }
  307. /* 重写鼠标移动事件 */
  308. void DialogBase::mouseMoveEvent(QMouseEvent *event)
  309. {
  310. auto point = m_widgetTop->mapToGlobal(QPoint(0, 0));
  311. QRect rect(point, m_widgetTop->size());
  312. if(!rect.contains(m_lastPos))
  313. {
  314. event->accept();
  315. return;
  316. }
  317. int dx = event->globalX() - m_lastPos.x();
  318. int dy = event->globalY() - m_lastPos.y();
  319. if(m_isFullScreen)
  320. {
  321. m_widgetBackground->move(m_widgetBackground->x() + dx, m_widgetBackground->y() + dy);
  322. }else {
  323. move(x() + dx, y() + dy);
  324. }
  325. m_lastPos = event->globalPos();
  326. event->accept();
  327. }
  328. /* 重写鼠标释放事件 */
  329. void DialogBase::mouseReleaseEvent(QMouseEvent *event)
  330. {
  331. event->accept();
  332. }
  333. /* 显示事件 */
  334. void DialogBase::showEvent(QShowEvent *event)
  335. {
  336. QDialog::showEvent(event);
  337. if(m_isFullScreen)
  338. {
  339. /* 设置设置区域居中显示 */
  340. m_widgetBackground->move(m_widgetTransparent->width() / 2 - m_widgetBackground->width() / 2,
  341. m_widgetTransparent->height() / 2 - m_widgetBackground->height() / 2);
  342. }
  343. /* 重新布局顶栏 */
  344. layoutTop();
  345. }
  346. /* 重新设置大小 */
  347. void DialogBase::resizeEvent(QResizeEvent *event)
  348. {
  349. QDialog::resizeEvent(event);
  350. if(m_isFullScreen)
  351. {
  352. /* 设置设置区域居中显示 */
  353. m_widgetBackground->move(m_widgetTransparent->width() / 2 - m_widgetBackground->width() / 2,
  354. m_widgetTransparent->height() / 2 - m_widgetBackground->height() / 2);
  355. }
  356. /* 重新布局顶栏 */
  357. layoutTop();
  358. }
  359. /* 事件过滤器 */
  360. bool DialogBase::eventFilter(QObject *watched, QEvent *event)
  361. {
  362. if(watched == m_pBtn_Close && event->type() == QEvent::HoverEnter)
  363. {
  364. m_pBtn_Close->setProperty("Hover", true);
  365. m_pBtn_Close->style()->unpolish(m_pBtn_Close);
  366. m_pBtn_Close->style()->polish(m_pBtn_Close);
  367. m_pBtn_Close->update();
  368. return true;
  369. }
  370. else if(watched == m_pBtn_Close && event->type() == QEvent::HoverLeave)
  371. {
  372. m_pBtn_Close->setProperty("Hover", false);
  373. m_pBtn_Close->style()->unpolish(m_pBtn_Close);
  374. m_pBtn_Close->style()->polish(m_pBtn_Close);
  375. m_pBtn_Close->update();
  376. return true;
  377. }
  378. return QDialog::eventFilter(watched, event);
  379. }