要在C++中实现WebSocket功能并暴露给QML,您需要创建一个C++类来处理WebSocket连接,然后将其注册为QML类型。以下是完整的实现步骤:
1、创建C++ WebSocket处理类
WebSocketHandler.h
1 #ifndef WEBSOCKETHANDLER_H
2 #define WEBSOCKETHANDLER_H
3
4 #include <QObject>
5 #include <QWebSocket>
6 #include <QUrl>
7
8 class WebSocketHandler : public QObject
9 {
10 Q_OBJECT
11 Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged)
12 Q_PROPERTY(QString statusMessage READ statusMessage NOTIFY statusMessageChanged)
13
14 public:
15 explicit WebSocketHandler(QObject *parent = nullptr);
16 ~WebSocketHandler();
17
18 Q_INVOKABLE void connectToServer(const QString &url);
19 Q_INVOKABLE void disconnectFromServer();
20 Q_INVOKABLE void sendMessage(const QString &message);
21
22 bool isConnected() const;
23 QString statusMessage() const;
24 void setStatusMessage(const QString &message);
25
26 signals:
27 void connectedChanged(bool connected);
28 void statusMessageChanged(const QString &message);
29 void messageReceived(const QString &message);
30 void errorOccurred(const QString &error);
31
32 private slots:
33 void onConnected();
34 void onDisconnected();
35 void onTextMessageReceived(const QString &message);
36 void onError(QAbstractSocket::SocketError error);
37
38 private:
39 QWebSocket *m_webSocket;
40 bool m_connected;
41 QString m_statusMessage;
42 QString m_url;
43
44 };
45
46 #endif // WEBSOCKETHANDLER_H
WebSocketHandler.cpp
1 #include "WebSocketHandler.h"
2 #include <QDebug>
3
4 WebSocketHandler::WebSocketHandler(QObject *parent)
5 : QObject(parent)
6 , m_webSocket(new QWebSocket)
7 , m_connected(false)
8 , m_statusMessage("Not connected")
9 {
10 connect(m_webSocket, &QWebSocket::connected, this, &WebSocketHandler::onConnected);
11 connect(m_webSocket, &QWebSocket::disconnected, this, &WebSocketHandler::onDisconnected);
12 connect(m_webSocket, &QWebSocket::textMessageReceived, this, &WebSocketHandler::onTextMessageReceived);
13 connect(m_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &WebSocketHandler::onError);
14
15 }
16
17 WebSocketHandler::~WebSocketHandler()
18 {
19 disconnectFromServer();
20 delete m_webSocket;
21 }
22
23 void WebSocketHandler::connectToServer(const QString &url)
24 {
25 if (m_connected) {
26 disconnectFromServer();
27 }
28
29 m_url = url;
30 m_webSocket->open(QUrl(url));
31 setStatusMessage("Connecting...");
32 }
33
34 void WebSocketHandler::disconnectFromServer()
35 {
36 m_webSocket->close();
37 }
38
39 void WebSocketHandler::sendMessage(const QString &message)
40 {
41 if (!m_connected) {
42 emit errorOccurred("Not connected to server");
43 // return;
44 }
45
46 m_webSocket->sendTextMessage(message);
47 }
48
49 bool WebSocketHandler::isConnected() const
50 {
51 return m_connected;
52 }
53
54 QString WebSocketHandler::statusMessage() const
55 {
56 return m_statusMessage;
57 }
58
59 void WebSocketHandler::setStatusMessage(const QString &message)
60 {
61 if (m_statusMessage != message) {
62 m_statusMessage = message;
63 emit statusMessageChanged(m_statusMessage);
64 }
65 }
66
67
68 void WebSocketHandler::onConnected()
69 {
70 m_connected = true;
71 setStatusMessage("Connected to server");
72 emit connectedChanged(m_connected);
73 }
74
75 void WebSocketHandler::onDisconnected()
76 {
77 m_connected = false;
78 setStatusMessage("Connection closed");
79 emit connectedChanged(m_connected);
80 }
81
82 void WebSocketHandler::onTextMessageReceived(const QString &message)
83 {
84 emit messageReceived(message);
85 }
86
87 void WebSocketHandler::onError(QAbstractSocket::SocketError error)
88 {
89 Q_UNUSED(error)
90 QString errorMsg = "Error: " + m_webSocket->errorString();
91 setStatusMessage(errorMsg);
92 emit errorOccurred(errorMsg);
93 }
2、在main.cpp中注册QML类型
1 #include <QGuiApplication>
2 #include <QQmlApplicationEngine>
3 #include <QQmlContext>
4 #include "WebSocketHandler.h"
5
6 int main(int argc, char *argv[])
7 {
8 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
9 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
10 #endif
11 QGuiApplication app(argc, argv);
12
13 qmlRegisterType<WebSocketHandler>("WebSocket", 1, 0, "WebSocketHandler");
14
15 QQmlApplicationEngine engine;
16 const QUrl url(QStringLiteral("qrc:/main.qml"));
17 QObject::connect(
18 &engine,
19 &QQmlApplicationEngine::objectCreated,
20 &app,
21 [url](QObject *obj, const QUrl &objUrl) {
22 if (!obj && url == objUrl)
23 QCoreApplication::exit(-1);
24 },
25 Qt::QueuedConnection);
26 engine.load(url);
27
28 return app.exec();
29 }
3、修改QML文件以使用C++ WebSocket处理类
1 import QtQuick 2.11
2 import QtQuick.Controls 2.15
3 import QtQuick.Dialogs 1.3
4 import QtQuick.Layouts 1.11
5 import QtQuick.Window 2.11
6 import WebSocket 1.0
7
8
9 Component {
10 id: webSocketComp
11 Popup {
12 id: webSocketPop
13 width: 800
14 height: 600
15 anchors.centerIn: parent
16 padding: 0
17
18 // WebSocket连接
19 WebSocketHandler{
20 id: webSocketHandle
21
22 onMessageReceived: {
23 messageDisplay.append(message + "\n")
24 }
25
26 onErrorOccurred: {
27 messageDisplay.append(error + "\n")
28 }
29
30 onStatusMessageChanged: {
31 messageDisplay.append(statusMessage + "\n")
32 }
33
34 }
35
36 // 发送消息函数
37 function sendMessage() {
38 if (!webSocketHandle.connected) {
39 messageDisplay.append("错误: 请先连接到服务器\n")
40 return
41 }
42
43 var text = messageTextField.text
44
45 if (text === "") {
46 messageDisplay.append("错误: 请输入消息内容\n")
47 return
48 }
49
50 webSocketHandle.sendMessage(text)
51 messageTextField.clear()
52 }
53
54
55
56 background: Rectangle {
57 anchors.fill: parent
58 color: "#042A3F"
59 radius: 8
60 border.color: "#00E5FF"
61 border.width: 1
62 }
63
64 ColumnLayout {
65 anchors.fill: parent
66 anchors.margins: 8
67 spacing: 8
68
69 // 标题栏
70 Rectangle {
71 Layout.fillWidth: true
72 Layout.preferredHeight: 36
73 color: "#041A2F"
74 radius: 4
75
76 RowLayout {
77 anchors.fill: parent
78 anchors.leftMargin: 12
79 anchors.rightMargin: 4
80 spacing: 10
81
82 Label {
83 text: "通信测试窗口"
84 font.pointSize: 12
85 font.bold: true
86 color: "white"
87 Layout.alignment: Qt.AlignVCenter
88 }
89
90 Item {
91 Layout.fillWidth: true
92 }
93
94 Button {
95 Layout.preferredWidth: 28
96 Layout.preferredHeight: 28
97 Layout.alignment: Qt.AlignVCenter
98
99 background: Rectangle {
100 anchors.fill: parent
101 color: parent.down ? "#E53935" :
102 (parent.hovered ? "#FF5252" : "white")
103 radius: 14
104 border.color: "#FFFFFF"
105 border.width: 1
106 }
107
108 contentItem: Image {
109 anchors.fill: parent
110 anchors.margins: 6
111 source: "qrc:/images/close.svg"
112 fillMode: Image.PreserveAspectFit
113 }
114
115 onClicked:{
116 if (webSocketHandle.connected) {
117 webSocketHandle.disconnectFromServer()
118 }
119 webSocketPop.close()
120 }
121 }
122 }
123 }
124
125 // 消息显示区域
126 Rectangle {
127 Layout.fillWidth: true
128 Layout.fillHeight: true
129 color: "white"
130 radius: 4
131 border.color: "#CCCCCC"
132 border.width: 1
133
134 ScrollView {
135 anchors.fill: parent
136 anchors.margins: 4
137
138 TextArea {
139 id: messageDisplay
140 readOnly: true
141 wrapMode: TextArea.Wrap
142 font.pointSize: 10
143 background: null
144 text: "WebSocket通信测试窗口已就绪\n"
145 }
146 }
147 }
148
149 // 表单区域
150 GridLayout {
151 Layout.fillWidth: true
152 columns: 2
153 columnSpacing: 8
154 rowSpacing: 8
155
156 Label {
157 text: "服务器URL:"
158 font.pointSize: 10
159 font.bold: true
160 color: "white"
161 Layout.alignment: Qt.AlignVCenter
162 }
163
164 TextField {
165 id: urlTextField
166 Layout.fillWidth: true
167 placeholderText: "请输入WebSocket服务器地址"
168 font.pointSize: 10
169 // ws://localhost:6789/api/v1/ws?userId=a46b2cdf-af02-4a89-b034-b8587483fd33
170 //"wss://echo.websocket.org"
171 text: "ws://192.168.0.105:6789/api/v1/ws?userId=a46b2cdf-af02-4a89-b034-b8587483fd33"
172 background: Rectangle {
173 implicitHeight: 30
174 radius: 4
175 color: "white"
176 border.color: "#CCCCCC"
177 border.width: 1
178 }
179 }
180
181 Label {
182 text: "发送消息:"
183 font.pointSize: 10
184 font.bold: true
185 color: "white"
186 Layout.alignment: Qt.AlignVCenter
187 }
188
189 TextField {
190 id: messageTextField
191 Layout.fillWidth: true
192 placeholderText: "请输入要发送的消息"
193 font.pointSize: 10
194 background: Rectangle {
195 implicitHeight: 30
196 radius: 4
197 color: "white"
198 border.color: "#CCCCCC"
199 border.width: 1
200 }
201
202 onAccepted: {
203 // 按回车键发送消息
204 sendMessage()
205 }
206 }
207 }
208
209 // 按钮区域
210 RowLayout {
211 Layout.fillWidth: true
212 Layout.preferredHeight: 40
213 spacing: 12
214
215 Item {
216 Layout.fillWidth: true
217 }
218
219 // 自定义按钮组件
220 component CustomButton: Button {
221 property alias textColor: btnText.color
222
223 background: Rectangle {
224 gradient: Gradient {
225 GradientStop {
226 position: 0.0;
227 color: parent.down ? "#2A3F5F" :
228 (parent.hovered ? "#2A3F5F" : "#1E2A4A")
229 }
230 GradientStop {
231 position: 1.0;
232 color: parent.down ? "#1E2A4A" :
233 (parent.hovered ? "#1E2A4A" : "#2A3F5F")
234 }
235 }
236 radius: 6
237 border.color: "#00E5FF"
238 border.width: 2
239 }
240
241 contentItem: Text {
242 id: btnText
243 text: parent.text
244 font.bold: true
245 font.pointSize: 10
246 color: "#00E5FF"
247 horizontalAlignment: Text.AlignHCenter
248 verticalAlignment: Text.AlignVCenter
249 }
250 }
251
252
253 CustomButton {
254 id: connectButton
255 text: webSocketHandle.connected ? "断开" : "连接"
256 width: 80
257 height: 36
258 onClicked: {
259 if (webSocketHandle.connected) {
260 webSocketHandle.disconnectFromServer()
261 } else {
262 webSocketHandle.connectToServer(urlTextField.text)
263 }
264 }
265 }
266
267
268 CustomButton {
269 id: sendButton
270 text: "发送"
271 width: 80
272 height: 36
273 enabled: webSocketHandle.connected
274 onClicked: {
275 sendMessage()
276 }
277 }
278
279 CustomButton {
280 id: clearButton
281 text: "清空"
282 width: 80
283 height: 36
284 onClicked: {
285 messageDisplay.clear()
286 messageDisplay.text = "消息已清空\n"
287 }
288 }
289
290 }
291 }
292 }
293 }
在测试接口时,若没有服务器,可以使用"wss://echo.websocket.org",这是一个回调显示,即你向服务器发送什么信息,也会得到什么信息。
4、修改.pro文件以包含必要的模块
在您的.pro文件中,确保添加了websockets模块:
QT += quick websockets