首先这篇博客主要讲解的是如何设计一个基于qt开发的点菜系统,这方面有很多内容会引用他人的文章需要继续学习他人的文章才会明白此文章是在讲解啥。
整体设计思路

这张图其实很详细的介绍了点菜系统需要的技术,在开发板方面,也就是服务器端,首先屏幕显示也是基于qt开发,所有你的ubuntu qt开发的时候就得设置好其编译器和环境基于开发板的,同时你还需要另一套环境进行直接在开发板上测试不需要反反复复的在开发板上重装。屏幕显示部分还需要首先设置一个登陆界面当客户端也就是ubuntu或者电脑登陆完成后发送消息给开发板,告诉其可以点菜了否则还在此等待。点菜界面部分也就是需要设置一个输入人数餐桌号的界面后确认后进行菜品的选择。点菜图片是需要到网上下载并选择你想要的菜品图片比如辣椒炒肉、水煮活鱼等。开发板作为服务器需要与客户端ubuntu连接通讯协议采用tcp协议。
在ubuntu方面也就是客户端,需要用到数据库sqlite存储数据防止代码中断后数据就删除了,登陆界面也是qt开发,客户端与服务器通讯采用tcp协议。
首先第一部分了解tcp协议
了解一个协议最好的方式就是跟随老师学习。
此部分主要工作为tcp协议在Linux ubuntu 上的实操,tcp协议的详细介绍内容请参考韦东山相关教程百问网韦东山嵌入式Linux应用开发入门实验班5-3tcp示例
第一部分实操,主要是跟着韦老师学习,其实操课程。
首先下载代码放到Ubuntu中

首先你得知道作为Ubuntu中打开的程序是不需要makefile以及生成ko文件的,也就是其实你这文件代码也可以在win11的vscode中用编译器编译运行。
client.c
1#include <sys/types.h> /* See NOTES */ 2#include <sys/socket.h> 3#include <string.h> 4#include <sys/socket.h> 5#include <netinet/in.h> 6#include <arpa/inet.h> 7#include <unistd.h> 8#include <stdio.h> 9 10/* socket 11 * connect 12 * send/recv 13 */ 14 15#define SERVER_PORT 8888 16 17int main(int argc, char **argv) 18{ 19 int iSocketClient; 20 struct sockaddr_in tSocketServerAddr; 21 22 int iRet; 23 unsigned char ucSendBuf[1000]; 24 int iSendLen; 25 int iRecvLen; 26 27 if (argc != 2) 28 { 29 printf("Usage:\n"); 30 printf("%s <server_ip>\n", argv[0]); 31 return -1; 32 } 33 // 1.面向连接的TCP协议(SOCK_STREAM) 的Socket 34 iSocketClient = socket(AF_INET, SOCK_STREAM, 0); 35 36 tSocketServerAddr.sin_family = AF_INET; 37 tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */ 38 //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; 39 if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) 40 { 41 printf("invalid server_ip\n"); 42 return -1; 43 } 44 memset(tSocketServerAddr.sin_zero, 0, 8); 45 46 // 2.连接服务器,设置好的服务器地址发起TCP连接请求 47 iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); 48 if (-1 == iRet) 49 { 50 printf("connect error!\n"); 51 return -1; 52 } 53 54 while (1) 55 { 56 if (fgets(ucSendBuf, 999, stdin)) 57 { // 3.发送数据到服务器 58 iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0); 59 if (iSendLen <= 0) 60 { // 4 61 close(iSocketClient); 62 return -1; 63 } 64 // 接收服务器的回复并打印 65 // recv函数等待并读取服务器返回的数据。这是一个阻塞调用 66 iRecvLen = recv(iSocketClient, ucSendBuf, 999, 0); 67 if (iRecvLen > 0) 68 { 69 ucSendBuf[iRecvLen] = '\0'; 70 printf("From server: %s\n", ucSendBuf); 71 } 72 } 73 } 74 75 return 0; 76} 77 78
server.c
1#include <sys/types.h> /* See NOTES */ 2#include <sys/socket.h> 3#include <string.h> 4#include <sys/socket.h> 5#include <netinet/in.h> 6#include <arpa/inet.h> 7#include <unistd.h> 8#include <stdio.h> 9#include <signal.h> 10 11 12/* socket 13 * bind 14 * listen 15 * accept 16 * send/recv 17 */ 18// 服务器监听的端口号(8888) 19// BACKLOG定义了连接请求队列的最大长度 20#define SERVER_PORT 8888 21#define BACKLOG 10 22 23int main(int argc, char **argv) 24{ 25 int iSocketServer; 26 int iSocketClient; 27 struct sockaddr_in tSocketServerAddr; 28 struct sockaddr_in tSocketClientAddr; 29 int iRet; 30 int iAddrLen; 31 int cnt; 32 33 int iRecvLen; 34 unsigned char ucRecvBuf[1000]; 35 36 int iClientNum = -1; 37 38 signal(SIGCHLD,SIG_IGN); 39 // 1.创建一个使用 IPv4地址族(AF_INET) 和 面向连接的TCP协议(SOCK_STREAM) 的Socket 40 iSocketServer = socket(AF_INET, SOCK_STREAM, 0); 41 if (-1 == iSocketServer) 42 { 43 printf("socket error!\n"); 44 return -1; 45 } 46 47 tSocketServerAddr.sin_family = AF_INET; 48 tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */ 49 tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; 50 memset(tSocketServerAddr.sin_zero, 0, 8); 51 52 // 2.bind函数将创建的Socket与指定的IP地址和端口号绑定 53 iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); 54 if (-1 == iRet) 55 { 56 printf("bind error!\n"); 57 return -1; 58 } 59 60 // 3.服务器Socket开始监听来自客户端的连接请求 61 iRet = listen(iSocketServer, BACKLOG); 62 if (-1 == iRet) 63 { 64 printf("listen error!\n"); 65 return -1; 66 } 67 68 while (1) 69 { 70 iAddrLen = sizeof(struct sockaddr); 71 // accept函数从连接请求队列中取出一个请求,为该连接创建一个新的Socket(iSocketClient) 72 // 4.并获取客户端的地址信息。这是一个阻塞调用,直到有连接请求才会返回 73 iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen); 74 75 if (-1 != iSocketClient) // 连接成功后,打印客户端信息 76 { 77 iClientNum++; 78 printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr)); 79 if (!fork()) 80 { 81 cnt = 0; 82 /* 子进程的源码 */ 83 while (1) 84 { 85 /* 5.使用 recv函数读取客户端发送的数据 */ 86 iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0); 87 if (iRecvLen <= 0) 88 { 89 close(iSocketClient); 90 return -1; 91 } 92 else 93 { 94 ucRecvBuf[iRecvLen] = '\0'; 95 printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf); 96 sprintf(ucRecvBuf, "Get Msg cnt %d", cnt++); 97 // send函数向客户端发送一个带计数器的回应消息 98 send(iSocketClient, ucRecvBuf, strlen(ucRecvBuf), 0); 99 } 100 } 101 } 102 } 103 } 104 // 6 105 close(iSocketServer); 106 return 0; 107} 108 109
1gcc -o server server.c 2gcc -o client client.c 3./server 4./client 192.168.101.129 5
打开两个终端分别运行客户端、服务器端程序测试。

从图中可以看出,你得设置两个终端,一个做服务器,一个做客户端。设置ip时,可以任意指定其中的一个即可。
其次qt开发界面基础
这方面是基于Ubuntu 的qt开发的基础方面的知识。
首先安装ubuntu时我是跟着韦东山的此教程百问网韦东山嵌入式Linux应用开发入门实验班—编译烧录qt系统
跟着他的教程首先完成了最基础的实现,以上就不详细展开说了。

输入 chmod +x qt然后按一下 Tab键,终端会自动补全完整的文件名。
./qt-opensource-linux-x64-5.12.9.run
在学习的过程中我也遇到了一些问题,我的没有找到

在终端中的确没有找到此文件。

还有就是qt里面设置的slot最开始按的时候没反应,发现代码中文件名和设置的函数名得一模一样

如下图所示的设置。

以上就是我跟着他的时候出现的部分错误你看能不能帮你解决问题。
但是我们要明白,他编译的环境是针对开发板编译的都是32位的qmake也是win32位,如果想在ubuntu上测试会出现,以下这个错误。
102:23:09: Starting /home/book/QT_Project/build-server_jiemian-100ask_imx6ull-Debug/server_jiemian... 202:23:09: Failed to start program. Path or permissions wrong? 302:23:09: /home/book/QT_Project/build-server_jiemian-100ask_imx6ull-Debug/server_jiemian exited with code -1 402:23:09: The process failed to start. Either the invoked program "/home/book/QT_Project/build-server_jiemian-100ask_imx6ull-Debug/server_jiemian" is missing, or you may have insufficient permissions to invoke the program. 5

会发现miss找不到路径。Ubuntu上运行不了,但是下载到开发板上可以运行。
接下来你需要设置桌面版本也就是unbuntu版本。

到时候你想给开发板编译就选上面哪个,想在板子上运行就选下面这个。上面哪个C,C++编译器是32位的包括qt version也是。所以你如果要设置ubuntu的就得找到x86 64位的qmake 安装。

输入此命令更新库
1sudo apt-get update 2sudo apt-get install qt5-default 3
安装qmake
qmake --version查看版本,查看其安装路径,然后把路径放到Qt Version里面。保存Kits再新建一个。


然后编译后你的ubuntu就可以正常运行了。

你可以在debug处选择使用的编译器,等你在ubuntu上调好后就可以导入到开发板上直接使用了。
本人第一个qt界面是参考的这位博主的文章
Qt设计精美的登录注册界面(包含SQLite数据库应用)
具体详细步骤可以跟着他的来。

这也就是我在ubuintu上设计的第一个界面。

ui界面设计的时候选择这个将他的代码复制进去。


升级后的界面。
但在这个过程中我发现,我一直输入不了中文,后来才知道得安装qt支持的中文包。
安装Qt5的Fcitx前端插件:
在终端中执行以下命令:
1sudo apt install fcitx-frontend-qt5 2
安装后,文件通常在这里:
你可以用 ls命令检查一下是否存在:
1/usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so 2ls /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so 3
将插件文件复制到Qt Creator的插件目录(这是解决问题的核心操作)
首先,需要找到您Qt Creator的安装路径。 如果您是通过Qt官方安装程序安装的,路径通常像这样:
/opt/Qt/Tools/QtCreator/lib/Qt/plugins/platforminputcontexts/
但是我的在:
/home/book/Qt5.12.9/Tools/QtCreator/lib/Qt/plugins/platforminputcontexts/
然后,使用cp命令复制文件(请将下面的路径替换为您电脑上真实的Qt安装路径):
1sudo cp /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so /home/book/Qt5.12.9/Tools/QtCreator/lib/Qt/plugins/platforminputcontexts/ 2


ctrl+空格就可以输入中文了
后续内容就是加载数据库,到时候和开发板数据相关联。


最后实现的登陆界面
详细代码主要涉及到注册界面、登陆界面。代码放在最后的链接中。
接下来就要涉及到点菜系统的整个开发了,客户端登陆可以直接使用以上界面。所以关键就是服务器端的点菜了。
首先我的mainwindow计划实现一个等待消息的界面,通过tcp协议接受begin_val后进入点菜界面的跳转。
mainwindow.h
1#ifndef MAINWINDOW_H 2#define MAINWINDOW_H 3 4#include <QMainWindow> 5#include <QTcpServer> 6#include <QTcpSocket> 7class desk_people_num; 8QT_BEGIN_NAMESPACE 9namespace Ui { class MainWindow; } 10QT_END_NAMESPACE 11 12class MainWindow : public QMainWindow 13{ 14 Q_OBJECT 15 16public: 17 MainWindow(QWidget *parent = nullptr); 18 ~MainWindow(); 19 20private slots: 21 void onNewConnection(); // 处理新连接 22 void onReadyRead(); // 处理接收数据 23 void onSocketError(QAbstractSocket::SocketError error); // 处理socket错误 24 25private: 26 Ui::MainWindow *ui; 27 QTcpServer *tcpServer; // TCP服务器 28 QTcpSocket *clientSocket; // 客户端socket 29 desk_people_num *deskPeopleWindow; // 第二个界面指针 30 void setupTCPConnection(); // 设置TCP连接 31 void switchToDeskPeopleNum(); // 切换到第二个界面 32 void handleOrder(); 33 34public: 35 QTcpSocket* getClientSocket() const { return clientSocket; } 36 void sendResponseToClient(const QString &response); 37}; 38 39// 全局变量声明 40extern QTcpSocket* clientSocket; 41extern desk_people_num* deskPeopleWindow; 42#endif // MAINWINDOW_H 43 44
mainwindow.cpp
1#include "mainwindow.h" 2#include "ui_mainwindow.h" 3#include <QGraphicsDropShadowEffect> 4#include <QMessageBox> 5#include <QDebug> 6#include "desk_people_num.h" 7#include "ui_desk_people_num.h" 8 9// 定义全局变量 10QTcpSocket* clientSocket = nullptr; //初始化为nullptr 11desk_people_num* deskPeopleWindow= nullptr; 12MainWindow::MainWindow(QWidget *parent) 13 : QMainWindow(parent) 14 , ui(new Ui::MainWindow) 15 , tcpServer(nullptr) 16 , clientSocket(nullptr) 17 , deskPeopleWindow(nullptr) 18{ 19 ui->setupUi(this); 20 //设置图片 21 QPixmap *pix = new QPixmap(":/new/prefix1/diancai.jpg"); 22 QSize sz = ui->label_image->size(); 23 ui->label_image->setPixmap(pix->scaled(sz)); 24 25 //设置图片阴影效果 26 QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this); 27 shadow->setOffset(-3, 0); 28 shadow->setColor(QColor("#888888")); 29 shadow->setBlurRadius(30); 30 ui->label_image->setGraphicsEffect(shadow); 31 32 // 设置TCP连接 33 setupTCPConnection(); 34} 35 36void MainWindow::setupTCPConnection() 37{ 38 // 创建TCP服务器 39 tcpServer = new QTcpServer(this); 40 41 // 监听所有IP的8080端口(您可以根据需要修改端口号) 42 //if (!tcpServer->listen(QHostAddress::Any, 8080)) { 43 if (!tcpServer->listen(QHostAddress("192.168.101.129"), 8080)) { 44 QMessageBox::critical(this, "TCP Server", 45 QString("无法启动服务器: %1").arg(tcpServer->errorString())); 46 return; 47 } 48 49 // 连接新连接信号 50 connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::onNewConnection); 51 52 qDebug() << "TCP服务器已启动,监听端口: 8080"; 53} 54 55void MainWindow::onNewConnection() 56{ 57 // 如果有已连接的客户端,先断开 58 if (clientSocket) { 59 clientSocket->disconnectFromHost(); 60 clientSocket->deleteLater(); 61 clientSocket = nullptr; 62 ::clientSocket = nullptr; // 同步全局变量 63 } 64 65 // 获取新连接 66 clientSocket = tcpServer->nextPendingConnection(); 67 ::clientSocket = clientSocket; // 同步到全局变量 68 69 // 连接信号槽 70 connect(clientSocket, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead); 71 connect(clientSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), 72 this, &MainWindow::onSocketError); 73 74 qDebug() << "新的客户端连接:" << clientSocket->peerAddress().toString(); 75 qDebug() << "全局clientSocket地址:" << ::clientSocket; 76 qDebug() << "成员clientSocket地址:" << clientSocket; 77} 78 79//static int begin_val=0; 80void MainWindow::onReadyRead() 81{ 82 if (!clientSocket) return; 83 84 // 读取所有数据 85 QByteArray data = clientSocket->readAll(); 86 QString message = QString::fromUtf8(data).trimmed(); 87 88 qDebug() << "接收到消息:" << message; 89 90 // 检查是否为开始消息 91 if (message == "begin_val") { 92 // 向客户端发送"ok"响应 93 sendResponseToClient("ok"); 94 qDebug() << "接收到开始消息,准备切换界面"; 95 switchToDeskPeopleNum(); 96 } 97} 98 99// 向客户端发送响应 100void MainWindow::sendResponseToClient(const QString &response) 101{ 102 if (clientSocket && clientSocket->state() == QAbstractSocket::ConnectedState) { 103 QByteArray responseData = response.toUtf8(); 104 qint64 bytesWritten = clientSocket->write(responseData); 105 106 if (bytesWritten == -1) { 107 qDebug() << "发送响应失败:" << clientSocket->errorString(); 108 } else { 109 // 确保数据被发送 110 clientSocket->flush(); 111 qDebug() << "已向客户端发送响应:" << response; 112 } 113 } else { 114 qDebug() << "客户端未连接,无法发送响应"; 115 } 116} 117 118void MainWindow::onSocketError(QAbstractSocket::SocketError error) 119{ 120 Q_UNUSED(error) 121 if (clientSocket) { 122 qDebug() << "Socket错误:" << clientSocket->errorString(); 123 } 124} 125 126void MainWindow::switchToDeskPeopleNum() 127{ 128 //this->close(); // 关界面 129 this->hide(); // 改为隐藏而不是关闭 130 desk_people_num *s = new desk_people_num; //跳至singup界面 131 s->show(); 132 133 qDebug() << "已切换到desk_people_num界面"; 134} 135 136MainWindow::~MainWindow() 137{ 138 if (tcpServer) { 139 tcpServer->close(); 140 } 141 if (clientSocket) { 142 clientSocket->close(); 143 } 144 delete ui; 145} 146 147// 在MainWindow的成员函数中 148extern int g_deskNumber,g_peopleNumber; 149void MainWindow::handleOrder() 150{ 151 // 可以直接访问全局变量 152 if (g_deskNumber > 0 && g_peopleNumber > 0) { 153 qDebug() << "桌号:" << g_deskNumber << "人数:" << g_peopleNumber; 154 155 // 发送到服务器或其他处理 156 QString orderInfo = QString("桌号:%1,人数:%2").arg(g_deskNumber).arg(g_peopleNumber); 157 //sendToServer(orderInfo); 158 159 // 重置选择(可选) 160 // g_deskNumber = 0; 161 // g_peopleNumber = 0; 162 } else { 163 qDebug() << "请先选择桌号和人数"; 164 } 165} 166 167

如图所示以上代码实现的就是这个界面。

同时我会开启tcp监听,当有连接后并发送消息给ubuntu服务器端时,向客户端返回消息ok。

我是通过正点原子的调试助手模拟发送。
完成以上部分后开始计划desk_people_num选桌号选人数的界面设计,当选好人数和桌号后按下确定跳转界面,当按下取消后界面数据清空重新选择。

desk_people_num.h
1#ifndef DESK_PEOPLE_NUM_H 2#define DESK_PEOPLE_NUM_H 3 4#include <QWidget> 5#include <QDebug> 6#include "xuancai.h" 7namespace Ui { 8class desk_people_num; 9} 10 11class desk_people_num : public QWidget 12{ 13 Q_OBJECT 14 15public: 16 explicit desk_people_num(QWidget *parent = nullptr); 17 ~desk_people_num(); 18 19private slots: 20 21 22 void on_desk1_Button_clicked(); 23 24 void on_desk2_Button_clicked(); 25 26 void on_desk3_Button_clicked(); 27 28 void on_desk4_Button_clicked(); 29 30 void on_desk5_Button_clicked(); 31 32 void on_desk6_Button_clicked(); 33 34 void on_desk7_Button_clicked(); 35 36 void on_desk8_Button_clicked(); 37 38 void on_desk9_Button_clicked(); 39 40 void on_desk10_Button_clicked(); 41 42 void on_people1_Button_clicked(); 43 44 void on_people2_Button_clicked(); 45 46 void on_people3_Button_clicked(); 47 48 void on_people4_Button_clicked(); 49 50 void on_people5_Button_clicked(); 51 52 void on_people6_Button_clicked(); 53 54 void on_people7_Button_clicked(); 55 56 void on_people8_Button_clicked(); 57 58 void on_people9_Button_clicked(); 59 60 void on_ensureButton_clicked(); 61 62 void on_cancelButton_clicked(); 63 64private: 65 Ui::desk_people_num *ui; 66 // 当前选择的桌号和人数 67 int currentDeskNumber; 68 int currentPeopleNumber; 69 70 // 更新按钮样式 71 void updateDeskButtonsStyle(); 72 void updatePeopleButtonsStyle(); 73 void resetAllSelection(); 74}; 75 76#endif // DESK_PEOPLE_NUM_H 77 78
desk_people_num.cpp
1#include "desk_people_num.h" 2#include "ui_desk_people_num.h" 3#include "xuancai.h" 4// 定义全局变量 5int g_deskNumber = 0; // 初始值为0,表示未选择 6int g_peopleNumber = 0; // 初始值为0,表示未选择 7 8desk_people_num::desk_people_num(QWidget *parent) : 9 QWidget(parent), 10 ui(new Ui::desk_people_num) 11{ 12 ui->setupUi(this); 13 // 初始化全局变量 14 g_deskNumber = 0; 15 g_peopleNumber = 0; 16} 17 18 19desk_people_num::~desk_people_num() 20{ 21 delete ui; 22} 23 24 25void desk_people_num::updateDeskButtonsStyle() 26{ 27 // 重置所有桌号按钮样式 28 QList<QPushButton*> deskButtons = { 29 ui->desk1_Button, ui->desk2_Button, ui->desk3_Button, 30 ui->desk4_Button, ui->desk5_Button, ui->desk6_Button, 31 ui->desk7_Button, ui->desk8_Button, ui->desk9_Button, 32 ui->desk10_Button 33 }; 34 35 for (int i = 0; i < deskButtons.size(); ++i) { 36 if ((i + 1) == currentDeskNumber) { 37 // 选中的按钮样式 - 绿色背景 38 deskButtons[i]->setStyleSheet( 39 "QPushButton {" 40 " background-color: #4CAF50;" 41 " color: white;" 42 " border: 2px solid #45a049;" 43 " border-radius: 5px;" 44 " font-weight: bold;" 45 "}" 46 "QPushButton:hover {" 47 " background-color: #45a049;" 48 "}" 49 ); 50 } else { 51 // 未选中的按钮样式 - 灰色背景 52 deskButtons[i]->setStyleSheet( 53 "QPushButton {" 54 " background-color: #f0f0f0;" 55 " color: #333333;" 56 " border: 1px solid #cccccc;" 57 " border-radius: 5px;" 58 "}" 59 "QPushButton:hover {" 60 " background-color: #e0e0e0;" 61 "}" 62 ); 63 } 64 } 65} 66 67void desk_people_num::updatePeopleButtonsStyle() 68{ 69 // 重置所有人数按钮样式 70 QList<QPushButton*> peopleButtons = { 71 ui->people1_Button, ui->people2_Button, ui->people3_Button, 72 ui->people4_Button, ui->people5_Button, ui->people6_Button, 73 ui->people7_Button, ui->people8_Button, ui->people9_Button 74 }; 75 76 for (int i = 0; i < peopleButtons.size(); ++i) { 77 if ((i + 1) == currentPeopleNumber) { 78 // 选中的按钮样式 - 蓝色背景 79 peopleButtons[i]->setStyleSheet( 80 "QPushButton {" 81 " background-color: #2196F3;" 82 " color: white;" 83 " border: 2px solid #0b7dda;" 84 " border-radius: 5px;" 85 " font-weight: bold;" 86 "}" 87 "QPushButton:hover {" 88 " background-color: #0b7dda;" 89 "}" 90 ); 91 } else { 92 // 未选中的按钮样式 - 灰色背景 93 peopleButtons[i]->setStyleSheet( 94 "QPushButton {" 95 " background-color: #f0f0f0;" 96 " color: #333333;" 97 " border: 1px solid #cccccc;" 98 " border-radius: 5px;" 99 "}" 100 "QPushButton:hover {" 101 " background-color: #e0e0e0;" 102 "}" 103 ); 104 } 105 } 106} 107 108// 重置所有选择 109void desk_people_num::resetAllSelection() 110{ 111 currentDeskNumber = 0; 112 currentPeopleNumber = 0; 113 g_deskNumber = 0; 114 g_peopleNumber = 0; 115 116 updateDeskButtonsStyle(); 117 updatePeopleButtonsStyle(); 118 119 qDebug() << "已重置所有选择: 桌号 =" << g_deskNumber << "人数 =" << g_peopleNumber; 120} 121 122void desk_people_num::on_desk1_Button_clicked() 123{ 124 currentDeskNumber = 1; g_deskNumber = 1; 125 updateDeskButtonsStyle(); 126 qDebug() << "选择桌号:" << g_deskNumber; 127} 128 129void desk_people_num::on_desk2_Button_clicked() 130{ 131 currentDeskNumber = 2; g_deskNumber = 2; 132 updateDeskButtonsStyle(); 133 qDebug() << "选择桌号:" << g_deskNumber; 134} 135 136void desk_people_num::on_desk3_Button_clicked() 137{ 138 currentDeskNumber = 3; g_deskNumber = 3; 139 updateDeskButtonsStyle(); 140 qDebug() << "选择桌号:" << g_deskNumber; 141} 142 143void desk_people_num::on_desk4_Button_clicked() 144{ 145 currentDeskNumber = 4; g_deskNumber = 4; 146 updateDeskButtonsStyle(); 147 qDebug() << "选择桌号:" << g_deskNumber; 148} 149 150void desk_people_num::on_desk5_Button_clicked() 151{ 152 currentDeskNumber = 5; g_deskNumber = 5; 153 updateDeskButtonsStyle(); 154 qDebug() << "选择桌号:" << g_deskNumber; 155} 156 157void desk_people_num::on_desk6_Button_clicked() 158{ 159 currentDeskNumber = 6; g_deskNumber = 6; 160 updateDeskButtonsStyle(); 161 qDebug() << "选择桌号:" << g_deskNumber; 162} 163 164void desk_people_num::on_desk7_Button_clicked() 165{ 166 currentDeskNumber = 7; g_deskNumber = 7; 167 updateDeskButtonsStyle(); 168 qDebug() << "选择桌号:" << g_deskNumber; 169} 170 171void desk_people_num::on_desk8_Button_clicked() 172{ 173 currentDeskNumber = 8; g_deskNumber = 8; 174 updateDeskButtonsStyle(); 175 qDebug() << "选择桌号:" << g_deskNumber; 176} 177 178void desk_people_num::on_desk9_Button_clicked() 179{ 180 currentDeskNumber = 9; g_deskNumber = 9; 181 updateDeskButtonsStyle(); 182 qDebug() << "选择桌号:" << g_deskNumber; 183} 184 185void desk_people_num::on_desk10_Button_clicked() 186{ 187 currentDeskNumber = 10; g_deskNumber = 10; 188 updateDeskButtonsStyle(); 189 qDebug() << "选择桌号:" << g_deskNumber; 190} 191 192void desk_people_num::on_people1_Button_clicked() 193{ 194 currentPeopleNumber = 1; g_peopleNumber = 1; 195 updatePeopleButtonsStyle(); 196 qDebug() << "选择人数:" << g_peopleNumber; 197} 198 199void desk_people_num::on_people2_Button_clicked() 200{ 201 currentPeopleNumber = 2; g_peopleNumber = 2; 202 updatePeopleButtonsStyle(); 203 qDebug() << "选择人数:" << g_peopleNumber; 204} 205 206void desk_people_num::on_people3_Button_clicked() 207{ 208 currentPeopleNumber = 3; g_peopleNumber = 3; 209 updatePeopleButtonsStyle(); 210 qDebug() << "选择人数:" << g_peopleNumber; 211} 212 213void desk_people_num::on_people4_Button_clicked() 214{ 215 currentPeopleNumber = 4; g_peopleNumber = 4; 216 updatePeopleButtonsStyle(); 217 qDebug() << "选择人数:" << g_peopleNumber; 218} 219 220void desk_people_num::on_people5_Button_clicked() 221{ 222 currentPeopleNumber = 5; g_peopleNumber = 5; 223 updatePeopleButtonsStyle(); 224 qDebug() << "选择人数:" << g_peopleNumber; 225} 226 227void desk_people_num::on_people6_Button_clicked() 228{ 229 currentPeopleNumber = 6; g_peopleNumber = 6; 230 updatePeopleButtonsStyle(); 231 qDebug() << "选择人数:" << g_peopleNumber; 232} 233 234void desk_people_num::on_people7_Button_clicked() 235{ 236 currentPeopleNumber = 7; g_peopleNumber = 7; 237 updatePeopleButtonsStyle(); 238 qDebug() << "选择人数:" << g_peopleNumber; 239} 240 241void desk_people_num::on_people8_Button_clicked() 242{ 243 currentPeopleNumber = 8; g_peopleNumber = 8; 244 updatePeopleButtonsStyle(); 245 qDebug() << "选择人数:" << g_peopleNumber; 246} 247 248void desk_people_num::on_people9_Button_clicked() 249{ 250 currentPeopleNumber = 9; g_peopleNumber = 9; 251 updatePeopleButtonsStyle(); 252 qDebug() << "选择人数:" << g_peopleNumber; 253} 254 255void desk_people_num::on_ensureButton_clicked() 256{ 257 // 检查是否已选择桌号和人数 258 if (g_deskNumber == 0 || g_peopleNumber == 0) { 259 qDebug() << "请先选择桌号和人数"; 260 return; 261 } 262 263 qDebug() << "确定 - 桌号:" << g_deskNumber << "人数:" << g_peopleNumber; 264 //this->close(); // 关界面 265 this->hide(); // 改为隐藏而不是关闭 266 xuancai *s = new xuancai; //跳至xuancai界面 267 s->show(); 268 qDebug() << "已切换到xuancai界面"; 269} 270 271void desk_people_num::on_cancelButton_clicked() 272{ 273 // 重置所有选择 274 resetAllSelection(); 275 qDebug() << "取消 - 已清空所有选择"; 276} 277 278

实现的界面效果以及代码如上。
第3部分也就是选菜界面了,直接上效果图,那个test按钮主要是用来发送测试tcp协议连接的。

xuancai.h
1#ifndef XUANCAI_H 2#define XUANCAI_H 3 4#include <QWidget> 5#include "mainwindow.h" 6namespace Ui { 7class xuancai; 8} 9 10class xuancai : public QWidget 11{ 12 Q_OBJECT 13 14public: 15 explicit xuancai(QWidget *parent = nullptr); 16 explicit xuancai(MainWindow* mainWindow, QWidget *parent = nullptr); // 传入MainWindow指针 17 ~xuancai(); 18 19private slots: 20 void on_feiniu_Button1_clicked(); 21 22 void on_feiniu_Button2_clicked(); 23 24 void on_fish_Button1_clicked(); 25 26 void on_fish_Button2_clicked(); 27 28 void on_xia_Button1_clicked(); 29 30 void on_xia_Button2_clicked(); 31 32 void on_doufu_Button1_clicked(); 33 34 void on_doufu_Button2_clicked(); 35 36 void on_ensureButton_clicked(); 37 38 void on_cancelButton_clicked(); 39 void on_testConnectionButton_clicked(); 40private: 41 int beefCount = 0; // 肥牛卷数量 42 int fishCount = 0; // 酸菜鱼数量 43 int xiaCount = 0; // 盐焗大虾数量 44 int doufuCount = 0; // 麻婆豆腐数量 45 46 // 重置所有菜品数量 47 void resetAllDishes(); 48 49 // 发送数据到TCP服务器 50 void sendOrderToClient(); // 修改函数名,更清晰 51 52private: 53 Ui::xuancai *ui; 54 55}; 56 57#endif // XUANCAI_H 58 59
xuancai.cpp
1#include "xuancai.h" 2#include "ui_xuancai.h" 3#include <QTcpSocket> 4#include <QMessageBox> 5#include <QJsonObject> 6#include <QJsonDocument> 7 8xuancai::xuancai(QWidget *parent) : 9 QWidget(parent), 10 ui(new Ui::xuancai), 11 beefCount(0), 12 fishCount(0), 13 xiaCount(0), 14 doufuCount(0) 15{ 16 ui->setupUi(this); 17 18 // 初始化界面显示 19 ui->beef_label->setText("0"); 20 ui->fish_label->setText("0"); 21 ui->xia_label->setText("0"); 22 ui->doufu_label->setText("0"); 23 24 qDebug() << "选菜界面初始化完成"; 25} 26 27xuancai::~xuancai() 28{ 29 delete ui; 30} 31 32void xuancai::resetAllDishes() 33{ 34 beefCount = 0; 35 fishCount = 0; 36 xiaCount = 0; 37 doufuCount = 0; 38 39 ui->beef_label->setText("0"); 40 ui->fish_label->setText("0"); 41 ui->xia_label->setText("0"); 42 ui->doufu_label->setText("0"); 43 44 qDebug() << "所有菜品数量已重置"; 45} 46 47// 模仿MainWindow的sendResponseToClient函数 48void xuancai::sendOrderToClient() 49{ 50 // 使用MainWindow中已建立的clientSocket 51 if (clientSocket && clientSocket->state() == QAbstractSocket::ConnectedState) { 52 53 // 创建JSON数据 54 QJsonObject jsonData; 55 jsonData["beef"] = beefCount; 56 jsonData["doufu"] = doufuCount; 57 jsonData["fish"] = fishCount; 58 jsonData["xia"] = xiaCount; 59 60 QJsonDocument doc(jsonData); 61 QByteArray orderData = doc.toJson(QJsonDocument::Compact); 62 63 qint64 bytesWritten = clientSocket->write(orderData); 64 65 if (bytesWritten == -1) { 66 qDebug() << "发送订单失败:" << clientSocket->errorString(); 67 QMessageBox::warning(this, "发送错误", "订单发送失败"); 68 } else { 69 // 确保数据被发送 70 clientSocket->flush(); 71 qDebug() << "已向客户端发送订单,字节数:" << bytesWritten; 72 qDebug() << "发送的订单数据:" << orderData; 73 QMessageBox::information(this, "成功", "菜品已提交到客户端"); 74 } 75 } else { 76 qDebug() << "客户端未连接,无法发送订单"; 77 QMessageBox::warning(this, "连接错误", "客户端未连接,请先建立连接"); 78 } 79} 80 81// 测试连接状态 82 83void xuancai::on_testConnectionButton_clicked() 84{ 85 qDebug() << "=== 开始TCP连接测试 ==="; 86 87 if (clientSocket && clientSocket->state() == QAbstractSocket::ConnectedState) { 88 qDebug() << "TCP连接状态: 已连接"; 89 QMessageBox::information(this, "连接测试", "TCP连接测试成功!客户端已连接"); 90 } else { 91 qDebug() << "TCP连接状态: 未连接"; 92 QMessageBox::critical(this, "连接测试", "TCP连接测试失败!客户端未连接"); 93 } 94 95 qDebug() << "=== TCP连接测试结束 ==="; 96} 97 98void xuancai::on_ensureButton_clicked() 99{ 100 if (beefCount == 0 && fishCount == 0 && xiaCount == 0 && doufuCount == 0) { 101 QMessageBox::information(this, "提示", "请至少选择一种菜品"); 102 return; 103 } 104 105 qDebug() << "=== 选择的菜品 ==="; 106 qDebug() << "牛肉:" << beefCount << "鱼肉:" << fishCount 107 << "虾:" << xiaCount << "豆腐:" << doufuCount; 108 109 // 使用MainWindow的客户端连接发送数据 110 sendOrderToClient(); 111} 112 113void xuancai::on_cancelButton_clicked() 114{ 115 resetAllDishes(); 116} 117 118// 菜品数量增减按钮(保持不变) 119void xuancai::on_feiniu_Button2_clicked() 120{ 121 beefCount++; 122 ui->beef_label->setText(QString::number(beefCount)); 123} 124 125void xuancai::on_fish_Button2_clicked() 126{ 127 fishCount++; 128 ui->fish_label->setText(QString::number(fishCount)); 129} 130 131void xuancai::on_xia_Button2_clicked() 132{ 133 xiaCount++; 134 ui->xia_label->setText(QString::number(xiaCount)); 135} 136 137void xuancai::on_doufu_Button2_clicked() 138{ 139 doufuCount++; 140 ui->doufu_label->setText(QString::number(doufuCount)); 141} 142 143void xuancai::on_feiniu_Button1_clicked() 144{ 145 if(beefCount > 0) { 146 beefCount--; 147 ui->beef_label->setText(QString::number(beefCount)); 148 } 149} 150 151void xuancai::on_fish_Button1_clicked() 152{ 153 if(fishCount > 0) { 154 fishCount--; 155 ui->fish_label->setText(QString::number(fishCount)); 156 } 157} 158 159void xuancai::on_xia_Button1_clicked() 160{ 161 if(xiaCount > 0) { 162 xiaCount--; 163 ui->xia_label->setText(QString::number(xiaCount)); 164 } 165} 166 167void xuancai::on_doufu_Button1_clicked() 168{ 169 if(doufuCount > 0) { 170 doufuCount--; 171 ui->doufu_label->setText(QString::number(doufuCount)); 172 } 173} 174 175

最后的测试效果和代码如图所示,构建tcp类的时候注意用全局变量,不然单个页面完成后它会销毁断开连接,这个问题卡了我挺久的。
确保你的网络连接没问题后再在开发板上测试。



unbuntu_jiemian就是那个登陆注册的界面。diancai_system_imx6ull就是点菜系统界面。
通过网盘分享的文件:diancai_system_imx6ull.zip等2个文件
链接: https://pan.baidu.com/s/1SDu6y3SeMCb-EzpvP3hNPw?pwd=k4u4 提取码: k4u4
《linux之ubuntu qt界面开发开发点菜系统》 是转载文章,点击查看原文。