日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Qt】Qt手动布局

發布時間:2024/4/24 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Qt】Qt手动布局 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

00. 目錄

文章目錄

    • 00. 目錄
    • 01. 概述
    • 02. 開發環境
    • 03. 限定窗口大小
    • 04. 手動計算調整控件分布
    • 05. 計算文本顯示寬度
    • 06. 附錄

01. 概述

本次內容主要講解手動計算來調整控件分布,以及限定窗口最大尺寸和最小尺寸。 雖然使用 Qt 布局器非常方便,不需要我們自己去計算控件實時的位置和大小, 但是我們還是應該學習如何根據窗口大小,自己編寫代碼計算各個控件的位置和大小, 這是一項傳統的技術活,多學點基本知識總是好的,因為布局器也不是萬能的。

手動計算和調整控件分布這項傳統技術有缺點,就是沒有通用性,控件多一個、少一個都得重新計算。 但也有優點,就是程序員對界面調整的掌控有最大的自由度和靈活度。我們本節第一個例子是限定窗口的最大尺寸和最小尺寸。第二個例子是根據窗口大小和控件的類型、數 目,手動計算調整控件的分布。 第三個例子根據程序默認字體和不同文本長度計算按鈕控件實時的寬度,其他控件根據文本內容調整大小的原理也是類似的。

02. 開發環境

Windows系統:Windows10

Qt版本:Qt5.15或者Qt6

03. 限定窗口大小

窗體里用到的控件幾乎都是以 QWidget 為基類,QWidget 關于控件或窗口大小的設置有如下幾個函數:
設置窗口占用矩形的函數:

void setGeometry(int x, int y, int w, int h) void setGeometry(const QRect &) x 和 y 是控件距離父窗口左上角的坐標,w 是寬度,h 是高度。QRect 也是以類似的 4 個參數構造。

如果不改變窗口大小,只是移動窗口左上角坐標,那么使用如下函數:

void move(int x, int y) void move(const QPoint &)

如果不移動窗口左上角坐標,只改變窗口的尺寸大小,那么使用如下函數:

void resize(int w, int h) void resize(const QSize &) w 是寬度,h 是高度。QSize 也是以寬度、高度為參數構造。

當窗體尺寸變化時,不會發送信號,而是調用內部保護類型的虛函數 resizeEvent()。因為一方面信號和槽有開銷,這對實時繪圖不利,另一方面窗體變化應該由類對象內部處理,而不是交給外部對象處理,所以窗口大小變化時,調用的 是內部保護類型虛函數:

void QWidget::?resizeEvent(QResizeEvent * event) //virtual protected 注意一般不要在 ?resizeEvent() 函數內部調用 setGeometry() 或者 resize() 改變窗口尺寸,那樣容易導致?resizeEvent() 函數循環觸發,進入死循環。

限定窗口的尺寸范圍有兩個屬性 minimumSize (最小尺寸,該屬性又可細分為 minimumWidth、minimumHeight)和 maximumSize (最大尺寸,該屬性又可細分為 maximumWidth、maximumHeight),無論使用代碼調用設置函數還是用 Qt 設計師直接設置屬性都可以限定窗口尺寸范圍:

void setMinimumSize(const QSize &) //最小尺寸 void setMinimumSize(int minw, int minh) //最小尺寸 void setMaximumSize(const QSize &) //最大尺寸 void setMaximumSize(int maxw, int maxh) //最大尺寸

如果同時將窗口的最大尺寸和最小尺寸設置為一樣大,那么窗口就是固定尺寸的,不能拉伸或縮小。
設置固定大小的窗口,可以同時設置上面的最小尺寸和最大尺寸,或者調用一個比較方便的函數:

void setFixedSize(const QSize & s) void setFixedSize(int w, int h)

如果只希望單獨設置固定寬度或者固定高度,則可以使用如下函數:

void setFixedWidth(int w) //單獨設置固定寬度 void setFixedHeight(int h) //單獨設置固定高度

窗口的尺寸和坐標設置函數就介紹這些,控件的尺寸和坐標設置函數是一樣的。

創建項目,配置好項目后,打開 widget.ui 界面文件,進入 QtCreator 設計模式:

我們右擊主窗體下面空白區域,右鍵菜單里選擇 “大小限定” ,然后看到 6 個子菜單項,解釋一下:

① “設定最小寬度”,就是將現在看到的窗體寬度設置為該窗體的最小寬度。
② “設定最小高度”,就是將現在看到的窗體高度設置為該窗體的最小高度。
③ “設定最小大小”,就是將現在看到的窗體尺寸設置為該窗體的最小尺寸。
④ “設定最大寬度”,就是將現在看到的窗體寬度設置為該窗體的最大寬度。
⑤ “設定最大高度”,就是將現在看到的窗體高度設置為該窗體的最大高度。
⑥ “設定最大大小”,就是將現在看到的窗體尺寸設置為該窗體的最大尺寸。

這里是右擊主窗體空白區的,設置的就是主窗體的大小限定。如果右擊某一個控件,那么就是設置該控件的大小限定,過程類似。

【注意】

拉伸窗口到自己想要的尺寸,然后設置最大大小、設置最大寬度、設置最大高度、設置最小寬度、設置最小高度和設置最小大小。

04. 手動計算調整控件分布

在不使用 Qt 布局器的情況下,我們可以手動規劃各個控件的位置和尺寸設置,當然,這個手動計算的過程要根據不同界面進行不同的規劃。手動計算調整控件分布的缺點就是沒有什么通用性,換 個程序界面或者多一個控件、少一個控件都需要改寫 cpp 文件中的源代碼。接下來我們設計一個能跟隨窗口大小變化而自動調整 各個控件分布和尺寸的程序。

新建QMainWindows項目,然后打開UI文件,設計如下:

● 首先是主界面窗體的大概情況設定:
主窗體第一行是非常大的標簽控件 labelShow ,占據其他控件剩下的區域。
第二行是四個按壓按鈕,目前的尺寸都是 75*23 ,四個按鈕的文字能全部顯示出來,在窗口變大時,不需要拉伸,但是需要均勻分布在同一水平線上,四個按鈕之間的間隔相同。
我們從這四個按鈕計算主界面最小寬度,比如按鈕間隔最小為 10,與兩邊框間距為 10,那么最小寬度就是
10 * 5 + 75 * 4 == 350 ,我們將主窗體最小高度設置為與最小寬度一樣,比較省事,就是最小尺寸 350 * 350 ,最大尺寸不限。
主窗體第三行的控件就是一個水平滑動條 horizontalSlider ,我們希望它距離主窗體底部 10 ,寬度與第二行右邊三個按鈕占據寬度一樣,水平滑動條高度是固定為原本的 21 。

● 現在我們來詳細規劃并計算各個控件的分布和尺寸:
這個主窗體的規劃思路是這樣的,控件之間以及控件與四個邊界都是有 10 像素的間隙,然后水平方向因為第二行控件最多,并且第三行的水平滑動條依賴第二行右邊三 個按鈕,我們從這第二行開始規劃。

當窗體拉伸后的寬度的 W,高度為 H ,按鈕尺寸固定為 75*23 ,
第一個按鈕的左上角起點坐標:
水平 x1 = 10,距離左邊界為 10,這個是固定的。
垂直 y1 = H - 10 - 21 - 10 - 23 ,其中第一個 10 是水平滑動條距離底部的垂直空隙,21 是水平滑動條的高度,
第二個 10 是水平滑動條與按鈕的垂直間隙,23 是按鈕自己的高度。

四個按鈕的在同一水平線上,也就是 y1 == y2 == y3 == y4。
第四個按鈕也是距離右邊界 10 個像素空隙,那么可以容易得出:
x4 = W - 10 - 75 ,75 是按鈕自己的寬度。

四個按鈕之間有三個大間隙,計算這個三個間隙總大小:
nTriGap = W - 10 - 10 - 754 ,兩個 10 是兩個邊界間隙,754 是按鈕自己占的寬度,那么單個的大間隙就為:
nGap = nTriGap / 3 。
然后計算第二個和第三個按鈕的水平坐標:
x2 = x1 + 75 + nGap;
x3 = x4 - 75 - nGap.
這樣四個按鈕的坐標和尺寸就都確定了。

按鈕設置好之后,其他的就好辦了,第三行的水平滑動條:
xSlider = x2 ,
ySlider = H - 10 - 21 ,最后的 21 是滑動條自己的高度。
滑動條寬度是 wSlider = W - x2 - 10 ,高度固定為 hSlider = 21。

現在可以計算第一行的標簽控件矩形了(其實應該是包裹標簽的滾動區域矩形),標簽坐標為:
xLabel = 10;
yLabel = 10;
現在要計算標簽的寬度和高度,
寬度為 wLabel = W - 10 - 10;
高度為 hLabel = H - 10 - 21 - 10 - 23 - 10 - 10 。
高度計算里面第一個 10 是底部邊界間隙, 21 是水平滑動條高度,
第二個 10 是水平滑動條與按鈕的間隙,23 是按鈕的高度,
第三個 10 是按鈕與標簽控件的間隙,
第四個 10 是標簽距離頂部的間隙。

到這里按鈕的分布情況就確定了。這個界面只有 6 個控件而已,如果控件再多些,計算就會更復雜了。

當窗口大小改變時,我們需要重載主窗體基類的事件函數:

void QWidget::resizeEvent(QResizeEvent * event) 參數 event 是 QResizeEvent 類型,除了構造函數,這個 QResizeEvent 只有兩個自己的公有函數: const QSize & QResizeEvent::oldSize() const oldSize() 用于獲取窗體的舊尺寸,就是變化前的尺寸。 const QSize & QResizeEvent::size() const size() 用于獲取窗體當前的新尺寸,就是變化后的尺寸。 當然,我們都是根據新尺寸調整里面各個控件的分布和尺寸。

【小技巧】重寫基類虛函數的方法

我們需要重載基類的 resizeEvent() 函數,我們可以手動在 MainWindow類的 .h 文件和 .cpp 里面,按照幫助文檔里給定的函數名和參數,手動添加代碼行進行重載。或者按照下面示范的操作,可以用右鍵菜單實現自動重載基類函數。
打開 MainWindow.h 頭文件,選中類名 MainWindow,右擊類名 MainWindow,然后也是在右鍵菜單選擇 “Refactor”

“Refactor” 第四個子菜單項是 “Insert Virtual Functions of Base Classes” ,就是重載基類虛函數的意思。
點擊重載基類虛函數的子菜單項,進入下面插入基類虛函數對話框:

該對話框最上面是樹形列表,列舉了所有基類可重載的虛函數,
然后有個復選框 “Hide reimplemented functions” ,是隱藏之前已經重載過的虛函數的意思。
接下來是 “Insertion options” 分組框,里面有一個組合框,用于設置插入虛函數的選項,
組合框里面有四項內容:
“Insert only declarations” ,只在類聲明里面插入一個虛函數聲明,不添加函數定義。
“Insert definitions inside class”,把函數定義直接放到類聲明里面,函數聲明直接省了,在類聲明里編寫新函數實體。
“Insert definitions outside class” ,把函數定義和聲明都放在頭文件里面,函數聲明放在類聲明里面,函數定義放在類聲明結束之后外面的代碼位置。
“Insert definitions in implementation file” ,函數聲明放到頭文件的類聲明里面,函數的實體定義放到對應的 .cpp 文件末尾的位置。第四種是最為推薦的用法。當然,如果類的 .h 名與 .cpp 文件簡短名不一樣,那么可能找不到實現文件。這種情況才會用第一選項,只添加聲明,回頭自己在實現文件補上函數定義。

組合框下面又是一個復選框 “Add keyword ‘virtual’ to function declearation” ,這個是建議勾選的,基類是虛函數,雖然能自動繼承虛函數特性,但明確加上 virtual 關鍵字其實更好,讓代碼意義更清晰,并且將來當前類的派生類也能重載該虛函數。

我們在最上面的樹形列表里面選中基類 QWidget 的 resizeEvent() 函數,
組合框里面選擇第四個 “Insert definitions in implementation file” ,
勾選插入關鍵字 virtual 的復選框,如下圖所示:

mainwindow.h內容如下:

#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;// QWidget interface protected:virtual void resizeEvent(QResizeEvent *event); }; #endif // MAINWINDOW_H

mainwindow.cpp內容如下:

#include "mainwindow.h" #include "ui_mainwindow.h"#include <QScrollArea> #include <QResizeEvent>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);//獲取標簽矩形QRect rcLabel = ui->label->geometry();QScrollArea *pSA = new QScrollArea(this);//將標簽填充到滾動區域中pSA->setWidget(ui->label);//設置關東區域占據矩形pSA->setGeometry(rcLabel);//設置最小尺寸 構造函數最后一句就是設置最小尺寸為 350*350this->setMinimumSize(350, 350); }MainWindow::~MainWindow() {delete ui; }void MainWindow::resizeEvent(QResizeEvent *event) {//獲取當前寬度、高度int W = event->size().width();int H = event->size().height();//先計算第二行四個按鈕的左上角坐標,按鈕尺寸固定為 75*23//第一個按鈕int x1 = 10; //左邊距 10int y1 = H - 10 - 21 - 10 - 23; // 10 都是間隔,21 是水平滑動條高度,23 是按鈕高度//第四個按鈕int x4 = W - 10 - 75; //10 是右邊距,75 是按鈕寬度int y4 = y1; //與第一個按鈕同一水平線//計算四個按鈕的三個間隙總大小int nTriGap = W - 10 - 10 - 75 * 4;//計算單個間隙int nGap = nTriGap / 3 ;//計算第二個按鈕坐標int x2 = x1 + 75 + nGap;int y2 = y1;//計算第三個按鈕左邊int x3 = x4 - 75 - nGap;int y3 = y1;//設置四個按鈕的矩形ui->pushButton->setGeometry(x1, y1, 75, 23);ui->pushButton_2->setGeometry(x2, y2, 75, 23);ui->pushButton_3->setGeometry(x3, y3, 75, 23);ui->pushButton_4->setGeometry(x4, y4, 75, 23);//計算第三行水平滑動條的坐標和尺寸int xSlider = x2;int ySlider = H - 10 - 21;int wSlider = W - x2 - 10;int hSlider = 21;//設置水平滑動條的矩形ui->horizontalSlider->setGeometry(xSlider, ySlider, wSlider, hSlider);//計算包裹標簽的滾動區域占用的矩形int xLabel = 10;int yLabel = 10;int wLabel = W - 10 - 10;int hLabel = H - 10 - 21 - 10 - 23 - 10 - 10;//設置包裹標簽的滾動區域矩形QScrollArea *pSA = this->findChild<QScrollArea *>(); //查找子對象if( pSA != NULL) //如果 pSA 不為 NULL 才能設置矩形{pSA->setGeometry(xLabel, yLabel, wLabel, hLabel);} }

關于標簽控件的代碼,因為我們在構造函數里用滾動區域 pSA 替代了標簽占用的矩形,
把標簽對象塞到滾動區域內部了,現在標簽對象自己的矩形我們不用管。
需要把計算出來的 xLabel 、yLabel、wLabel、hLabel 設置給主界面里的滾動區域對象。
注意,在構造函數里的 pSA 是臨時指針,我們沒有存儲它,其實應該把滾動區域對象的指針存為成員變量的,但我們沒有存。

沒有存成員變量,也有不存的搞法。Qt 類庫的總基類 QObject 支持實時查詢當前父對象包含的子對象,就是 findChild 模板函數:

T QObject::?findChild(const QString & name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const 這是一個模板函數,需要把被查詢的指針類型用尖括號包裹,放在函數名與小括號之間,比如: QScrollArea *pSA = this->findChild<QScrollArea *>(); //查找子對象 QScrollArea * 就是要查找的子對象指針類型,我們這里因為主界面窗體里面只有一個 QScrollArea * 對象指針,不需要參數就能查找到。 ?findChild() 第一個參數 name 是對象名稱,就是 setObjectName() 函數設置的名字。 第二個參數 options 是查找選項,默認的 Qt::FindChildrenRecursively 是一直遞歸查找所有的子對象以及子對象的子對象。 如果調用下面這句,就是僅僅查找直屬的子對象,不遞歸查找: QPushButton *button = parentWidget->findChild("button1", Qt::FindDirectChildOnly); 這一句就是查找按壓按鈕的指針,對象名為 "button1",Qt::FindDirectChildOnly 就是僅僅搜尋直屬子對象,不遞歸。如果查找不到指定的對象指針,那么 findChild() 函數會返回 NULL 空指針。 因此在代碼里需要判斷該函數的返回值是否為空再進行操作,例如://設置包裹標簽的滾動區域矩形QScrollArea *pSA = this->findChild<QScrollArea *>(); //查找子對象if( pSA != NULL) //如果 pSA 不為 NULL 才能設置矩形{pSA->setGeometry(xLabel, yLabel, wLabel, hLabel);}

程序執行結果

05. 計算文本顯示寬度

在自己規劃和計算界面控件分布的時候,可能遇上控件寬度是根據文本長度變化的情況。接下來我們根據按鈕控件自身的字體設置,計算某一段按鈕文本的顯示寬度,根據這個文 本顯示寬度來確定按鈕的動態寬度。

Qt 控件的基類 QWidget 原本有 能讓控件根據顯示內容自動調整大小 的函數:

void QWidget::adjustSize()

我們例子沒有用這個函數,而是自己手動計算并調整控件寬度的。無論是用 adjustSize() 函數還是自己手動計算,都能達到類似的效果。

相關函數

QWidget 類有獲取當前字體的函數: const QFont & QWidget::font() const 另外還有獲取 QFontMetrics 對象的函數,QFontMetrics 對象專門用于根據文本字符串計算文本寬度: QFontMetrics QWidget::?fontMetrics() const 我們獲取控件的 QFontMetrics 字體度量對象,然后就可以用該對象的函數來確定某一段文本的顯示寬度: int QFontMetrics::?width(const QString & text, int len = -1) const int QFontMetrics::?width(QChar ch) const 第一個 width() 函數中,text 就是需要計算的文本字符串,len 是指定字符串片段的字符個數,如果 len 為默認的 -1,說明計算全部字符串的顯示寬度。第二個 width() 函數負責計算單個字符的顯示寬度。 QFontMetrics 通常只是計算單行字符串的寬度和高度,字體度量的單行高度是用如下函數獲取: int QFontMetrics::?height() const 高度函數里沒有參數,這個字體高度是最大高度,以 xbg 三個字母為例,b 上凸,g 下凹,字體高度是從最上面的水平線計算到最下面水平線,這是一個最大高度。QFontMetrics 有一個 size() 函數可以計算多行文本的總寬度和總高度,返回 QSize 對象表示尺寸: QSize QFontMetrics::?size(int flags, const QString & text, int tabStops = 0, int * tabArray = 0) const 第一個參數 flags 可以是如下幾個標志位進行位或 | 后的數值: Qt::TextSingleLine 代表忽略換行符,把所有文本作為一行來計算。 Qt::TextExpandTabs 代表展開 '\t' 制表符,用空白區域填充制表符。 Qt::TextShowMnemonic 是指將 "&x" 替換為 x 來計算,這在伙伴快捷鍵里常用到。其他標志位見 enum Qt::?TextFlag 枚舉常量列表。 如果不設置任何標志位,就把 flags 設置為 0 ,這時候換行符 '\n' 會起作用,自動計算多行文本占用的尺寸。 QFontMetrics::?size() 函數第二個參數 text 就是要計算的文本字符串。QFontMetrics::?size() 函數第三個參數和第四個參數只在 Qt::TextExpandTabs 標志位啟用的時候有作用,使用方法比較怪異: 如果第四個 tabArray 不為空數組,這個數組指定每個制表符的像素點位置,tabArray 數組最后一個數值必須是 0,作為結束標志。 如果第四個 tabArray 為空指針,那么再看第三個 tabStops ,tabStops 如果非 0 ,就是指每個制表符占據的空白區域像素寬度; 如果 tabStops 和 tabArray 都沒設置,都是默認的 0,那么交給 QFontMetrics 用默認策略擴展制表符。 QFontMetrics::?size() 函數最簡單的用法舉例: QFontMetrics fm = pWidget->fontMetrics(); QSize szMulti = fm.size(0, "ABC\n123\nXYZ"); 上面第二句就是計算三行文本的總尺寸。

創建新的項目,設計UI如下圖所示

程序主要功能就是在 lineEdit 里面編輯文本時,動態按鈕根據該文本計算顯示寬度,動態調整自己的寬度;
而固定按鈕的尺寸是不變的,它會根據 lineEdit 文本內容自動計算能夠顯示的文本片段,如果能全部顯示出來就全部顯示,如果不能全部顯示,它就顯示前面一小段文本和 “…” ,比如文本字符串 “哈哈哈哈哈哈哈哈哈” 太長了,固定按鈕就顯示 “哈哈哈哈…” 。
另外這里會為控件設置工具提示信息,隨后會看到設置工具提示信息的代碼。

現在這個計算顯示寬度的例子,它的三行控件在垂直方向是均勻分布的,并且控件高度全部固定為 24 。
這樣如圖所示,三行控件的中軸線把主窗體分割成均勻的四塊區域,根據圖上規劃就很容易計算各個控件的分布情況了。
第一行的單行編輯控件寬度是根據窗口大小變化的,
第二行的按鈕控件是根據單行編輯器里的文本動態調整寬度。
只有第三行的按鈕控件,尺寸是固定的,我們根據第三行控件可以定出窗口的最小尺寸:
最小寬度是 10+54+10+75+10 ,其中 10 都是間隙和邊距,54 是標簽的固定寬度,75 是第三行按鈕的寬度。
最小高度是 243 + 104 ,24是每行控件高度,10 是間隙和邊距。
窗口大致的規劃就是這樣,詳細的計算放在后面代碼里。

為單行編輯控件添加 textEdited(QString) 信號對應的槽函數:

打開 .h 頭文件,添加重載窗口調整大小的函數 resizeEvent() ,這個操作也是按照前面添加 resizeEvent() 的過程,一樣地添加就行了,即選中并右擊類名,從右鍵菜單選擇
“Refactor” --> “Insert Virtual Functions of Base Classes” ,
然后從彈出的對話框添加窗口大小調整的事件函數:

mainwindow.h內容如下:

#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_lineEdit_textEdited(const QString &arg1);private:Ui::MainWindow *ui;// QWidget interface protected:virtual void resizeEvent(QResizeEvent *event); }; #endif // MAINWINDOW_H

新包含的 是窗口大小調整的事件, 是字體度量類,用于計算文本顯示寬度。
在構造函數里面增加了一句 setMinimumSize() 函數調用,把我們之前規劃的最小尺寸設置給主窗體,沒有限定最大尺寸。

接著是槽函數 on_lineEdit_textEdited() 的內容,這個槽函數代碼比較多,我們分兩塊來講解,第一塊代碼是關于 “動態按鈕” 尺寸計算和設置的:

void MainWindow::on_lineEdit_textEdited(const QString &arg1) {//獲取按鈕文本字體度量對象QFontMetrics fm = ui->pushButton->fontMetrics();//計算按鈕文本的顯示寬度int nTextWidth = fm.width(arg1);//獲取動態按鈕原先的尺寸QSize szButton1 = ui->pushButton->size();//修改寬度 10表示文本兩端留的空隙szButton1.setWidth(nTextWidth + 10);//重置大小ui->pushButton->resize(szButton1);//設置動態按鈕文本ui->pushButton->setText(arg1);//設置動態按鈕工具提示信息ui->pushButton->setToolTip(arg1);}

代碼解析

槽函數開始處獲取了按鈕的字體度量對象 fm;
然后計算文本字符串 arg1 的顯示寬度 nTextWidth ;
接著獲取按鈕原來尺寸 szButtonDynamic ;
動態按鈕新尺寸不要修改高度,我們將 szButtonDynamic 的寬度設置為 nTextWidth + 10,這個 10 是為文本顯示左右兩端各留了 5 個像素的空白,這樣按鈕文字看起來不會擠到邊框;
得到新尺寸 szButtonDynamic ,用 resize() 函數把這個新尺寸設置給動態按鈕;
然后設置動態按鈕的文本為 arg1;
設置動態按鈕的工具提示信息也為 arg1。

圖形界面的控件都可以設置工具提示信息 setToolTip(QString),當鼠標懸停在控件上的時候,過一陣子會自動顯示一行提示信息,就是表示該控件附加提示信息的,一般用于展示控件的功能作 用等。

以下代碼是關于固定按鈕文本設置的:

//固定按鈕尺寸為75 * 24 可顯示文本的寬度為75 - 10 = 65if (nTextWidth <= 65){//文字全部可以顯示ui->pushButton_2->setText(arg1);}else{//文本不可以全部顯示QString strPart;QString strDot = "...";//字符串長度int nStrLen = arg1.length();//新的文本顯示長度int nNewTextWidth = 0;for (int i = 0; i < nStrLen; i++){strPart += arg1[i];nNewTextWidth = fm.width(strPart + strDot);if (nNewTextWidth >= 65){break;}}//為固定按鈕設置文本ui->pushButton_2->setText(strPart + strDot);}//設置固定按鈕的工具提示信息ui->pushButton_2->setToolTip(arg1);

因為固定按鈕的尺寸是 75*24,為文本兩端要留 10 像素間隙,文本能占有的寬度就是 75 - 10 == 65。
這是判斷 arg1 文本顯示寬度 nTextWidth 是否不超過 65,如果不超過就直接把 arg1 文本設置給固定按鈕,不需要額外計算。

如果 nTextWidth 超過了 65,那么需要進行計算:
strPart 是我們最終需要從 arg1 里面截取的前面一部分字符串;
strDot 是省略號 “…”;
nStrLen 是字符串的總長度,也就是所有字符計數;
nNewTextWidth 用于計算 (strPart + strDot) 字符串總長度。
然后進入 for 循環,該循環每次為 strPart 添加一個字符,計算新的 (strPart + strDot) 總的顯示寬度 nNewTextWidth ,
如果新的 nNewTextWidth 剛剛好超了可顯示寬度 65,那么就退出循環。

經過該循環處理后,(strPart + strDot) 就是我們在固定按鈕里需要顯示的文本,
我們把 (strPart + strDot) 設置給固定按鈕。

槽函數最后一句是為固定按鈕設置工具提示信息 arg1 ,這樣即使固定按鈕自己顯示不了全部的文本,它工具提示信息顯示的是完整的文本 arg1 。

槽函數就是上面那些,槽函數功能主要是設置兩個按鈕的文本、工具提示信息,并且根據文本內容實時調整動態按鈕的尺寸,如果文本過長,固定按鈕只會顯示文本前面的片 段和 “…”。

最后部分是 resizeEvent() 虛函數的代碼,根據窗口大小調整各個控件的分布情況。我們有三行控件,下面就針對每一行的控件設置代碼來講解,首先是第一行標簽和單行編輯控件的:

void MainWindow::resizeEvent(QResizeEvent *event) {//獲取當前寬度、高度int W = event->size().width();int H = event->size().height();//計算第一行控件分布,標簽尺寸都是 54*24//標簽1int xLabel1 = 10;int yLabel1 = H/4 - 12;//標簽尺寸不變,移動坐標即可ui->label->move(xLabel1, yLabel1);//單行編輯控件int xLineEdit = xLabel1 + 54 + 10; //54是標簽寬度,10是間隙int yLineEdit = yLabel1;int wLineEdit = W - xLineEdit - 10; // 10 是右邊距int hLineEdit = 24;//設置矩形ui->lineEdit->setGeometry(xLineEdit, yLineEdit, wLineEdit, hLineEdit);}

W 是主窗體寬度,H 是主窗口寬度。
xLabel1 是第一行標簽的左邊距,固定為 10;
yLabel1 = H/4 - 12,其中 H/4 是第一行控件的中軸線,12 是控件上半截的高度。
標簽控件尺寸固定,只需要用 move() 函數把坐標移動到 (xLabel1, yLabel1) 就行了。

單行編輯控件的 xLineEdit = xLabel1 + 54 + 10,是標簽控件右邊間隔 10 的位置,54 是標簽寬度;
yLineEdit 與標簽控件 yLabel1 一樣的垂直位置;
wLineEdit 是單行編輯控件寬度,除去單行編輯控件左邊區域 xLineEdit 和右邊距 10,剩下的就是自己的寬度;
單行編輯控件高度固定 hLineEdit 為 24 。
然后設置單行編輯控件占據的矩形,就完成第一行控件的分布了。

//計算第二行控件分布,標簽控件 54*24//標簽2int xLabel2 = 10;int yLabel2 = 2*H/4 - 12;//移動標簽ui->label_2->move(xLabel2, yLabel2);//動態按鈕int xButtonDynamic = xLabel2 + 54 + 10;int yButtonDynamic = yLabel2;//移動即可,尺寸由上面槽函數 on_lineEdit_textEdited 處理ui->pushButton->move(xButtonDynamic, yButtonDynamic);

標簽控件 xLabel2 = 10,距離左邊界 10 像素;
yLabel2 = 2H/4 - 12 ,第二行中軸線的垂直坐標是 2H/4,12 是控件上半截的高度。
標簽控件尺寸是固定的,將坐標移動到 (xLabel2, yLabel2) 就行了。

動態按鈕的 xButtonDynamic = xLabel2 + 54 + 10,是距離標簽右邊間隔 10 的位置,54 是標簽的寬度。
yButtonDynamic 與標簽垂直位置 yLabel2 一樣。
這個動態按鈕的尺寸由前面槽函數調整,這里只需要把坐標移動到 (xButtonDynamic, yButtonDynamic) 即可。

//計算第三行控件分布,標簽控件 54*24//標簽3int xLabel3 = 10;int yLabel3 = 3*H/4 - 12;//移動標簽ui->label_3->move(xLabel3, yLabel3);//固定按鈕int xButtonFixed = xLabel3 + 54 + 10;int yButtonFixed = yLabel3;//移動即可,尺寸固定ui->pushButton_2->move(xButtonFixed, yButtonFixed);

標簽控件 xLabel3 = 10,也是距離左邊界 10 像素。
yLabel3 = 3H/4 - 12,其中 3H/4 是第三行控件的中軸線垂直位置,12 是控件上半部分高度。
標簽大小不需要調整,只需要移動到坐標 (xLabel3, yLabel3) 。

固定按鈕的 xButtonFixed = xLabel3 + 54 + 10,是位于標簽控件右邊間隔 10 的位置,54 是標簽控件寬度。
yButtonFixed 與標簽的垂直坐標 yLabel3 一樣。
固定按鈕的尺寸不用調整,直接移動到坐標 (xButtonFixed, yButtonFixed) 就行了。

執行結果如下:

06. 附錄

6.1 Qt教程匯總
網址:https://dengjin.blog.csdn.net/article/details/115174639

6.2 源碼下載:

下載:

下載:

總結

以上是生活随笔為你收集整理的【Qt】Qt手动布局的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。