漫談程序員(十八)淺談谷歌用戶體驗設計準則
999
2025-04-01
首先給大家推薦一個學習C語言/C++ 的github,分享C語言/C入門、學習路線、電子書籍推薦與下載、視頻推薦、小項目、干貨文章、筆試面試、C語言/C++ 規范、開源項目等。
地址:C語言/C++學習平臺
信號槽是 Qt 框架引以為豪的機制之一。所謂信號槽,實際就是觀察者模式。當某個事件發生之后,比如,按鈕檢測到自己被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,類似廣播。如果有對象對這個信號感興趣,它就會使用連接(connect)函數,意思是,將想要處理的信號和自己的一個函數(稱為槽(slot))綁定來處理這個信號。也就是說,當信號發出時,被連接的槽函數會自動被回調。這就類似觀察者模式:當發生了感興趣的事件,某一個操作就會被自動觸發。
1.1 系統自帶的信號和槽
下面我們完成一個小功能,上面我們已經學習了按鈕的創建,但是還沒有體現出按鈕的功能,按鈕最大的功能也就是點擊后觸發一些事情,比如我們點擊按鈕,就把當前的窗口給關閉掉,那么在Qt中,這樣的功能如何實現呢?
其實無法兩行代碼就可以搞定了,我們看下面的代碼
QPushButton * quitBtn = new QPushButton("關閉窗口",this);
connect(quitBtn,&QPushButton::clicked,this,&MyWidget::close);
第一行是創建一個關閉按鈕,這個之前已經學過,第二行就是核心了,也就是信號槽的使用方式
connect()函數最常用的一般形式:
connect(sender, signal, receiver, slot);
參數解釋:
sender:發出信號的對象
signal:發送對象發出的信號
receiver:接收信號的對象
slot:接收對象在接收到信號之后所需要調用的函數(槽函數)
那么系統自帶的信號和槽通常如何查找呢,這個就需要利用幫助文檔了,在幫助文檔中比如我們上面的按鈕的點擊信號,在幫助文檔中輸入QPushButton,首先我們可以在Contents中尋找關鍵字 signals,信號的意思,但是我們發現并沒有找到,這時候我們應該想到也許這個信號的被父類繼承下來的,因此我們去他的父類QAbstractButton中就可以找到該關鍵字,點擊signals索引到系統自帶的信號有如下幾個
這里的clicked就是我們要找到,槽函數的尋找方式和信號一樣,只不過他的關鍵字是slot。
1.2 自定義信號和槽
使用connect()可以讓我們連接系統提供的信號和槽。但是,Qt 的信號槽機制并不僅僅是使用系統提供的那部分,還會允許我們自己設計自己的信號和槽。
下面我們看看使用 Qt 的信號槽:
首先定義一個學生類和老師類:
老師類中聲明信號 餓了 hungry
signals:
void hungury();
學生類中聲明槽?? 請客 treat
public slots:
void treat();
在窗口中聲明一個公共方法下課,這個方法的調用會觸發老師餓了這個信號,而響應槽函數學生請客
void MyWidget::ClassIsOver()
{
//發送信號
emit teacher->hungury();
}
學生響應了槽函數,并且打印信息
//自定義槽函數 實現
void Student::eat()
{
qDebug() << "該吃飯了!";
}
在窗口中連接信號槽
teacher = new Teacher(this);
student = new Student(this);
connect(teacher,&Teacher::hungury,student,&Student::treat);
并且調用下課函數,測試打印出 “該吃飯了”
自定義的信號 hungry帶參數,需要提供重載的自定義信號和 自定義槽
void hungury(QString name);? 自定義信號
void treat(QString name );??? 自定義槽
但是由于有兩個重名的自定義信號和自定義的槽,直接連接會報錯,所以需要利用函數指針來指向函數地址, 然后在做連接
void (Teacher:: * teacherSingal)(QString) = &Teacher::hungury;
void (Student:: * studentSlot)(QString) = &Student::treat;
connect(teacher,teacherSingal,student,studentSlot);
自定義信號槽需要注意的事項:
發送者和接收者都需要是QObject的子類(當然,槽函數是全局函數、Lambda 表達式等無需接收者的時候除外);
信號和槽函數返回值是 void
信號只需要聲明,不需要實現
槽函數需要聲明也需要實現
槽函數是普通的成員函數,作為成員函數,會受到 public、private、protected 的影響;
使用 emit 在恰當的位置發送信號;
使用connect()函數連接信號和槽。
任何成員函數、static 函數、全局函數和 Lambda 表達式都可以作為槽函數
信號槽要求信號和槽的參數一致,所謂一致,是參數類型一致。
如果信號和槽的參數不一致,允許的情況是,槽函數的參數可以比信號的少,即便如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是因為,你可以在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少)。
1.3信號槽的拓展
一個信號可以和多個槽相連
如果是這種情況,這些槽會一個接一個的被調用,但是它們的調用順序是不確定的。
多個信號可以連接到一個槽
只要任意一個信號發出,這個槽就會被調用。
一個信號可以連接到另外的一個信號
當第一個信號發出時,第二個信號被發出。除此之外,這種信號-信號的形式和信號-槽的形式沒有什么區別。
槽可以被取消鏈接
這種情況并不經常出現,因為當一個對象delete之后,Qt自動取消所有連接到這個對象上面的槽。
信號槽可以斷開
利用disconnect關鍵字是可以斷開信號槽的
使用Lambda 表達式
在使用 Qt 5 的時候,能夠支持 Qt 5 的編譯器都是支持 Lambda 表達式的。
在連接信號和槽的時候,槽函數可以使用Lambda表達式的方式進行處理。后面我們會詳細介紹什么是Lambda表達式
1.4 Qt4版本的信號槽寫法
connect(zt,SIGNAL(hungry(QString)),st,SLOT(treat(QString)));
這里使用了SIGNAL和SLOT這兩個宏,將兩個函數名轉換成了字符串。注意到connect()函數的 signal 和 slot 都是接受字符串,一旦出現連接不成功的情況,Qt4是沒有編譯錯誤的(因為一切都是字符串,編譯期是不檢查字符串是否匹配),而是在運行時給出錯誤。這無疑會增加程序的不穩定性。
Qt5在語法上完全兼容Qt4,而反之是不可以的。
1.5 Lambda表達式
C++11中的Lambda表達式用于定義并創建匿名的函數對象,以簡化編程工作。首先看一下Lambda表達式的基本構成:
[capture](parameters) mutable ->return-type
{
statement
}
[函數對象參數](操作符重載函數參數)mutable ->返回值{函數體}
① 函數對象參數;
[],標識一個Lambda的開始,這部分必須存在,不能省略。函數對象參數是傳遞給編譯器自動生成的函數對象類的構造函數的。函數對象參數只能使用那些到定義Lambda為止時Lambda所在作用范圍內可見的局部變量(包括Lambda所在類的this)。函數對象參數有以下形式:
空。沒有使用任何函數對象參數。
=。函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是值傳遞方式(相當于編譯器自動為我們按值傳遞了所有局部變量)。
&。函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是引用傳遞方式(相當于編譯器自動為我們按引用傳遞了所有局部變量)。
this。函數體內可以使用Lambda所在類中的成員變量。
a。將a按值進行傳遞。按值進行傳遞時,函數體內不能修改傳遞進來的a的拷貝,因為默認情況下函數是const的。要修改傳遞進來的a的拷貝,可以添加mutable修飾符。
&a。將a按引用進行傳遞。
a, &b。將a按值進行傳遞,b按引用進行傳遞。
=,&a, &b。除a和b按引用進行傳遞外,其他參數都按值進行傳遞。
&, a, b。除a和b按值進行傳遞外,其他參數都按引用進行傳遞。
② 操作符重載函數參數;
標識重載的()操作符的參數,沒有參數時,這部分可以省略。參數可以通過按值(如:(a,b))和按引用(如:(&a,&b))兩種方式進行傳遞。
③ 可修改標示符;
mutable聲明,這部分可以省略。按值傳遞函數對象參數時,加上mutable修飾符后,可以修改按值傳遞進來的拷貝(注意是能修改拷貝,而不是值本身)。
QPushButton * myBtn = new QPushButton (this);
QPushButton * myBtn2 = new QPushButton (this);
myBtn2->move(100,100);
int m = 10;
connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() < connect(myBtn2,&QPushButton::clicked,this,[=] () { qDebug() << m; }); qDebug() << m; ④ 函數返回值; ->返回值類型,標識函數返回值的類型,當返回值為void,或者函數體中只有一處return的地方(此時編譯器可以自動推斷出返回值類型)時,這部分可以省略。 ⑤ 是函數體; {},標識函數的實現,這部分不能省略,但函數體可以為空。 Qt
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。