加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 1 新建Qt工程
    • 2 代碼編寫
    • 3 編譯運(yùn)行
    •  
    • 4 總結(jié)
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

嵌入式Qt-做一個(gè)秒表

2022/08/01
1872
閱讀需 13 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

之前的文章:嵌入式Qt-動(dòng)手編寫并運(yùn)行自己的第1個(gè)ARM-Qt程序,介紹了如何編寫第一個(gè)嵌入式Qt程序,實(shí)現(xiàn)了一個(gè)電子時(shí)鐘的演示。

本篇,繼續(xù)進(jìn)行Qt實(shí)踐,仿照手機(jī)中的秒表,實(shí)現(xiàn)一個(gè)相同功能的秒表:

回顧上一次的Qt開發(fā)流程,整個(gè)Qt的開發(fā)都是通過敲代碼實(shí)現(xiàn)的,實(shí)際上,還可以利用Qt Creater的UI界面功能,通過圖像化的配置來開發(fā)圖形界面,本篇就使用這種方法來進(jìn)行開發(fā)。

先來看下效果:

1 新建Qt工程

Qt工程創(chuàng)建的具體步驟可參照之前的文章:嵌入式Qt-動(dòng)手編寫并運(yùn)行自己的第1個(gè)ARM-Qt程序,這里只說明不同之處。

上篇是通過代碼實(shí)現(xiàn)頁面設(shè)計(jì)的,本篇要借助Qt Creater的UI界面設(shè)計(jì)功能,因此要把下面的創(chuàng)建頁面勾選上:

創(chuàng)建完成之后的Qt默認(rèn)工程結(jié)構(gòu)如下:

雙擊widget.ui,即可打開UI設(shè)置頁面,如下圖:

這里先簡單熟悉下各個(gè)功能區(qū):

2 代碼編寫

2.1 ui界面設(shè)計(jì)

修改界面的尺寸,我的Linux板子屏幕的分辨率是800x480,因此調(diào)整到對(duì)應(yīng)的尺寸:

從左側(cè)拖入一個(gè)Label,然后可以修改字體的大?。?/p>

再從左側(cè)拖入其它需要用到的組件(PushButton、TextBrower)和位置調(diào)節(jié)組件(彈簧形狀的HorizontalSpacer、VericalSpacer)

進(jìn)行水平布局和豎直布局,選中對(duì)應(yīng)的組件,例如3個(gè)按鈕和中間的2個(gè)彈簧,點(diǎn)擊上方工具欄中的水平布局按鈕:

3個(gè)按鍵的水平布局效果如下:

然后再依次對(duì)其它組件進(jìn)行布局:

字體可以調(diào)整到居中顯示:

鼠標(biāo)選中最大的組合組件,拖拽邊緣調(diào)整到合適的外尺寸。然后選中不同級(jí)別的組合組件,調(diào)整layoutStretch的參數(shù),實(shí)現(xiàn)按比例顯示各個(gè)組件(相當(dāng)于調(diào)節(jié)各個(gè)彈簧組件的彈力大小)

點(diǎn)擊左下角上面那個(gè)三角圖標(biāo),運(yùn)行,查看效果:

注意左邊留的空白是給秒表的表盤留的。

2.2 QTimer與QTime介紹

QTimer 類為定時(shí)器提供了一個(gè)高級(jí)編程接口,提供重復(fù)和單次計(jì)時(shí)。

QTime 類提供時(shí)鐘時(shí)間功能,QTime 對(duì)象包含一個(gè)時(shí)鐘時(shí)間,它可以表示為自午夜以來的小時(shí)數(shù)、分鐘數(shù)、秒數(shù)和毫秒數(shù)。

Qt Creater提供了方便的幫助文檔,可以在Qt Creater中直接查看對(duì)應(yīng)功能函數(shù)的使用,比如搜索QTimer,就可以看到對(duì)應(yīng)的介紹,以及可用的API函數(shù):

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

  • start:啟動(dòng)定時(shí)器stop:停止定時(shí)器

再看看QTime的介紹:

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

  • setHMS:設(shè)置初始時(shí)間addMSecs:增加一個(gè)時(shí)間(毫秒單位)toString:時(shí)間轉(zhuǎn)為字符串格式minute:獲取分鐘second:獲取秒msec:獲取毫秒

2.3 對(duì)應(yīng)按鈕的函數(shù)

為了編寫出更易看懂的代碼,在編寫代碼之前,需要修改對(duì)應(yīng)的組件的默認(rèn)名稱為便于理解的名稱,比如我將3個(gè)按鍵的名稱分別改為了:

  • Btn_Start:開始按鈕,并同時(shí)具有暫停/繼續(xù)功能Btn_Reset:復(fù)位按鈕Btn_Hit:打點(diǎn)按鈕,用于記錄不同名次的時(shí)間

然后還要手動(dòng)添加QTimer和QTime對(duì)象,用于實(shí)現(xiàn)秒表的計(jì)時(shí)功能:

2.3.1 開始按鈕的處理

Qt編程中重要處理就是信號(hào)和槽機(jī)制,它可用通過手動(dòng)通過connet函數(shù)實(shí)現(xiàn),而對(duì)于使用Qt Creater的圖形界面設(shè)計(jì)方式,通常也是繼續(xù)通過界面實(shí)現(xiàn)信號(hào)和槽的連接:在開始按鈕上右鍵,選則“**轉(zhuǎn)到槽...**”:

然后有多種按鈕信號(hào)可以選擇,因?yàn)殚_始按鈕同時(shí)具有暫停/繼續(xù)的功能,這里使用toggled功能,利用按鈕的按下和松開狀態(tài),來實(shí)現(xiàn)暫停/繼續(xù)的功能:

點(diǎn)擊OK之后,會(huì)自動(dòng)跳到到代碼頁面,并自動(dòng)生成對(duì)應(yīng)的槽函數(shù)框架,然后就可以在里面編譯對(duì)應(yīng)的業(yè)務(wù)邏輯代碼了:

開始按鈕的具體業(yè)務(wù)邏輯代碼如下,當(dāng)首次按下時(shí),checked為true,此時(shí)啟動(dòng)timer,記錄此時(shí)的時(shí)間戳,然后將按鈕的文字顯示為“暫停”,同時(shí)將復(fù)位和打點(diǎn)按鈕置灰,使這兩個(gè)按鈕不能再按下,因?yàn)闀和5臅r(shí)候執(zhí)行復(fù)位和打點(diǎn)無意義。

timer每隔一段時(shí)間會(huì)觸發(fā)超時(shí),這里ADD_TIME_MSEC設(shè)置的是30ms,超時(shí)時(shí)間到后,編寫對(duì)應(yīng)的超時(shí)處理函數(shù)timeout_slot以及聲明對(duì)應(yīng)的信號(hào)和槽的處理。

void Widget::on_Btn_Start_toggled(bool checked)
{
    if (checked)
    {
        timer.start(ADD_TIME_MSEC);
        lastTime = QTime::currentTime();//記錄時(shí)間戳
        ui->Btn_Start->setText("暫停");
        ui->Btn_Reset->setEnabled(false);
        ui->Btn_Hit->setEnabled(true);
    }
    else
    {
        timer.stop();
        ui->Btn_Start->setText("繼續(xù)");
        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"));
}

超時(shí)時(shí)間到了之后,計(jì)算一些兩次的時(shí)間差值,然后通過addMSecs函數(shù)來累加時(shí)間。

2.3.2 復(fù)位按鈕的處理

復(fù)位按鈕也是通過右鍵來調(diào)整到槽,注意這里使用clicked函數(shù)即可,因?yàn)閺?fù)位按鈕只需要使用它的點(diǎn)擊按下功能:

對(duì)應(yīng)的槽函數(shù)的具體實(shí)現(xiàn)如下:

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);
}

主要是將時(shí)間歸零,將顯示情況,并將各個(gè)按鈕的顯示狀態(tài)復(fù)位為默認(rèn)顯示狀態(tài)。

2.3.3 打點(diǎn)按鈕的處理

打點(diǎn)按鈕與復(fù)位按鈕一樣,也是只使用clicked函數(shù)即可,對(duì)應(yīng)的槽函數(shù)的具體實(shí)現(xiàn)如下:

void Widget::on_Btn_Hit_clicked()
{
    QString temp;
    m_iHitCnt++;
    temp.sprintf("--計(jì)次 %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]"));
}

打點(diǎn)功能用于在秒表的運(yùn)行過程中,記錄不同名次的時(shí)間,并顯示在右側(cè)的文本顯示框中。

這里通過setFontPointSize函數(shù)來設(shè)置不同大小的字體顯示。

2.4 秒表表盤的實(shí)現(xiàn)

之前這篇文章:嵌入式Qt-動(dòng)手編寫并運(yùn)行自己的第1個(gè)ARM-Qt程序,通過代碼的方式,實(shí)現(xiàn)了一個(gè)時(shí)鐘表盤的顯示,本篇在這個(gè)的基礎(chǔ)上,修改代碼,實(shí)現(xiàn)一個(gè)顯示秒和分的秒表表盤,具體修改后的代碼如下:

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); //畫圖的基準(zhǔn)位置
    painter.scale(side/300.0, side/300.0); //隨窗口尺寸自動(dòng)縮放

    //表盤(3個(gè)同心圓)
    for (int i=0; i<PANEL_RADIUS_NUM; i++)
    {
        QBrush brush(stPanelParaArr[i].color);
        QPen pen(stPanelParaArr[i].color);
        painter.setBrush(brush);
        painter.setPen(pen);
        painter.drawEllipse(-stPanelParaArr[i].radius, -stPanelParaArr[i].radius, 2*stPanelParaArr[i].radius, 2*stPanelParaArr[i].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);
        }
        //秒再細(xì)分5個(gè)格
        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();
}

主要修改是將之前的小時(shí)顯示去掉,并改為兩個(gè)時(shí)間環(huán):外圈秒環(huán)和內(nèi)圈分環(huán),秒環(huán)的范圍是0~60秒,分環(huán)的范圍是0~30分。

秒表表盤的顯示效果如下:

3 編譯運(yùn)行

代碼是在Window環(huán)境中的Qt Creater中編寫的,首先是Windows中編譯查看效果。

3.1 Windows中編譯

在Windows中的運(yùn)行效果如下圖的右圖,可以實(shí)現(xiàn)手機(jī)中秒表類似的計(jì)時(shí)效果:

 

3.2 Ubuntu中編譯

將Windows中的QT工程源碼:

  • .cpp文件.h文件.pro文件.ui文件

復(fù)制到Ubuntu中,注意.user文件是不需要的(它是Windows平臺(tái)的編譯配置)。

然后使用ARM平臺(tái)的編譯工具鏈,我的是在”/home/xxpcb/myTest/imx6ull/otherlib/qt/qt-everywhere-src-5.12.9/arm-qt/“,這里需要先用到它的qmake工具先自動(dòng)生成Makefile文件,再通過make指令進(jìn)行編譯。

使用qmake生成Makefile,進(jìn)入程序源碼目錄,執(zhí)行qmake指令:

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

成功執(zhí)行之后,就可以看到自動(dòng)生成的Makefile文件,然后執(zhí)行make指令進(jìn)行編譯得到可執(zhí)行文件。

3.3 Linux板子中運(yùn)行

將可執(zhí)行文件放到已配置了qt運(yùn)行環(huán)境的Linux板子中,運(yùn)行并查看效果:

注:

Ubuntu中的具體編譯過程,可參考之前這篇文章:嵌入式Qt-動(dòng)手編寫并運(yùn)行自己的第1個(gè)ARM-Qt程序

Ubuntu中Qt的交叉編譯環(huán)境的配置,可參考之前這篇文章:嵌入式Linux-Qt環(huán)境搭建

 

4 總結(jié)

本篇通過一個(gè)秒表的實(shí)例,介紹了如何使用Qt Creator的UI界面設(shè)計(jì)功能,進(jìn)行Qt的開發(fā),并將代碼進(jìn)行交叉編譯,放入i.MX6ULL的Linux環(huán)境中測試運(yùn)行情況。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

控制科學(xué)與工程碩士,日常分享單片機(jī)、嵌入式、C/C++、Linux等學(xué)習(xí)經(jīng)驗(yàn)干貨~