在 Qt5 中建立一個 HTTP 介面以返回螢幕截圖

槑孒發表於2024-09-09

在 Qt5 中建立一個 HTTP 介面以返回 MainWindow 的螢幕截圖

在 Qt5 中,可以透過使用 QTcpServerQTcpSocket 來建立一個簡單的 HTTP 伺服器。透過這種方式,我們可以實現一個 HTTP 介面,當訪問該介面時,會返回當前 MainWindow 視窗的螢幕截圖。以下是實現這一功能的詳細步驟與相關知識點整理。

1. 準備工作

在開始編寫程式碼之前,確保你的專案已經包含了以下模組:

  • core
  • gui
  • network

在你的 .pro 檔案中新增如下配置:

QT += core gui network

2. 包含必要的標頭檔案

mainwindow.cpp 檔案中,需要包含以下標頭檔案:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QScreen>
#include <QGuiApplication>
#include <QBuffer>

這些標頭檔案用於處理網路通訊 (QTcpServerQTcpSocket),以及螢幕截圖和影像處理 (QScreenQGuiApplicationQBuffer)。

3. 建立 HTTP 伺服器

首先,我們在 MainWindow 建構函式中建立並啟動一個 QTcpServer

QTcpServer* server = new QTcpServer(this);

connect(server, &QTcpServer::newConnection, this, &MainWindow::handleNewConnection);

if (!server->listen(QHostAddress::Any, 8080)) {
    qDebug() << "Server could not start!";
} else {
    qDebug() << "Server started!";
}
  • QTcpServer 物件監聽所有網路介面 (QHostAddress::Any) 的 8080 埠。
  • 如果伺服器啟動成功,會在控制檯輸出 "Server started!",否則輸出 "Server could not start!"。

4. 處理新連線

當有新的連線時,會觸發 newConnection 訊號,並呼叫 handleNewConnection 函式處理新連線:

void MainWindow::handleNewConnection() {
    QTcpSocket* socket = server->nextPendingConnection();

    connect(socket, &QTcpSocket::readyRead, this, [this, socket]() {
        QByteArray request = socket->readAll();
        if (request.startsWith("GET /screenshot")) {
            QByteArray response = handleScreenshotRequest();
            socket->write(response);
        }
        socket->disconnectFromHost();
    });

    connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
}
  • nextPendingConnection 返回一個指向新連線的 QTcpSocket 指標。
  • 使用 readyRead 訊號讀取客戶端請求,如果請求以 "GET /screenshot" 開頭,則呼叫 handleScreenshotRequest 來處理螢幕截圖請求。
  • 在請求處理完成後,斷開與客戶端的連線並釋放資源。

5. 處理螢幕截圖請求

handleScreenshotRequest 函式用於獲取 MainWindow 的螢幕截圖並將其作為 HTTP 響應返回:

QByteArray MainWindow::handleScreenshotRequest() {
    QScreen *screen = QGuiApplication::primaryScreen();
    if (!screen)
        return QByteArray();

    QRect rect = this->geometry();
    QPixmap pixmap = screen->grabWindow(this->winId(), rect.x(), rect.y(), rect.width(), rect.height());

    QByteArray byteArray;
    QBuffer buffer(&byteArray);
    buffer.open(QIODevice::WriteOnly);
    pixmap.save(&buffer, "PNG");
    buffer.close();

    QByteArray response;
    response.append("HTTP/1.1 200 OK\r\n");
    response.append("Content-Type: image/png\r\n");
    response.append("Content-Length: " + QByteArray::number(byteArray.size()) + "\r\n");
    response.append("\r\n");
    response.append(byteArray);

    return response;
}
  • QGuiApplication::primaryScreen() 獲取當前主螢幕。
  • 使用 QScreen::grabWindow() 獲取 MainWindow 視窗的截圖。
  • 使用 QBufferQPixmap 儲存為 PNG 格式的位元組陣列。
  • 構造一個簡單的 HTTP 響應,其中包含螢幕截圖的內容。

6. 處理編譯錯誤

如果在編譯時遇到 member access into incomplete type 'QScreen' 錯誤,通常是因為缺少對 QScreen 類的標頭檔案引用。確保在 mainwindow.cpp 檔案頂部包含 #include <QScreen>#include <QGuiApplication>

7. 完整程式碼示例

以下是完整的 mainwindow.cpp 檔案示例:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QScreen>
#include <QGuiApplication>
#include <QBuffer>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QTcpServer* server = new QTcpServer(this);

    connect(server, &QTcpServer::newConnection, this, &MainWindow::handleNewConnection);

    if (!server->listen(QHostAddress::Any, 8080)) {
        qDebug() << "Server could not start!";
    } else {
        qDebug() << "Server started!";
    }
}

void MainWindow::handleNewConnection() {
    QTcpSocket* socket = server->nextPendingConnection();

    connect(socket, &QTcpSocket::readyRead, this, [this, socket]() {
        QByteArray request = socket->readAll();
        if (request.startsWith("GET /screenshot")) {
            QByteArray response = handleScreenshotRequest();
            socket->write(response);
        }
        socket->disconnectFromHost();
    });

    connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
}

QByteArray MainWindow::handleScreenshotRequest() {
    QScreen *screen = QGuiApplication::primaryScreen();
    if (!screen)
        return QByteArray();

    QRect rect = this->geometry();
    QPixmap pixmap = screen->grabWindow(this->winId(), rect.x(), rect.y(), rect.width(), rect.height());

    QByteArray byteArray;
    QBuffer buffer(&byteArray);
    buffer.open(QIODevice::WriteOnly);
    pixmap.save(&buffer, "PNG");
    buffer.close();

    QByteArray response;
    response.append("HTTP/1.1 200 OK\r\n");
    response.append("Content-Type: image/png\r\n");
    response.append("Content-Length: " + QByteArray::number(byteArray.size()) + "\r\n");
    response.append("\r\n");
    response.append(byteArray);

    return response;
}

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

8. 總結

透過上述步驟,您可以在 Qt5 中實現一個簡單的 HTTP 伺服器,用於返回 MainWindow 視窗的螢幕截圖。這個示例展示瞭如何結合使用 QTcpServerQScreenQPixmap 等類,以及如何處理網路通訊和螢幕截圖功能。

相關文章