學習C++、QT---30(QT庫中如何自定義控件(自定義按鈕)講解)

每日一言

????????你比想象中更有韌性,那些看似艱難的日子,終將成為勛章。

自定義按鈕

????????我們要知道自定義控件就需要我們創建一個新的類加上繼承父類,但是我們還要注意一個點,就是如果我們是自己重頭開始造控件的話,那么我們就直接可以繼承QWidget就可以了,因為這個屬于是極致的定制開發,如果是只需要在QT已有的控件上添加QT官方在這個控件上沒有的功能的話就需要我們自己創建新的類之后還需要將原有的控件進行提升為這個我們創建的新類,提升成自己的類,那么我們寫的新控件就等于是在原有控件上的改變,變的擁有了更多功能,但是可以說又保存了90%的原有控件的功能,這個就是兩種不同的自定義控件的方法

好的那我們現在來自定義一個按鈕吧(實際上是自定義一個控件,看起來像按鈕一樣的功能)

就是我們這個說實話不叫自定義按鈕,應該是叫做自定義控件,只是看起來像一個按鈕,現在我來講講怎么搞,首先我們先創建一個C++的類叫做MyButton隨后繼承這個QWidget,那么就是意味著是全部是自己極致開發,全部自己干,所以我們需要重寫的事件有鼠標點擊事件、鼠標的進入事件

Widget::enterEvent

MyButton::enterEvent

這個兩個是不一樣的效果的,一個是在窗口的時候,鼠標進入到窗口就會觸發事件,一個是要在Mybutton這個控件上的時候才會觸發事件,

每一個控件都有自己的(鼠標、鍵盤)事件

好的現在我們想要我們的自定義按鈕是一個圖片的樣子我們怎么操作呢?

那么我們這邊就需要進行接收新的知識點了

QPixmap??這個類是專門用于畫圖的

這里有一個load這個函數,就是可以載入我們的資源文件的,值得注意的是我們去看這個函數的參數

漲知識啦

核心是理解?const QString &?作為函數參數的特性—— 它允許直接接收臨時對象(比如字符串字面量轉換的臨時 QString),而不需要顯式定義一個變量。我們一步步拆解:

一、const QString &?為什么能直接接收字符串字面量?

當你寫?pic.load(":/QTicon/open2.png")?時,發生了這幾步:

  1. 字符串字面量?":/QTicon/open2.png"?是?const char*?類型,Qt 會自動調用?QString?的構造函數,創建一個臨時的 QString 對象(這個對象在內存中短暫存在,沒有名字)。
  2. 函數參數?const QString &fileName?是常量引用,它可以直接綁定到這個臨時 QString 對象上(這是 C++ 標準允許的,const?引用的特殊權限)。

二、為什么不需要先用變量接收?

非 const 引用(如?QString &必須綁定到一個 “有名字的、已存在的變量”,不能綁定臨時對象。例如:

void?func(QString &s)?{}??// 非const引用參數func("hello");??// 報錯!不能綁定臨時對象

但?const?引用?被設計為可以綁定到:

    • 已存在的變量(如?QString path = "..."; load(path);
    • 臨時對象(如字符串字面量轉換的臨時 QString)
      這是 C++ 的語法規則,目的是方便使用(不需要顯式定義變量),同時保證安全性(const?確保不會修改這個臨時對象)。

三、const QString &?中 “引用” 的作用是什么?

引用的核心作用是?“避免不必要的拷貝,提高效率”

如果函數參數是?QString fileName(按值傳遞):
調用時會把傳遞的字符串(無論是變量還是臨時對象)完整拷貝一份到函數內部的?fileName?中。對于長字符串(比如路徑很長),拷貝會浪費內存和時間。

如果參數是?const QString &fileName(按 const 引用傳遞):
不會拷貝,fileName?只是一個 “別名”,直接指向傳遞進來的對象(可能是變量,也可能是臨時對象)。既節省了拷貝的開銷,又通過?const?保證不會意外修改這個對象。

四、總結你的代碼為什么可行?

pic.load(":/QTicon/open2.png")?的過程:

  1. 字符串字面量被轉換為臨時 QString 對象(存儲路徑)。
  2. const QString &fileName?綁定到這個臨時對象(不需要顯式變量)。
  3. 函數內部通過引用直接訪問這個臨時對象,避免拷貝,高效且安全。

簡單說:const?引用的特性就是?“既能直接用字面量 / 臨時對象,又不浪費內存”,所以不需要先定義一個 QString 變量~

那么我們的代碼怎么寫呢?

我們需要在類這邊寫QPixmap pic這個對象,還記得這個是什么操作嗎,這個就是我們的類的組合的操作,在類中創建其他類的對象,可以實現獲得其他類的屬性和方法,然后我們去這個cpp中調用他的load函數

我來一個一個講,這個MyButton的這個里面的??pic.load(":/QTicon/open.png");這個是在構造函數里面寫的嘛,說明這個就是我們設置的這個程序第一眼看到的樣子,我們畢竟是自定義按鈕嘛,這些初始化的設置肯定是在構造函數里面寫的

就是這個樣子,

其他的幾個事件也都是一樣的意思,這個圖片文件的話是我通過添加Qt Resources文件添加的就像我們給記事本的按鈕添加上圖片作為圖標一樣做的前期工作,需要將我們想要的圖片先放在資源文件里面

setFixedSize(pic.size());

這個是什么意思呢,這個就是設置我們的控件的尺寸,尺寸為pic.size()調用這個函數,就是表示我們設置這個按鈕的尺寸為這個圖片的尺寸

后面會發現沒有任何的結果啊,不顯示啊,這也是因為我們是繼承的QWidget這個是為了極致的開發的,什么都自己干,所以連很基礎的繪圖都沒有,因此我們也有一個繪圖事件,對于這個事件我們可以去QWidget這個類里面去尋找

我們會找到這個繪制事件,然后我們可以通過這個事件找到QPaint這個類

我們通過這個類創建一個對象,調用這個drawPixmap()這個函數,這個函數的話就是,可以將我們的圖片繪制出來,

void?MyButton::paintEvent(QPaintEvent?*event)

{

????QPainter?painter(this);

????painter.drawPixmap(rect(),pic);

}

會發現我們的painter(this)要加上這個才會正常運行,this的意思就是這個Mybutton這個控件,

我們也可以看這個案例,會發現這個用法painter(this)要這樣寫

目的是:作用:作為?QPainter?的構造參數時,它告訴?QPainter?在哪個控件上進行繪制

對于這個drawPixmap(),他需要一個矩形區域,還有一個就是QPixmap 的對象的引用,說實話有點像我們的之前的那個font對象的那個操作,那個ui->textEdit->setFont(font)

這樣的操作都是傳的是對象的引用,

好的說一下這個矩形

?rect()?作為目標矩形(控件的完整區域),讓圖片自適應控件大小:

painter.drawPixmap(rect(), pic); // 圖片填滿整個控件(可能拉伸)

最后一步就是我們需要在加載完這個圖片的時候需要手動更新一下update一下,這個是為什么呢?而且我之前那個設置字體的縮放的時候好像也不需要這樣啊?

因為:

  • 內置屬性(如字體):Qt 已處理自動更新,無需手動?update()
  • 自定義繪圖:必須手動調用?update()?來觸發重繪,否則界面不會更新。

這種設計體現了 Qt 的靈活性:內置控件負責基礎屬性的自動管理,而自定義繪圖則交給開發者控制,避免了不必要的性能開銷。

其實到最后如果我前面沒有講提升的問題的話,那么我們就需要進行提升

就是因為我們是繼承這個QWidget的,所以我們需要拉一個widget就好了

我提出一個問題??是不是就是我由于是繼承的QWidget那么就是意味著我需要的是極致的自己開發控件,所以也就是只能去拉一個widget出來,然后我去提升他

是的,你的理解非常準確!我用更簡潔的方式總結一下:

為什么必須拉一個?QWidget?并提升?

因為你繼承?QWidget?時,相當于從頭開始開發一個全新控件,而 Qt Designer 默認沒有你的控件。具體邏輯鏈:

繼承?QWidget?的本質
QWidget?是最基礎的控件類,幾乎什么都沒實現(沒有按鈕外觀、沒有點擊事件)。你繼承它,就像 “從零開始造一輛車”,所有功能都要自己寫。

“提升控件” 如何解決問題?

“提升” 操作的本質是:告訴 Qt Designer,把這個普通的?QWidget?當成我的?MyButton?來用

具體步驟的意義:
  1. 拖一個普通?QWidget?到界面上:這是因為 Qt Designer 沒有?MyButton?控件可選,只能用?widget?占位。就是因為我們是極致開發啊,記住我們這個是自己開發的按鈕,不是在QT已有的控件上的開發,另外的是我選擇繼承的是QWidget,就說明全部自己干,說明就是拖一個Widget就好了
  2. 右鍵 → 提升為?MyButton
    1. Qt Designer 會記錄這個操作,并在生成的代碼中使用?MyButton?而非?Widget
    2. 生成的代碼會自動包含?mybutton.h?頭文件。

最后完成以上所有的操作就可以實現啦

效果為:我鼠標移到上方的時候就是紫色,點擊的時候就是黑色,鼠標離開這個控件的時候就是藍色,一打開程序的時候也是藍色

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/89965.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/89965.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/89965.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【補充】Linux內核鏈表機制

專題文章:Linux內核鏈表與Pinctrl數據結構解析 目標: 深入解析Pinctrl子系統中,struct pinctrl如何通過內核鏈表,來組織和管理其多個struct pinctrl_state。 1. 問題背景:一個設備,多種引腳狀態 一個復雜的…

本地部署Dify、Docker重裝

需要先安裝一個Docker,Docker就像是一個容器,將部署Dify的空間與本地環境隔離,避免因為本地環境的一些問題導致BUG。也確保了環境的統一,不會出現在自己的電腦上能跑但是移植到別人電腦上就跑不通的情況。那么現在就開始先安裝Doc…

【每天一個知識點】非參聚類(Nonparametric Clustering)

ChatGPT 說:“非參聚類”(Nonparametric Clustering)是一類不預先設定聚類數目或數據分布形式的聚類方法。與傳統“參數聚類”(如高斯混合模型)不同,非參聚類在建模過程中不假設數據來自于已知分布數量的某…

人形機器人CMU-ASAP算法理解

一原文在第一階段,用重定位的人體運動數據在模擬中預訓練運動跟蹤策略。在第二階段,在現實世界中部署策略并收集現實世界數據來訓練一個增量(殘差)動作模型來補償動態不匹配。,ASAP 使用集成到模擬器中的增量動作模型對…

next.js刷新頁面時二級菜單展開狀態判斷

在 Next.js 中保持二級菜單刷新后展開狀態的解決方案 在 Next.js 應用中,當頁面刷新時保持二級菜單的展開狀態,可以通過以下幾種方法實現: 方法1:使用 URL 參數保存狀態(推薦) import { useRouter } from n…

網絡基礎DAY13-NAT技術

NAT技術internet接入方式:ADLS技術:能夠將不同設備的不同信號通過分離器進行打包之后再internet中傳輸,到另一端的分離器之后再進行分離。傳輸到不同的設備中去。常見光纖接入方式internet接入認證方式:PPPoE:先認證再…

HBuilderX中設置 DevEco Studio路徑,但是一直提示未安裝

前言: HBuilderX中設置 DevEco Studio路徑,但是一直提示未安裝。 報錯信息: 檢測到鴻蒙工具鏈,請在菜單“工具->設置->運行配置”中設置鴻蒙開發者工具路徑為 DevEco Studio 的安裝路徑,請參考 報錯原因…

什么是GNN?——聚合、更新與循環

在傳統的深度學習中,卷積神經網絡(CNN)擅長處理網格結構數據(如圖像),循環神經網絡(RNN)擅長處理序列數據(如文本)。但當數據以圖的形式存在時(如…

深入解析 Django REST Framework 的 APIView 核心方法

在 Python 3 中,Django 的 APIView 類是 Django REST Framework(DRF)中用于構建 API 視圖的核心基類。它提供了一個靈活的框架來處理 HTTP 請求,并通過一系列方法支持認證、權限檢查和請求限制等功能。self.perform_authenticatio…

神經網絡——卷積層

目錄 卷積層介紹 Conv2d 卷積動畫演示 卷積代碼演示 綜合代碼案例 卷積層介紹 卷積層是卷積神經網絡(CNN)的核心組件,它通過卷積運算提取輸入數據的特征。 基本原理 卷積層通過卷積核(過濾器)在輸入數據&…

神經網絡——線性層

在機器學習中,線性層(Linear Layer) 是一種基礎的神經網絡組件,也稱為全連接層(Fully Connected Layer) 或密集層(Dense Layer)。 其嚴格的數學定義為:對輸入數據執行線…

大模型高效適配:軟提示調優 Prompt Tuning

The Power of Scale for Parameter-Efficient Prompt Tuning ruatishi 軟提示向量 具體是什么 《The Power of Scale for Parameter-Efficient Prompt Tuning》中增加的部分是“軟提示(soft prompts)”,這是一種針對特定下游任務,添加到輸入文本中的可調參數序列。它與傳統…

https正向代理 GoProxy

背景: 在安全隔離的內網環境中,部署于內網的應用如需調用公網第三方接口(如支付、短信),可通過正向代理服務實現訪問。 GoProxy 下載: https://github.com/snail007/goproxy/releases 使用文檔&#xff…

Java IO流體系詳解:字節流、字符流與NIO/BIO對比及文件拷貝實踐

一、字節流與字符流:如何選擇? 1.1 核心區別特性字節流字符流處理單位字節(8位)字符(16位Unicode)適用場景二進制文件(圖片/視頻)文本文件(TXT/CSV)編碼處理需…

QT6 源,七章對話框與多窗體(5) 文件對話框 QFileDialog 篇二:源碼帶注釋

&#xff08;13&#xff09;本源代碼定義于頭文件 qfiledialog . h &#xff1a; #ifndef QFILEDIALOG_H #define QFILEDIALOG_H#include <QtWidgets/qtwidgetsglobal.h> #include <QtCore/qdir.h> #include <QtCore/qstring.h> #include <QtCore/qurl.h…

關于Ajax的學習筆記

Ajax概念&#xff1a;是一門使用了js語言&#xff0c;可以使用于Javaweb&#xff0c;實現前端代碼和后端代碼連結的的一種異步同步&#xff08;不需要等待服務器相應&#xff0c;就能夠發送第二次請求&#xff09;的一種技術&#xff0c;它主要用于網頁內容的局部刷新&#xff…

The Missing Semester of Your CS Education 學習筆記以及一些拓展知識(三)

文章目錄The Missing Semester of Your CS Education 學習筆記以及一些拓展知識Vim編輯器筆記部分程序員常用的編輯器Vim的模式Vim的普通模式Vim的插入模式Vim的可視模式Vim的替換模式Vim的命令行模式Vim的高級功能文本對象宏寄存器緩沖區標記代碼折疊Vim的常用配置Vim的常用插…

PyTorch常用的簡單數學運算

一、基礎算術運算1. 逐元素運算a torch.tensor([1, 2, 3]) b torch.tensor([4, 5, 6])# 加減乘除 a b # [5, 7, 9] a - b # [-3, -3, -3] a * b # [4, 10, 18] a / b # [0.25, 0.4, 0.5]# 冪運算、平方根 a ** 2 # [1, 4, 9] torch.sqrt(a) # [1.0, 1.414, 1.732]2. 標…

C++ Lambda 表達式詳解:從基礎到實戰

Lambda 表達式是 C11 引入的重要特性&#xff0c;它允許我們在代碼中定義匿名函數&#xff0c;極大地簡化了代碼編寫&#xff0c;尤其是在使用 STL 算法和多線程編程時。本文將詳細介紹 Lambda 表達式的語法、特性及實際應用場景。什么是 Lambda 表達式&#xff1f;Lambda 表達…

Spring Boot注解詳解

文章目錄前言1. 核心啟動注解SpringBootApplicationEnableAutoConfigurationSpringBootConfiguration2. 組件注解Component及其衍生注解ComponentServiceRepositoryControllerRestController3. 依賴注入注解AutowiredQualifierPrimary4. Web相關注解請求映射注解RequestMapping…