每日激勵:“不設限和自我肯定的心態:I can do all things。 — Stephen Curry”
緒論?:
本文圍繞Qt中常用的顯示類控件展開,重點講解了 QLabel(文本/圖片顯示)、QLCDNumber(數字顯示)、QProgressBar(進度條) 和 QCalendarWidget(日歷控件) 的核心屬性、使用場景及代碼實例,幫助快速上手Qt界面開發中的基礎顯示功能。
————————
早關注不迷路,話不多說安全帶系好,發車啦(建議電腦觀看)。
顯示類控件
Label
QLabel 可以?來顯??本和圖?
屬性 | 說明 |
---|---|
text | QLabel 中的?本 |
textFormat | ?本的格式: Qt::PlainText 純?本(最普通的文本) Qt::RichText 富?本(?持 html 標簽、內容更豐富的文本、就類似word工具) Qt::MarkdownText markdown 格式 (提供各種特殊符號表示各種的樣式 / 格式) Qt::AutoText 根據?本內容?動決定?本格式 |
pixmap | QLabel 內部包含的圖?. |
scaledContents | 設為 true 表?內容?動拉伸填充 QLabel 、設為 false 則不會?動拉伸(讓圖片自動填充滿) |
alignment | 對??式。可以設置?平和垂直?向如何對?(靠左/靠右/居中…) |
wordWrap | 設為 true 內部的?本會?動換?. 設為 false 則內部?本不會?動換? |
indent | 設置?本縮進。?平和垂直?向都?效. |
margin | 內部?本和邊框之間的邊距。不同于于 indent, 但是是上下左右四個?向都同時有效. ? indent 最多只是兩個?向有效(具體哪兩個?向有效取決于 alignment ) |
openExternalLinks | 是否允許打開?個外部的鏈接. (當 QLabel ?本內容包含 url 的時候涉及到) |
buddy | 給 QLabel 關聯?個 “伙伴” , 這樣點擊 QLabel 時就能激活對應的伙伴 例如:伙伴如果是?個 QCheckBox, 那么該 QCheckBox 就會被選中 |
代碼實例
設置文本格式:
- ui文件中拖拽三個 label 控件
- 構造函數中設置label的文本格式(textFormat)
- 第一個:純文本(setTextFormat)、setText:這是一段純文本
- 第二個:富文本…、使用
<b>xxxxx</b>
加粗標簽 - 第三個:markdown、使用 # 設置標題
比較簡單源碼就不放了(如下)
設置圖片QPixmap
- 拖拽label、使用qrc機制,添加圖片
- 將QLabel設置和窗口一樣大,并且把QLabel左上角設置到窗口的左上角這里
- 將label的geometry的x y設置成 0 0 并且獲取窗口的寬高給到label(直接this->width、… 即可)
- 直接寫死某個數值,稱為 “硬編碼”(要保證數值不改變)
- label添加圖片:創建QPixmap對象構造圖片路徑
- 將該對圖片象設置(setpixmap)到label中、其中可能還會填不滿因為要保證圖片大小足夠大
- 若不夠大可以通過scaledContents進行拉伸填充
源碼如下:
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel* label = new QLabel(this);label->setGeometry(0,0,this->width(),this->height());//獲取窗口的寬和高給到labellabel->setScaledContents(true);QPixmap pixmap(":/1.jpg");label->setPixmap(pixmap);
}Widget::~Widget()
{delete ui;
}
但可能還會有點問題,因為是在構造函數中設置的尺寸,所以這個尺寸設置是一次性的,若窗口再次發生改變(修改窗口大小)QLabel中的圖片就不會變化了
解決辦法
- 首先了解概念:Qt中的操作會有兩類概念:信號、事件
- 當用戶拖拽修改窗口大小的時候,就會觸發resize事件(resizeEvent)、從A拖到B的過程的他是 連續的一系列的觸發 resizeEvent 事件
- 可以讓 Widget 窗口類,重寫父類QWidget的resizeEvent虛函數,該函數在鼠標拖動窗口尺寸時會被返回調用執行,所以重寫該函數,當父類調用該函數時就會調用到子類中的重寫的該函數(多態~)
- 重寫(聲明+定義)void resizeEvent(QResizeEvent* event)
- 此時的event就會窗口的實時大小
- 所以對于label的大小就能通過event對象獲取高度和寬度動態的改變
附:其中QResizeEvent不能直接使用,需要添加頭文件 #
include <QResizeEvent>
源碼如下:
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
#include <QDebug>
#include <QResizeEvent>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->label->setGeometry(0,0,this->width(),this->height());ui->label->setScaledContents(true);//設置自動拉伸QPixmap pixmap(":/1.jpg");ui->label->setPixmap(pixmap);//設置圖片
}Widget::~Widget()
{delete ui;
}void Widget::resizeEvent(QResizeEvent * event)
{qDebug() << event->size();//打印查看當前窗口大小ui->label->setGeometry(0,0,event->size().width(),event->size().height());//ui->label->setGeometry(0,0,this->width(),this->height());
}
?本對?, ?動換?, 縮進, 邊距
-
構建幾個label,設置邊框:QFrame
- 通過設置邊框 frameShape:Box
-
構造函數中設置 label 的不同屬性
-
Text:“這是一段文本”
-
Alignment:
- Qt::AlignHCenter(水平居中)
- Qt::AlignVCenter(垂直居中)
- AlignRight(靠右對齊)
- AlignTop(靠上對齊)…
-
自動換行(WordWrap):
-
自動換行:
-
不換行:
-
-
設置縮進
-
Text:文本
-
Indent:50(單位:像素)
-
注意:此處的縮進即使文本換行了,后面的也仍然會縮進,而非首行縮進
-
若要實現首行縮進可以使用:CSS(QSS)中 text-indent 屬性實現首行縮進
-
-
設置邊距
- Margin:邊距(單位:像素)
- 其中上下左右都會設置到,其中當邊距過大可能會導致文本無法顯示(如下圖,并且還保持縮進)
-
QLabel 伙伴
- ui文件中拖拽兩個 RadioButuon:選項1/2 、和兩個label 快捷鍵
- 并設置快捷鍵:設置方法在文本后面添加 (&A),A代表某個鍵位的值 如上&T
- 將label通過Buddy進行設置和RadioButuon的關聯
- QLabel中的文本可以指定快捷鍵
- 但功能較弱,必須 在文本中使用 & 跟上字符來表示快捷鍵(不過加上括號會更好理解點!)
-
LCD Number
QLCdNumber是一個專門用來顯示數字的控件,類似“老式計算機”的效果
屬性 | 說明 |
---|---|
intValue | QLCDNumber 顯?的數字值(int). |
value | QLCDNumber 顯?的數字值(double) 和 intValue 是聯動的. 例如給 value 設為 1.5, intValue 的值就是 2 另外, 設置 value 和 intValue 的?法名字為 display , ?不是 setValue 或者 setIntValue . |
digitCount | 顯??位數字 |
mode | 數字顯?形式. 1.QLCDNumber::Dec :?進制模式,顯?常規的?進制數字。 2. QLCDNumber::Hex :?六進制模式,以?六進制格式顯?數字。 3. QLCDNumber::Bin :?進制模式,以?進制格式顯?數字。 4. QLCDNumber::Oct :?進制模式,以?進制格式顯?數字。 只有?進制的時候才能顯??數點后的內容. |
segmentStyle | 設置顯??格. 1. QLCDNumber::Flat :平?的顯??格,數字呈現在?個平坦的表?上。 2. QLCDNumber::Outline :輪廓顯??格,數字具有清晰的輪廓和陰影效果。 3. QLCDNumber::Filled :填充顯??格,數字被填充顏?并與背景區分開。 |
smallDecimalPoint | 設置?較?的 ?數點. |
其中注意在設置value和intValue的方法名字為 display,而不是setValue/setIntValue(這種設計是不太好的所以自己設計時就盡量保持一致)
實例:倒計時 QTimer的使用
- ui文件中拖拽上 LCD Number
- 設置顯示初始值:10,然后要實現每秒鐘 -1 的效果
- C++標準庫中沒有提供定時器的實現,boost里面提供了對應的功能
- Qt中也封裝了對應的定時器(結合信號槽機制)
- QTimer 這個類對象,就會自動不斷 產生 timeout 信號
- 可以通過start方式來開啟定時器
- 并且參數中設定觸發timeout信號的周期,
- 結合connect,把這個 timeout 信號綁定到槽函數中
- 就可以執行持續觸發槽函數,從而修改LCDNumber中的數字的邏輯
- 將QTimer對象寫成 類成員變量,并構造到對象樹中
- 把 QTimer 的 timeout 信號和咱們自己的槽函數(handle)進行連接
- 啟動定時器,參數是觸發timeout的周期,單位是 ms
- 編寫handle槽函數(定義在Widget的類函數)
- 先拿到LCDNumber中的數字,通過ui找到lcdNumber在獲取數字(intvalue)
- 判斷value是否小于0
- 若小于則調用stop,停止定時器
- 每次將lcdNumber的value中的值設置(display) - 1
源碼:
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lcdNumber->display(10);//注意是displaytimer = new QTimer(this);//注意不要使用成 QTimetimer->start(1000);//發送信號的時間 10000connect(timer,&QTimer::timeout,this,&Widget::handle);}Widget::~Widget()
{delete ui;
}void Widget::handle(){int v = ui->lcdNumber->intValue();if(v > 0){ui->lcdNumber->display(v - 1);//注意是display}else{timer->stop();//暫定}
}
不使用Qtime來實現:
- 拖拽LCDNumber
- 獲取 lcd 對象中的 intvalue(整形)
- 循環判斷value值(若小于0則直接退出)
- 內部使用C++11的 std::this_thread::sleep_for(std::chrono::seconds(1)) 進行休眠1s
- 每次設置value-1
- 但寫在 widget 構造函數中并沒有效果,因為顯示在構造后面(具體如下圖)
所需要需要修改:
- 使用thread(這是操作系統提供的api)
- 內部使用lambda表達式
- 實現和上面一樣
- 但這樣寫也會出現錯誤,因為界面有一個專門的線程負責維護更新(主線程、main函數所在的線程),對于GUI來說,內部包含了許多隱藏狀態,Qt為了保證修改界面的過程中,線程是不會收到影響的,Qt禁止了其他線程直接修改界面
因為:
- 對于一個圖形化界面會有許多的變量,進很容易出現線程安全,所以就要求所有對界面的修改操作必須在主線程中完成!!
- 對于Qt的槽函數來說,默認情況下,槽函數都是由主線程調用的,所以使用槽函數修改界面是沒問題的
- a.exec 就會時主線程進入“事件循環”,一直循環,每執行一次循環,都會有固定的事情要操作(其中的槽函數調用就是通過這里完成)
ProgressBar進度條
使? QProgressBar 表??個進度條
一些核心屬性:
屬性 | 說明 |
---|---|
minimum | 進度條最?值 |
maximum | 進度條最?值 |
value | 進度條當前值 |
alignment | ?本在進度條中的對??式: Qt::AlignLeft : 左對? Qt::AlignRight : 右對? Qt::AlignCenter : 居中對? Qt::AlignJustify : 兩端對? |
textVisible | 進度條的數字是否可?. |
orientation | 進度條的?向是?平還是垂直 |
invertAppearance | 是否是朝反?向增?進度 |
textDirection | ?本的朝向. |
format | 展?的數字格式. %p :表?進度的百分?(0-100) 、 %v :表?進度的數值(0-100)、 %m :表?剩余時間(以毫秒為單位) 、 %t :表?總時間(以毫秒為單位) |
實例:進度條
讓個這個進度條的進度跟隨時間增長(每隔100ms 進度條數值增長1)
- 拖拽ProgressBar到界面上
- 創建Qtimer 成員變量 timer
- 構造函數中:
- new上空間并且掛上對象樹
- 連接connect連接槽函數
- 將 timer 對象和 handle 進行連接,通過 Qtimer::timeout 信號進行觸發
- 創建handle成員函數
- 注意啟動timer定時器(100ms)
- handle函數:
- 獲取當前進度條的當前數值,通過ObjectName調用value獲取
- 判斷若value >= 100
- 代表進度條滿了就可以停止定時器了
- 并直接返回
- 每次 讓value值增加1
源碼:
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);timer = new QTimer();timer->start(100);//設置100ms周期的持續發送timeout信號//設置槽函數,讓其實現ProcessBar的遞增connect(timer,&QTimer::timeout,this,&Widget::handle);
}Widget::~Widget()
{delete ui;
}void Widget::handle(){//1. 獲取process的值int value = ui->progressBar->value();ui->progressBar->setValue(value+1);//每次進來都讓其+1if(value >= ui->progressBar->maximum()){//若夠了或者timer->stop();//停止信號}}
其中在widget.h中用到了QTimer,卻可以不用該文件中聲明頭文件,是因為在其他文件中聲明,所以就能使用(在.h中不添加、在.cpp中添加)
- 因為在Qt內部提供了體術技巧:Qt中有一個專門的頭文件,這個頭文件包含了Qt中所有類的前置聲明
- 這個頭文件,一般不會直接接觸到,但是包含了其他Qt的頭文件,都會間接包含到這個頭文件中,當然這并不代表你可以不寫頭文件,你必須在某個文件中添加頭文件
為啥要提供這種技巧?
主要是解決編譯速度的問題~
- 因為C/C++代碼編譯速度是較慢的
- 因為include頭文件的文本替換是比較慢的~
- 因此盡可能減少頭文件的個數,就能有效編譯時間,Qt 使用 class 前置聲明的方式盡量減少頭文件的包含(這樣某個文件中定義了該頭文件其他文件就不需要再包含了)
一些互聯網大廠,甚至會有專門的“編譯集群”(分布式編譯)
使用QSS將進度條改成紅色的
QSS機制可以使用 styleSheet 通過樣式來修改進度條的顏?.
- 實現方法點擊processBar控件右側屬性找到 styleSheet / 右擊控件選擇 “編輯樣式表”
- 內部樣式設置
QProgressBar::chunk {background-color: #FF0000;} 1. QProgressBar::chunk:代表指定控件,選擇器針對那個控件生效 2. {} 內部填寫樣式
其中注意的是:進度條具體的進度設置一般是根據時間任務類型靈活設置的(這里就簡單的實現了)
例如:要讀取某個文件,就可以先獲取該文件的總大小,每讀取一部分數據(就可以算出讀了多少數據段)進行更新進度條的數值
Calendar Widget
核?屬性
屬性 | 說明 |
---|---|
selectDate | 當前選中的?期 |
minimumDate | 最??期 |
maximumDate | 最??期 |
firstDayOfWeek | 每周的第?天(也就是?歷的第?列) 是周? |
gridVisible | 是否顯?表格的邊框 |
selectionMode | 是否允許選擇?期 |
navigationBarVisible | ?歷上?標題是否顯? |
horizontalHeaderFormat | ?歷上?標題顯?的?期格式 |
verticalHeaderFormat | ?歷第?列顯?的內容格式 |
dateEditEnabled | 是否允許?期被編輯 |
重要信號
信號 | 說明 |
---|---|
selectionChanged(const QDate&) | 當選中的?期發?改變時發出 |
activated(const QDate&) | 當雙擊?個有效的?期或者按下回?鍵時發出,形參是?個QDate類型,保存了選中的?期 |
currentPageChanged(int, int) | 當年份?份改變時發出,形參表?改變后的新年份和?份 |
實例
- ui文件中拖拽 calendar Widget、label
- 通過label中顯示選擇的日期
- 通過selectionChanged信號進行獲取用戶選中的日期,創建信號槽函數
- 槽函數編寫:
- 獲取選中日期 (selectDate)放到QDate對象中
- 將label中的文本修改為了 date 時間(需要配合QDate::toString轉換成字符串)
void Widget::on_calendarWidget_selectionChanged()
{
// qDebug() << ui->calendarWidget->selectedDate();QDate date = ui->calendarWidget->selectedDate();ui->label->setText(date.toString());
}
本章完。預知后事如何,暫聽下回分解。
如果有任何問題歡迎討論哈!
如果覺得這篇文章對你有所幫助的話點點贊吧!
持續更新大量C++ Qt細致內容,早關注不迷路。
?