起因

前段时间分享了一个MoneyProgress的Mac软件,一直有人在论坛发帖问有没有win版的,恰好最近在看Qt,于是就有了这个项目.

写这个贴子的目的是为了记录一下开发过程,以及遇到的问题.

以后可以拿它做参考,也可以给有需要的人提供一些帮助.

MAC版的项目地址: MoneyProgress
WIN版的项目地址: MoneyProgress_win

程序很大程度参考了原作者的UI设计,这里再次感谢原作者.

开发环境

  • Windows 10 20H2(这个不是很重要)
  • Qt 5.15 with Mingw(这个很重要)

开发过程

这块看我的commit记录就行了,虽然有点乱,但是基本上都是有用的.

这里只记录一些比较重要的问题,其他的问题可以参考Qt官方文档

多看文档,多看文档,多看文档.

问题1: 图片过大

原作者的图片都是png格式,大小足足有3.27MB,分辨率为1024x1024,应该是自己画的吧.

刚开始导入图片设置为label设置样式表background-image: url(:/img/avatar.png);

是这样的:

20230411122233-2023-04-11

可以看到图片很大,很奇怪,

解决办法:

设置为border-image: url(:/img/avatar.png);

20230411122553-2023-04-11

这样它就会自动缩放了.可以通过设置labelwidthheight来控制图片的大小.

问题2: 无法获取到正确的屏幕分辨率

这个问题是论坛上有人提出来的,我也遇到了.

原代码为:

1
2
3
4
5
// 这里省略了一些代码
// 获取屏幕分辨率高度
QApplication::desktop()->width();


实际获取的不一定就是当前屏幕的分辨率,有时候会获取到错误的值.
比如你有多块屏幕,它会获取到所有屏幕的分辨率的和.就很离谱.
这就会导致我们的程序在不同的屏幕上显示的效果不一样.
任务栏的弹窗就奇奇怪怪的.甚至看不到.

20230411123559-2023-04-11

解决办法:

1
2
3
4
// 这里省略了一些代码
QApplication::screenAt(QCursor().pos())->geometry().width()


意为获取鼠标所在屏幕的分辨率宽度.非常ok.

问题3: 文本无法正常更新

问题代码:

因为我想实现每次点击任务栏图标都会弹出一个弹窗,显示当前的挣钱进度,所以我在MoneyProgress类中添加了一个IconMessage类的对象(一个小widget),并且在MoneyProgress类中添加了一个update函数,用来更新弹窗中的文本.
同时update还要负责更新主窗口中的文本.所以就有了如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

void MoneyProgress::update()
{
// 这里省略了一些代码
// 判断两个界面是否可见
if (this->isVisible())
{
ui->labelMoneyNow->setText("您当前已经挣了"+QString::number(moneyday*progress/1000,'f',1)+"元;");
ui->labelDay->setText("您一月工作" + QString::number(days) + "天;");
ui->labelMoneyDay->setText("您一天能挣" + QString::number(moneyday, 'f', 1) + "元;");
ui->labelHourDay->setText("您一天工作" + QString::number(hours, 'f', 1) + "小时;");
ui->labelMoneySecond->setText("您一秒钟能挣" + QString::number(moneysecond, 'f', 6) + "元;");
}
if (iconmessage.isVisible())
{
iconmessage.update(progress, moneyday);
qDebug() << progress;
}
}

可以看到大致思路就是判断两个界面是否可见,如果可见就更新文本.但是任务栏那个小窗口的文本无法更新,调试发现了一个低级错误

1
2
3
4
5

update(); //错误的写法
iconmessage.show();
// update(); 把update()放在这里就可以更新了

确实很低级

问题4: QSettings 无效

这个问题是在保存时间的时候遇到的,我想把设置保存到QSettings里面,但是发现无论怎么设置都无效.
在网上逛了半天,发现是因为QSettings只能在构造函数和析构函数中使用,不能在其他函数中使用.

问题代码:

1
2
3
4
5
6
7
8
9
10
//原本设计的是每次设置改变就保存一次,但是发现无效
void MoneyProgress::on_timeSleepdown_userTimeChanged(const QTime &time)
{
// 这里省略了一些代码 settings 是一个QSettings对象,在.h文件中定义
settings.setValue("sleepDown", sleepDown);

// 保存设置

}

解决办法:

QSettings的保存设置放到析构函数中,这样就可以正常使用了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


MoneyProgress::~MoneyProgress()
{
QSettings settings("MuYin", "MoneyProgress_win");
// 保存设置
settings.setValue("money", money);
settings.setValue("days", days);
settings.setValue("workUp", workUp);
settings.setValue("workDown", workDown);
settings.setValue("sleepUp", sleepUp);
settings.setValue("sleepDown", sleepDown);
// settings.setValue("geometry", this->saveGeometry());
// settings.setValue("windowState", this->saveState());

// 保存设置
settings.sync();

delete ui;
}


问题5: QSS样式表不会用

因为我设置了标题栏隐藏

this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); // 隐藏标题栏

所以一直弄不出来borde的样式,最后发现改centralwidgetborder属性就可以了.

问题代码:

1
2
3
4
5
6
QWidget {
background-color: rgb(255, 255, 255);
border-width: 3px;
border-color: rgba(255, 216, 58, 225);
border-radius: 15px;
}

解决方法

1
2
3
4
5
6
7
8
9
10
QWidget {
background-color: rgb(255, 255, 255);
border-color: rgba(255, 216, 58, 225);
border-radius: 15px;
}
QWidget#centralwidget {
background-color: rgb(255, 255, 255);
border: 3px solid #ffee6f;
/* border-color: rgba(255, 216, 58, 225); */
}

css还是不太了解,回头需要好好学习一下.

问题6: 程序整体缩放问题

引用网友的话:

Qt下高分屏的问题,几乎是一场灾难。希望未来 Qt 能有更好的解决方案。

解决方法: 添加 qt/etc/qt.conf文件,注意这是在qrc文件中的路径,它的完整路径是qrc:/qt/etc/qt.conf,网上说一定不要弄错
文件内容的意思为不使用QT的缩放功能,而是使用系统的缩放功能

1
2
3
[Platforms]
WindowsArguments = dpiawareness=0

具体看这个commit

问题7: QtCreator 无法Debug

将build模式从release改为debug就可以了…………………………….

总结

项目不大,时间也不算长,大概两三个晚上的样子,但是在这个过程中学到了很多东西,比如说QSettings的使用,QSS的使用,QTimer的使用,QApplication::screenAt(QCursor().pos())->geometry().width()的使用,以及一些小技巧,比如说QSettings只能在构造函数和析构函数中使用,QSSborder属性要写在centralwidget上,QTimerstart函数可以传入一个参数,表示延迟多久开始计时,QApplication::screenAt(QCursor().pos())->geometry().width()可以获取鼠标所在屏幕的分辨率宽度等等.

最后希望大家能够多多支持,如果有什么问题,欢迎指正,可以在评论区留言,我会尽快回复的.