3464|10

291

帖子

5

TA的资源

纯净的硅(中级)

楼主
 

嵌入式Qt-做一个秒表 [复制链接]

本帖最后由 DDZZ669 于 2022-8-7 15:55 编辑

 

之前的文章:嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序

 

介绍了如何编写第一个嵌入式Qt程序,实现了一个电子时钟的演示。

本篇,继续进行Qt实践,仿照手机中的秒表,实现一个相同功能的秒表:

 

回顾上一次的Qt开发流程,整个Qt的开发都是通过敲代码实现的,实际上,还可以利用Qt Creater的UI界面功能,通过图像化的配置来开发图形界面,本篇就使用这种方法来进行开发。

1 新建Qt工程

Qt工程创建的具体步骤可参照之前的文章:嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序,这里只说明不同之处。

上篇是通过代码实现页面设计的,本篇要借助Qt Creater的UI界面设计功能,因此要把下面的创建页面勾选上:

创建完成之后的Qt默认工程结构如下:

双击widget.ui,即可打开UI设置页面,如下图:

这里先简单熟悉下各个功能区:

2 代码编写

2.1 ui界面设计

修改界面的尺寸,我的Linux板子屏幕的分辨率是800x480,因此调整到对应的尺寸:

从左侧拖入一个Label,然后可以修改字体的大小:

再从左侧拖入其它需要用到的组件(PushButtonTextBrower)和位置调节组件(弹簧形状的HorizontalSpacerVericalSpacer

进行水平布局和竖直布局,选中对应的组件,例如3个按钮和中间的2个弹簧,点击上方工具栏中的水平布局按钮:

3个按键的水平布局效果如下:

然后再依次对其它组件进行布局:

字体可以调整到居中显示:

鼠标选中最大的组合组件,拖拽边缘调整到合适的外尺寸。然后选中不同级别的组合组件,调整layoutStretch的参数,实现按比例显示各个组件(相当于调节各个弹簧组件的弹力大小)

点击左下角上面那个三角图标,运行,查看效果:

注意左边留的空白是给秒表的表盘留的。

 

2.2 QTimer与QTime介绍

QTimer 类为定时器提供了一个高级编程接口,提供重复和单次计时。

QTime 类提供时钟时间功能,QTime 对象包含一个时钟时间,它可以表示为自午夜以来的小时数、分钟数、秒数和毫秒数。

Qt Creater提供了方便的帮助文档,可以在Qt Creater中直接查看对应功能函数的使用,比如搜索QTimer,就可以看到对应的介绍,以及可用的API函数:

本篇需要用到QTimer的功能有:

  • start:启动定时器

  • stop:停止定时器

再看看QTime的介绍:

本篇需要用到QTime的功能有:

  • setHMS:设置初始时间

  • addMSecs:增加一个时间(毫秒单位)

  • toString:时间转为字符串格式

  • minute:获取分钟

  • second:获取秒

  • msec:获取毫秒

2.3 对应按钮的函数

为了编写出更易看懂的代码,在编写代码之前,需要修改对应的组件的默认名称为便于理解的名称,比如我将3个按键的名称分别改为了:

  • Btn_Start:开始按钮,并同时具有暂停/继续功能

  • Btn_Reset:复位按钮

  • Btn_Hit:打点按钮,用于记录不同名次的时间

然后还要手动添加QTimer和QTime对象,用于实现秒表的计时功能:

2.3.1 开始按钮的处理

Qt编程中重要处理就是信号和槽机制,它可用通过手动通过connet函数实现,而对于使用Qt Creater的图形界面设计方式,通常也是继续通过界面实现信号和和槽的连接:在开始按钮上右键,选则“转到槽...”:

然后有多种按钮信号可以选择,因为开始按钮同时具有暂停/继续的功能,这里使用toggled功能,利用按钮的按下和松开状态,来实现暂停/继续的功能:

点击OK之后,会自动跳到到代码页面,并自动生成对应的槽函数框架,然后就可以在里面编译对应的业务逻辑代码了:

开始按钮的具体业务逻辑代码如下,当首次按下时,checked为true,此时启动timer,记录此时的时间戳,然后将按钮的文字显示为“暂停”,同时将复位和打点按钮置灰,使这两个按钮不能再按下,因为暂停的时候执行复位和打点无意义。

timer每隔一段时间会触发超时,这里ADD_TIME_MSEC设置的是30ms,超时时间到后,编写对应的超时处理函数timeout_slot以及声明对应的信号和槽的处理。

void Widget::on_Btn_Start_toggled(bool checked)
{
    if (checked)
    {
        timer.start(ADD_TIME_MSEC);
        lastTime = QTime::currentTime();//记录时间戳
        ui->Btn_Start->setText("暂停");
        ui->Btn_Reset->setEnabled(false);
        ui->Btn_Hit->setEnabled(true);
    }
    else
    {
        timer.stop();
        ui->Btn_Start->setText("继续");
        ui->Btn_Reset->setEnabled(true);
        ui->Btn_Hit->setEnabled(false);
    }
}
​
connect(&timer, SIGNAL(timeout()), this, SLOT(timeout_slot()));
void Widget::timeout_slot()
{
    //qDebug("hello");
    QTime nowTime = QTime::currentTime();
    time = time.addMSecs(lastTime.msecsTo(nowTime));
    lastTime = nowTime;
    ui->Txt_ShowTime->setText(time.toString("mm:ss.zzz"));
}

超时时间到了之后,计算一些两次的时间差值,然后通过addMSecs函数来累加时间。

2.3.2 复位按钮的处理

复位按钮也是通过右键来调整到槽,注意这里使用clicked函数即可,因为复位按钮只需要使用它的点击按下功能:

对应的槽函数的具体实现如下:

void Widget::on_Btn_Reset_clicked()
{
    m_iHitCnt = 0;
    timer.stop();
    time.setHMS(0,0,0,0);
    ui->Txt_ShowTime->setText("00:00:00");
    ui->Txt_ShowItem->clear();
​
    ui->Btn_Start->setText("开始");
    ui->Btn_Start->setChecked(false);
    ui->Btn_Reset->setEnabled(false);
    ui->Btn_Hit->setEnabled(false);
}

主要是将时间归零,将显示情况,并将各个按钮的显示状态复位为默认显示状态。

2.3.3 打点按钮的处理

打点按钮与复位按钮一样,也是只使用clicked函数即可,对应的槽函数的具体实现如下:

void Widget::on_Btn_Hit_clicked()
{
    QString temp;
    m_iHitCnt++;
    temp.sprintf("--计次 %d--", m_iHitCnt);
    ui->Txt_ShowItem->setFontPointSize(9);
    ui->Txt_ShowItem->append(temp);
    ui->Txt_ShowItem->setFontPointSize(12);
    ui->Txt_ShowItem->append(time.toString("[mm:ss.zzz]"));
}

打点功能用于在秒表的运行过程中,记录不同名次的时间,并显示在右侧的文本显示框中。

这里通过setFontPointSize函数来设置不同大小的字体显示。

2.4 秒表表盘的实现

之前这篇文章:嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序,通过代码的方式,实现了一个时钟表盘的显示,本篇在这个的基础上,修改代码,实现一个显示秒和分的秒表表盘,具体修改后的代码如下:

connect(&timer, SIGNAL(timeout()), this, SLOT(update()));
connect(ui->Btn_Reset, SIGNAL(clicked()), this, SLOT(update()));
​
void Widget::paintEvent(QPaintEvent *event)
{
    int side = qMin(width(), height());
    //QTime time = QTime::currentTime();
​
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width()/3, height()*2/5); //画图的基准位置
    painter.scale(side/300.0, side/300.0); //随窗口尺寸自动缩放
​
    //表盘(3个同心圆)
    for (int i=0; i<PANEL_RADIUS_NUM; i++)
    {
        QBrush brush(stPanelParaArr.color);
        QPen pen(stPanelParaArr.color);
        painter.setBrush(brush);
        painter.setPen(pen);
        painter.drawEllipse(-stPanelParaArr.radius, -stPanelParaArr.radius, 2*stPanelParaArr.radius, 2*stPanelParaArr.radius);
    }
​
    //秒的刻度
    painter.setPen(secondColor);
    for (int i = 0; i < 60; i++)
    {
        if ((i % 5) == 0)
        {
            painter.drawLine(PANEL_RADIUS3-8, 0, PANEL_RADIUS3, 0);
            QFont font("TimesNewRoman", SEC_NUM_SIZE);
            painter.setFont(font);
            painter.drawText(-SEC_NUM_SIZE, -(CLOCK_RADIUS-15), 2*SEC_NUM_SIZE, 2*SEC_NUM_SIZE, Qt::AlignHCenter, QString::number(i==0? 60 : i));
        }
        else
        {
            painter.drawLine(PANEL_RADIUS3-5, 0, PANEL_RADIUS3, 0);
        }
        //秒再细分5个格
        for (int j = 0; j < 5; j++)
        {
            painter.rotate(6.0/5);
            if (j != 4)
            {
                painter.drawLine(PANEL_RADIUS3-2, 0, PANEL_RADIUS3, 0);
            }
        }
    }
​
    //分钟的刻度
    painter.setPen(minuteColor);
    for (int k = 0; k < 30; k++)
    {
        if ((k % 5) == 0)
        {
            painter.rotate(-90.0);
            painter.drawLine(PANEL_RADIUS4-8, 0, PANEL_RADIUS4, 0);
            painter.rotate(90.0);
​
            QFont font("TimesNewRoman", MIN_NUM_SIZE);
            painter.setFont(font);
            painter.drawText(-MIN_NUM_SIZE, -(PANEL_RADIUS4-10), 2*MIN_NUM_SIZE, 2*MIN_NUM_SIZE, Qt::AlignHCenter, QString::number(k==0? 30 : k));
        }
        else
        {
            painter.rotate(-90.0);
            painter.drawLine(PANEL_RADIUS4-4, 0, PANEL_RADIUS4, 0);
            painter.rotate(90.0);
        }
        painter.rotate(12.0);
    }
​
    //分钟的表针
    painter.setPen(Qt::NoPen);
    painter.setBrush(minuteColor);
    painter.save();
    painter.rotate(12.0 * (time.minute() + time.second() / 60.0));
    painter.drawConvexPolygon(minuteHand, 3);
    painter.restore();
​
    //秒钟的表针
    painter.setPen(Qt::NoPen);
    painter.setBrush(secondColor);
    painter.save();
    //painter.rotate(6.0 * time.second());
    painter.rotate(6.0 * (time.second()+time.msec()/1000.0));
    painter.drawConvexPolygon(secondHand, 3);
    painter.restore();
​
    painter.end();
}

主要修改是将之前的小时显示去掉,并改为两个时间环:外圈秒环和内圈分环,秒环的范围是0~60秒,分环的范围是0~30分。

秒表表盘的显示效果如下:

3 编译运行

代码是在Window环境中的Qt Creater中编写的,首先是Windows中编译查看效果。

3.1 Windows中编译

在Windows中的运行效果如下图的右图,可以实现手机中秒表类似的计时效果:

3.2 Ubuntu中编译

将Windows中的QT工程源码:

  • .cpp文件

  • .h文件

  • .pro文件

  • .ui文件

复制到Ubuntu中,注意.user文件是不需要的(它是Windows平台的编译配置)。

然后使用ARM平台的编译工具链,我的是在”/home/xxpcb/myTest/imx6ull/otherlib/qt/qt-everywhere-src-5.12.9/arm-qt/“,这里需要先用到它的qmake工具先自动生成Makefile文件,再通过make指令进行编译

使用qmake生成Makefile,进入程序源码目录,执行qmake指令:


/home/xxpcb/myTest/imx6ull/otherlib/qt/qt-everywhere-src-5.12.9/arm-qt/bin/qmake

成功执行之后,就可以看到自动生成的Makefile文件,然后执行make指令进行编译得到可执行文件。

3.3 Linux板子中运行

将可执行文件放到已配置了qt运行环境的Linux板子中,运行并查看效果:

注:

Ubuntu中的具体编译过程,可参考之前这篇文章:嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序

Ubuntu中Qt的交叉编译环境的配置,可参考之前这篇文章:嵌入式Linux-Qt环境搭建

4 总结

本篇通过一个秒表的实例,介绍了如何使用Qt Creator的UI界面设计功能,进行Qt的开发,并将代码进行交叉编译,放入i.MX6ULL的Linux环境中测试运行情况。

 

此帖出自ARM技术论坛

最新回复

嵌入式LINUX还是不太懂呢~太菜啦嵌入式LINUX还是不太懂呢~太菜啦   详情 回复 发表于 2022-10-11 13:12
点赞 关注(1)
 

回复
举报

6614

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

通过使用Qt Creator的UI界面设计功能,顺便把秒表的实例整的很详细了,精彩

此帖出自ARM技术论坛
 
 
 

回复

35

帖子

2

TA的资源

一粒金砂(中级)

板凳
 

Qt [1]  是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些,Qt很容易扩展,并且允许真正地组件编程。

2008年,Qt Company科技被诺基亚公司收购,Qt也因此成为诺基亚旗下的编程语言工具。2012年,Qt被Digia收购。

2014年4月,跨平台集成开发环境Qt Creator 3.1.0正式发布,实现了对于iOS的完全支持,新增WinRT、Beautifier等插件,废弃了无Python接口的GDB调试支持,集成了基于ClangC/C++代码模块,并对Android支持做出了调整,至此实现了全面支持iOS、Android、WP,它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能。基本上,Qt 同 X Window 上的 Motif,Openwin,GTK 等图形界面库和 Windows 平台上的 MFC,OWL,VCL,ATL 是同类型的东西。

此帖出自ARM技术论坛
 
 
 

回复

1万

帖子

203

TA的资源

管理员

4
 

这个不错呀!赞(≧▽≦)

此帖出自ARM技术论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复

4775

帖子

19

TA的资源

版主

5
 

牛呀学习了 据说钟表类最难的是万年历 尤其是对于闰年闰秒的处理

此帖出自ARM技术论坛
 
 
 

回复

7473

帖子

18

TA的资源

五彩晶圆(高级)

6
 

qt库确实用起来很方便,我现在在linux下面用qtcore搞事情。

此帖出自ARM技术论坛
 
个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

7
 

感谢分享 点个赞

此帖出自ARM技术论坛
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

8
 

    考虑的很全,    qt功能实现起来还是比较简单

此帖出自ARM技术论坛
 
 
 

回复

9

帖子

0

TA的资源

一粒金砂(中级)

9
 

真的很详细,感谢楼主分享

此帖出自ARM技术论坛
 
 
 

回复

87

帖子

0

TA的资源

一粒金砂(中级)

10
 

嵌入式LINUX还是不太懂呢~太菜啦

此帖出自ARM技术论坛
 
 
 

回复

87

帖子

0

TA的资源

一粒金砂(中级)

11
 

嵌入式LINUX还是不太懂呢~太菜啦嵌入式LINUX还是不太懂呢~太菜啦

此帖出自ARM技术论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表