QT定时器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT定时器相关的知识,希望对你有一定的参考价值。

#include "digiclock.h"
#include<qtimer.h>
#include<QTime>
#include<QMouseEvent>
#include<qpalette.h>
Digiclock::Digiclock(QWidget* parent):QLCDNumber(parent)

QPalette p=palette();
p.setColor(QPalette::Window,Qt::blue);
setPalette(p);
setWindowFlags(Qt::FramelessWindowHint);
//setWindowOpacity(0.5);
QTimer* timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(showTime()));
timer->start(1000);
showTime();
resize(150,60);
showcolon=true;

void Digiclock::showTime()

QTime time=QTime::currentTime();
QString string=time.toString("hh:mm:ss");
if(showcolon)

string[2]=':';
showcolon=false;

else

string[2]=' ';
showcolon=true;

setDigitCount(8);
display(string);

void Digiclock::mousepressevent(QMouseEvent* event)

if(event->button()==Qt::LeftButton)

drawposition=event->globalPos()-frameGeometry().topLeft();
event->accept();

if(event->button()==Qt::RightButton)

close();


void Digiclock::mousemoveevent(QMouseEvent * event)

if(event->buttons()&Qt::LeftButton)

move(event->globalPos()-drawposition);
event->accept();


提示这个QObject::connect: No such slot QLCDNumber::showTime() in ..\clock\digiclock.cpp:14,但是我是用的子类的showtime函数啊,没有用基类啊,这是什么原因呢,大神指教了

参考技术A 看一下你的DigiClock类的头文件中有没有Q_OBJECT宏,没有的话你这个类就不支持信号槽机制,即使你定义槽了也没用。

二Qt定时器与文本编辑器制作《QT 入门到实战》

学习目标

  • 了解 qt 的 pixmap
  • 了解 qt 的 label 如何显示图片
  • 了解定时器的开启
  • 了解定时器的关闭
  • 了解文件如何进行读取
  • 了解 QFileDialog 的使用
  • 了解了一个文本编辑器的基本编写
  • 巩固了 connect 的使用

一、制作一个图片浏览器

1.1 Pixmap

在 Qt 中使用 Label 可以显示文本,但 Label 不止可以显示文本,还可以用于图片的显示。

首先我们双击 ui 文件,随后在弹出的设计窗口中创建一个 Label :

接着拖动这个 label 的宽高,拖动至一个比较好展示图片的大小:

接着我们需要创建一个 QPixmap 对象。

QPixmap 类是一个用于处理图像的类,创建一个 QPixmap 传入对应的路径即可得到这个这个类对于这个图片处理的对象,QPixmap 更适合处理小图片。

如下就是一个创建 QPixmap 类对象的方法:

QPixmap pix("D:\\\\developer\\\\QT\\\\pro\\\\01\\\\04\\\\04\\\\img\\\\1.png");

在此传入了一张图片进行对象初始化,接下来就可以直接将这个图片显示在 label 之上。

使用 ui 指定需要显示图片的控件 label,在 label 中有一个 setPixmap 方法,通过 setPixmap 传入 QPixmap 的对象 pix 即可对图片进行设置:

代码如下:

ui->label->setPixmap(pix);

此时代码如下:

以上的报错都是 bug,其实代码是正确的,我们此时只需要点击运行,那么即会弹出一个窗口,上面使用了 label 显示一张图片:

1.2 定时器

现在已经知道了如何使用 label 显示图片,那么接下来我们制作一个图片的自动切换功能,那么必然是需要定时去执行图片切换,又或者说我们需要一个功能可以去触发图片的切换,并且多张图片的话,切换是重复执行的,那么就需要一个定时重复执行某个操作的功能。

好消息是在 Qt 中自带了定时器,定时器是一个用于对任务执行定时操作的功能,定时器本身存在于 QWidget 基类之中,由于我们在创建对应的项目后,其类是 QWidget 的子类,那么我们在这个类中就可以直接使用定时器。

那么此时我们需要两个按钮,一个用于定时器的开启,另一个按钮用于定时器的关闭,在此创建两个 pushButton 在 Qt 界面之上,并且更改对应的文本:

接着我们点击开始按钮触发定时器,那么必然是有一个信号(点击),与一个槽函数,在此右键开始按钮选择转到槽,选择 click 事件:


转到槽函数后,我们可以使用以下的代码开启定时器:

this->startTimer();

以上代码中的 startTimer就是表示开启一个定时器,startTimer 在此还需要传入一个间隔参数用来设定间隔的时间,这个时间是以毫秒为单位的,若你设置1s 那么则需要写成 1000:

this->startTimer(1000);

那接下来如何完成图片的切换呢?这时我们需要重写一个方法 timerEvent,timerEvent 方法时定时器响应后所执行的函数,其本身存在但需要重写。

此时我们回到 .h 头文件中声明:

virtual void timerEvent(QTimerEvent *event);

接着回到 .cpp 文件中对此方法进行重写:

void MainWindow::timerEvent(QTimerEvent *event)
    

在 .cpp 文件中添加以上函数后,我们需要在这个函数中编写切换图片的代码。

此时假如我们有一个文件夹是用于存储需要切换的图片地址,那么我们创建一个 QString 对象进行存储:

QString path("D:\\\\developer\\\\QT\\\\pro\\\\01\\\\04\\\\04\\\\img\\\\");

此时我对应的目录下,文件名是如下格式:


那么在此我可以创建一个变量,这个变量是一个整形变量,用于代表文件名,但是由于每次都需要在之前的名称基础上往上加1,那么我就不能这个定时器触发函数内进行创建,需要在外部创建这个变量,首先到头文件中进行声明:

int picId;

接着再到 cpp 文件中赋初值:

picId=1;

那么此时对于一个图片路径的编写就可以由最开始的 path 文件夹路径加上文件名已经文件名后缀即可,那么就可以写成:

path+=QString::number(picId);
path+=".png";

由于 picId 是 number 类型,并不能直接的对字符串进行拼接,在这里使用 QString::number() 方法对其进行类型转化。

现在图片路径有了,那么接下来必然是现实对应的图片,现实图片我们跟之前的方式一样,创建一个 QPixmap 并且指定对应的 ui 对象 label 对其进行显示即可,代码如下:

QPixmap pix(path);
ui->label->setPixmap(pix);

接下来图片的名称进行增加:

picId++;

这样就可以继续下一张图片了,但在此需要注意,咱们的图片只有3张,那么我们需要使图片索引在超过上限时从头开始,那么就需要进行判断:

picId++;
if(4==picId)
   picId=1;

此时该函数的所有代码如下:

void MainWindow::timerEvent(QTimerEvent *event)
    QString path("D:\\\\developer\\\\QT\\\\pro\\\\01\\\\04\\\\04\\\\img\\\\");
    path+=QString::number(picId);
    path+=".png";
    QPixmap pix(path);
    ui->label->setPixmap(pix);
    picId++;
    if(4==picId)
        picId=1;
    

此时运行项目点击开始后,图片会发生改变:

1.3 结束定时

接下来我们还需要使这个定时器结束定时,我们需要使用 killTimer 方法,这个方法本身继承自 QWidget 父类,所以直接使用 this 调用即可,那么代码如下:

this->killTimer();

但此时使用 killTimer 会出现错误,killTimer 需要一个某个定时器的 id 作为参数,指定你 kill 掉这个定时器。那定时器 id 如何拿到呢?其实在 startTimer 时将会返回一个定时器 id ,将这个 id 存储起来即可,由于是不同函数内都需要使用这个 id,那么此时我们需要在头文件中创建一个变量对这个 id 进行存储:


接着使用这个变量存储定时器的 id:

接着给结束按钮一个槽函数:


在这个函数中使用 killTimer 方法传入定时器 id 即可:

void MainWindow::on_pushButton_2_clicked()

    this->killTimer(timerId);

二、文本编辑器制作

在本章第二点的学习中,我们通过学习文本编辑器制作,从而了解 一般的文件、QFileDialog 以及 巩固自定义事件与槽的知识。

2.1 UI 设计

在正式敲代码之前,我们创建一个项目,设计一下整体的文本编辑器页面。创建好项目后,我们拖动一个 text 的控件拖动到界面之中:


在一般的文本编辑器中,一般以文本编辑为主要功能,接下来我们需要使整个文本编辑器占据整个 UI 的空间区域,那如何进行操作呢?若我们直接设置大小使文本编辑控件以及对应的窗口大小相等,那么这个程序的整个窗口都不能够进行拖放,当在某些设备上整体窗口会导致一些困扰;例如程序界面过大、过小等情况,由于不可拖动大小对用户并不友好。此时我们可以点击整个整个窗口,给整个窗口一个垂直布局,给与垂直布局后,这个窗体内的所有空间将会遵从于这个布局,会使整个空间占据整个宽度,那么在运行之后拖动窗体改变窗体大小,由于窗体内的控件遵循垂直布局的规则,那么窗体内的控件将会遵循父窗体的大小而发生改变,这样就很好的解决了窗口过大、过小而不能更改的问题了。

此时点击整个窗体程序:


选中整个窗体后,这个窗体将会在周围又蓝色小点代表选中,接下来我们点击对应的垂直布局:


点击完毕后整个空间将会占满窗体(这是因为只有一个控件的原因):


接着我们给与对应的菜单添加按钮功能。双击菜单(menubar)可更改名称:


输入如下截图的内容:


按下 enter 键后对应的 &(取地址符)将会消失:

这是因为此时在此处输入对应的取地址符加上某一个“按键”,那么则表示对应的快捷键,例如你在程序之中按下 F 那么将会与点击这个 menu 有相同的操作。

接着我们加入打开文件的 menu :


再接着添加对应的另存为 menu :

还有一个新建文件 menu 忘记添加了,在此添加上:

再接着我们更改一下对应的菜单名称,在 ui 设计窗口右上角更改对应的打开和另存为 menu 名称:

2.2 新建文件

接下来咱们开始编写新建文件操作的功能。

一般新建文件指的是在在窗体之内新建一个文件文档,此时对于文本编辑框的内容是需要清空的,并且文件名也要做一个提示,此时我们给与这个 new_Action 一个自定义的事件与槽。

因为此时你右键这些 menu 并不能直接转到对应的事件槽,所以此时我们需要对应的 connect 函数进行自定义。

此时我们回到 .h 头文件中,对我们自定义的槽函数进行声明:

private slots:
    void newActionSlot();

由于此时我们没有给某一个控件一个槽函数,所以此时我们需要自己编写 private 对槽函数的权限进行修饰,并且声明对应的函数。

接着定义完毕后我们需要在 cpp 文件中对其进行实现:

void MainWindow::newActionSlot()

实现后我们使用 connect 对 new_Action 新建文件操作 ui 绑定对应的槽函数:

connect(ui->new_Action,&QAction::triggered,this,&MainWindow::newActionSlot);

此时 connect 中 &QAction::triggered 是指 action 的点击事件,并且绑定了一个 newActionSlot 槽函数,有关 QAction 我们可以在 ui 设计框右上角可以看到 new_Action 是属于一个 Action 对象:

接着,当点击了新建文件的 action 后,我们需要对应的清空文本编辑框的内容,并且更改当前的 Windows 程序的窗体 title,使其有一个提示,那么槽函数的代码可以写成如下:

void MainWindow::newActionSlot()
    ui->textEdit->clear();
    this->setWindowTitle("新建文本.txt");

以上代码中 setWindowTitle 表示设置当前的窗体程序的标题。我们此时运行程序,在文本编辑框中输入一些内容,随后点击文件选择新建文件,之后将会看见窗体程序的标题发生了改变,并且文本编辑框的内容已被清空:

2.3 打开文件

打开文件的前置操作跟新建文件的操作一样,需要在头文件中声明槽函数、在 cpp 文件中实现槽函数 以及使用 connect 方法连接 menu 以及槽函数。

首先在 .h 文件中声明:


接着就是在 cpp 文件中实现以及使用 connect 自定义事件与槽:


那么接下来我们如何打开文件呢?此时我们需要使用 QFileDialog 类的一个方法打开一个资源选择框,这个方法是 getOpenFileName;首先我们需要在头文件中使用 include 对其引入:

#include <QFileDialog>

随后在 openActionSlot 槽函数中使用 QFileDialog 调用 getOpenFileName,其中 getOpenFileName 一般接收 4 个参数,第一个是资源选择框的父对象是谁,我们可以指定为 this 表示当前程序;第二个参数是一个提示语;第三个参数为资源选择框打开后的默认路径;第四个参数是打开后显示哪些文件。

那么此时代码写成:

QFileDialog::getOpenFileName(this,"选择一个文本",QCoreApplication::applicationFilePath(),"*.txt");

以上代码中的 QCoreApplication::applicationFilePath() 则是表示取到当前的文件路径,最后一个参数则是表示打开后指定显示 txt 类型文件,此时运行程序后,点击打开将会出现资源选择框:


当我们选择某一个文件后,将会弹出对应的文件绝对路径,我们可以使用一个 QString 进行存储,方便接下来读取到所选文件的内容:

QString filename = QFileDialog::getOpenFileName(this,"选择一个文本",QCoreApplication::applicationFilePath(),"*.txt");

若选择文件时并未选中某个文件(取消选择操作、关闭对话框等),其返回值为空,那么在正式读取文件操作之前,我们需要对应的判断当前是否选中文件,此时直接使用 if 判断 filename 的内容是否为 Empty 即可:

if(!filename.isEmpty())
    

此时表示当 filename 不为空时发生操作。接着在 if 判断内,创建一个 file 对象用于接下来对文件的读取,并且在创建时就需要传入 filename:

 QFile file(filename);

接着使用 open 方法对已“装载”路径的 file 对象进行 open,但是由于 open 对象时需要指定你是用什么模式进行读取,可以进行只读、只写等操作,在这里只需要只读,所以使用 QIODevice 方法传入 ReadOnly 作为参数即可:

file.open(QIODevice::ReadOnly);

接着使用 file 对象的 readAll 方法可以一次性读取其文本的内容,并且使用 QByteArray 进行存储;但是要注意,在大文件下不建议这样操作,当前只是作为示例:

QByteArray buf   = file.readAll();

最后直接将这个 buf 转为 string 后设置为 textEdit 的文本内容并且关闭 file 读取即可,此时这个槽函数的所有代码如下:

void MainWindow::openActionSlot()
    QString filename = QFileDialog::getOpenFileName(this,"选择一个文本",QCoreApplication::applicationFilePath(),"*.txt");
    if(!filename.isEmpty())
        QFile file(filename);
        file.open(QIODevice::ReadOnly);
        QByteArray buf   = file.readAll();
        ui->textEdit->setText(QString(buf));
        file.close();
    

接着我们运行一下程序,选择一个文本文件后进行打开,内容将会显示在当前的 textedit 之上:

2.3 另存为

另存为功能的前置操作跟之前两个功能一致,分别是头文件声明、cpp文件下实现以及connect 链接,在此简述一下步骤。

声明:

void saveActionSlot();

实现:

void MainWindow::saveActionSlot()


链接:

connect(ui->save_Action,&QAction::triggered,this,&MainWindow::saveActionSlot);

前置操作完毕后,我们着重了解如何实现保存功能。

保存功能跟打开文本文件操作类似,都是使用 QFileDialog 进行位置选择,并且最终的保存也是使用 file 对象进行操作,毕竟一个是读一个是写都属于 IO 操作。

既然类型,那么我们在进行保存时的流程都是要打开资源选择框,选择某一个位置进行内容保存,那么铁定是使用 Dialog,在之前是使用 getOpenFileName,是 open操作,那么此时就是 save ,那么就使用 getSaveFileName 方法:

QString filename = QFileDialog::getSaveFileName(this,"选择一个文件",QCoreApplication::applicationFilePath(),"*.txt");

接着同样是判断是否为空:

if(!filename.isEmpty())


接着是使用 file 文件对所选择的位置和保存文件名进行操作,并且此时不是 read 而是 write :

QFile file(filename);
file.open(QIODevice::WriteOnly);

接着使用一个 QString 获取当前的textEdit 的文本:

QString text = ui->textEdit->toPlainText();

创建一个 QByteArray 对象,并且将 textEdit 的文本转为 QByteArray:

QByteArray ba=text.toUtf8();

随后写入文件,并且关闭文件即可,完整代码如下:

void MainWindow::saveActionSlot()
    QString filename = QFileDialog::getSaveFileName(this,"选择一个文件",QCoreApplication::applicationFilePath(),"*.txt");
    if(!filename.isEmpty())
        QFile file(filename);
        file.open(QIODevice::WriteOnly);
        QString text = ui->textEdit->toPlainText();
        QByteArray ba=text.toUtf8();
        file.write(ba);
        file.close();
    

此时我们点击保存后将会出现一个资源选择框,我们选择桌面路径,随后点击保存即可对文件进行另存为操作:

查看桌面,文件保存成功并且内容已写入:

总结

本章节主要介绍了如何使用 qt 创建一个图片浏览器以及一个文本编辑器,并且在其中使用 qt QFileDialog 对文件进行选择已经保存,巩固了 qt 项目创建的基本流程;在此基础上巩固了信号与槽,在制作的过程中使用了垂直布局直接并有效的布局了整个 ui 界面。在此基础上还学习了什么是 menu 以及什么是 menu 的 action,并且在 action 上通过使用取地址符的方式创建了对应的快捷按钮,使其文本编辑器的操作更加的方便,这一节还学习了对应的定时器,了解了通过定时器可以对应的创建定时任务,例如制作一个壁纸切换的桌面、定时执行一些重复操作等。

以上是关于QT定时器的主要内容,如果未能解决你的问题,请参考以下文章

Qt 精确定时器

Qt 精确定时器

Qt分析:Qt中的两种定时器(可是QObject为什么要提高定时器呢,没必要啊。。。)

Qt学习 之 定时器

QT 定时器的删除问题

Qt中两种定时器用法