天天看點

Qt5 lambda表達式連接配接QTcpServer信号槽ProblemSolutionAppendix Qt Lambda表達式

Problem

當有多條語句調用而又不希望寫成一個單獨的子產品(函數或者方法)時,對于普通的方法可以寫成内聯形式,避免函數調用入棧、出棧等開銷,也或者可以定義一段宏,不過宏沒有類型檢查,也沒有作用對象的概念。而當這多條語句是在定義QObject::connect連接配接某信号的槽的實作邏輯時,除了lambda表達式,好像沒有别的更好方法了。

Solution

先上一段代碼,用一個簡單的Qt自帶的QTcpSocket和QTcpServer實作一個Tcp單機收發的功能。

頭檔案MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <iostream>
#include <cstdio>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <windows.h>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = );
    ~MainWindow();

private slots:
    void on_BtnTcpSndData_clicked();

private:
    Ui::MainWindow *ui;
    QTcpServer tcpServer;
    QTcpSocket socket;
};

#endif // MAINWINDOW_H
           

源檔案MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    connect(&tcpServer,&QTcpServer::newConnection,
        [&](){QTcpSocket* pSocket=tcpServer.nextPendingConnection();
        connect(pSocket,&QTcpSocket::readyRead,
                [=](){ui->textEditTcpRcv->append(QString::fromLocal8Bit(pSocket->readAll()));   });});
    tcpServer.listen(QHostAddress("127.0.0.1"),);
    Sleep();
    socket.connectToHost("127.0.0.1",);
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_BtnTcpSndData_clicked()
{
    socket.write(ui->textEditDataToSnd->toPlainText().toLocal8Bit().data());
}
           

注意下在pro檔案中對c++11、和network進行設定。pro檔案中添加如下2條語句。

QT       += network
CONFIG += c++11
           

如上代碼所示,直接在構造函數中即可實作所有的TcpSocket、TcpServer建立與連接配接工作,而且将Server端接收到資料的處理邏輯也寫進去了。所有的邏輯都在下面這條語句。

connect(&tcpServer,&QTcpServer::newConnection,
        [&](){QTcpSocket* pSocket=tcpServer.nextPendingConnection();
        connect(pSocket,&QTcpSocket::readyRead,
                [=](){ui->textEditTcpRcv->append(QString::fromLocal8Bit(pSocket->readAll()));   });});
           

這是一個嵌套的connect連接配接操作。首先,如果Server端有新的連接配接,進入第一個lambda表達式的處理邏輯,儲存目前連接配接的套接字,将目前套接字的準備好讀的信号連接配接到最終處理的也即第二個lambda表達式。第二個lambda表示式中将目前套接字讀取的内容顯示在螢幕上。

注意tcpServer.nextPendingConnection()傳回的指針是多變的,即第一次取出是指針,未有新連接配接,再調用些函數取出的是空指針。是以需要用一個自定義的變量來進行儲存。

Qt5 lambda表達式連接配接QTcpServer信号槽ProblemSolutionAppendix Qt Lambda表達式

———————————————————————————

Appendix Qt Lambda表達式

此介紹出處http://www.aichengxu.com/view/5170676

簡單來說,Lambda函數也就是一個函數,它的文法定義如下:

[capture](parameters)mutable->return-type{statement}
           

1.[capture]:捕捉清單。捕捉清單總是出現在Lambda函數的開始處。實際上,[]是Lambda引出符。編譯器根據該引出符判斷接下來的代碼是否是Lambda函數。捕捉清單能夠捕捉上下文中的變量以供Lambda函數使用;

2.(parameters):參數清單。與普通函數的參數清單一緻。如果不需要參數傳遞,則可以連同括号“()”一起省略;

3.mutable:mutable修飾符。預設情況下,Lambda函數總是一個const函數,mutable可以取消其常量性。在使用該修飾符時,參數清單不可省略(即使參數為空);

4.->return-type:傳回類型。用追蹤傳回類型形式聲明函數的傳回類型。我們可以在不需要傳回值的時候也可以連同符号”->”一起省略。此外,在傳回類型明确的情況下,也可以省略該部分,讓編譯器對傳回類型進行推導;

5.{statement}:函數體。内容與普通函數一樣,不過除了可以使用參數之外,還可以使用所有捕獲的變量。

與普通函數最大的差別是,除了可以使用參數以外,Lambda函數還可以通過捕獲清單通路一些上下文中的資料。具體地,捕捉清單描述了上下文中哪些資料可以被Lambda使用,以及使用方式(以值傳遞的方式或引用傳遞的方式)。文法上,在“[]”包括起來的是捕捉清單,捕捉清單由多個捕捉項組成,并以逗号分隔。捕捉清單有以下幾種形式:

1.[var]表示值傳遞方式捕捉變量var;

2.[=]表示值傳遞方式捕捉所有父作用域的變量(包括this);

3.[&var]表示引用傳遞捕捉變量var;

4.[&]表示引用傳遞方式捕捉所有父作用域的變量(包括this);

5.[this]表示值傳遞方式捕捉目前的this指針。

上面提到了一個父作用域,也就是包含Lambda函數的語句塊,說通俗點就是包含Lambda的“{}”代碼塊。上面的捕捉清單還可以進行組合,例如:

1.[=,&a,&b]表示以引用傳遞的方式捕捉變量a和b,以值傳遞方式捕捉其它所有變量;

2.[&,a,this]表示以值傳遞的方式捕捉變量a和this,引用傳遞方式捕捉其它所有變量。

不過值得注意的是,捕捉清單不允許變量重複傳遞。

——————————————————————–保持成長! :)

繼續閱讀