Qt使用std::thread更新QPlainTextEdit内容
Qt使用std::thread更新QPlainTextEdit内容
- 一、演示
- 二、部分代码讲解
- 1. 启动函数
- 2. 线程函数
- 三、代码片段
- 1. 主函数
- 2. MainWindow.h
- 3. MainWindow.cpp 源文件
- 四、TCP相关解释
导言:记录Qt使用std::thread更新QPlainTextEdit内容
在写一个简易的服务端发送软件中,需要表示正在发送的内容是哪些,需要在QPlainText中去标记发送对应的内容。这个就应用而生。也是用的单例和 标准的 std::thread来驱动的。有些是没有做完的,下面是全部的开源代码。
一、演示
Qt使用std::thread更新QPlainTextEdit
二、部分代码讲解
1. 启动函数
下面就是整个函数线程的启动函数,因为用到了界面的一些东西,就需要注册一些 类型 ,也是分离运行的
void MainWindow::slotSendBtnClicked()
{
ui->SendPlainText->clear();
ui->SendPlainText->setPlainText(SendContent);
MainWindow::Instance->ui->SendBtn->setEnabled(false);
//注册类型
qRegisterMetaType<QTextBlock>("QTextBlock");
qRegisterMetaType<QTextDocument*>("QTextDocument*");
qRegisterMetaType<QTextCursor>("QTextCursor");
std::thread t_thread(MainWindow::SendThread, MainWindow::Instance->ui->SendPlainText->document());
t_thread.detach();
}
2. 线程函数
这里使用的是静态的函数,数据刷新线程也是通过发送信号,通知主界面去更新内容的,也是用的信号槽机制。
void MainWindow::SendThread(QTextDocument *document)
{
QTextCursor cursor( document);
cursor.setPosition(0);
for (int i = 0; i <MainWindow::Instance->SendContentList.length(); i++)
{
//发送数据
emit MainWindow::Instance->updateLogInfo(QString("已发送序号 %1: ").arg(i+1)+ MainWindow::Instance->SendContentList[i]);
emit MainWindow::Instance->writeToSocket(MainWindow::Instance->SendContentList[i]);
cursor.insertText(">>> ");
cursor.movePosition(QTextCursor::StartOfLine);
cursor.movePosition(QTextCursor::Down);
MainWindow::Instance->ui->SendPlainText->verticalScrollBar()->setValue(cursor.blockNumber() - 5);
_sleep(MainWindow::Instance->ui->comboBox->currentText().toDouble() * 1000);
}
MainWindow::Instance->ui->SendBtn->setEnabled(true);
MainWindow::Instance->ui->SendBtn->setText("再次发送");
}
三、代码片段
1. 主函数
主函数这里设置了使用 Fusion 风格的窗口
#include "MainWindow.h"
#include <QApplication>
#include <QStyleFactory>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
MainWindow *w = MainWindow::GetInstance();
w->show();
return a.exec();
}
2. MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QProcess>
#include <QUrl>
#include <QDesktopServices>
#include <thread>
#include <QTextDocument>
#include <QScrollBar>
#include <QTextBlock>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
static MainWindow* GetInstance();
signals:
//打印日志
void updateLogInfo(QString info);
//向socket写数据
void writeToSocket(QString data);
private slots:
//处理新连接
void slotNewConnect();
//处理接收
void slotReadyRecv();
//处理发送
void slotReadySend();
//处理连接关闭
void slotDisconnect();
//启动监听
void slotListenPort();
private slots:
//选择文件发送
void slotOpenFileBtnClicked();
//当文件路径按钮被点击的时候
void on_pushButton_clicked();
//当发送按钮点击时
void slotSendBtnClicked();
//设置提示函数
void slotUpdateInfo(QString info);
//处理接收写socket信号函数
void slotWriteToSocket(QString data);
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_OnTopCheck_stateChanged(int arg1);
void on_OnTopCheck_toggled(bool checked);
private:
Ui::MainWindow *ui;
QTcpServer * m_TcpSever;
static MainWindow* Instance;
//负责通信
QTcpSocket *m_TcpSocket;
//设置提示信息
void OutPutInfo(QString info);
//发送内容缓存
QStringList SendContentList;
//发送内容字符串
QString SendContent;
static void SendThread(QTextDocument *document);
};
#endif // MAINWINDOW_H
3. MainWindow.cpp 源文件
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow * MainWindow::Instance = nullptr;
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("服务器数据程序");
//创建对象
m_TcpSever = new QTcpServer(this);
//为sever绑定连接函数
connect(m_TcpSever, &QTcpServer::newConnection, this, &MainWindow::slotNewConnect);
// connect(ui->SendBtn, &QPushButton::clicked, this, &MainWindow::slotReadySend);
connect(ui->StartListenBtn, &QPushButton::clicked, this, &MainWindow::slotListenPort);
connect(ui->openFileBtn, &QPushButton::clicked, this, &MainWindow::slotOpenFileBtnClicked);
connect(ui->SendBtn, &QPushButton::clicked, this, &MainWindow::slotSendBtnClicked);
connect(this, &MainWindow::updateLogInfo, this, &MainWindow::slotUpdateInfo);
connect(this, &MainWindow::writeToSocket, this, &MainWindow::slotWriteToSocket);
//触发置顶消息
emit ui->OnTopCheck->toggled(true);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow *MainWindow::GetInstance()
{
if(Instance == nullptr)
{
Instance = new MainWindow();
}
return Instance;
}
void MainWindow::slotNewConnect()
{
//处理客户端请求
m_TcpSocket= m_TcpSever->nextPendingConnection();
ui->ReceivePlainText->appendPlainText(QString("receive connect from IP: %1 Port: %2 ").arg(m_TcpSocket->peerName()).arg(m_TcpSocket->peerPort()));
emit updateLogInfo(QString("接收到来自 IP: %1 端口: %2 的连接").arg(m_TcpSocket->peerName()).arg(m_TcpSocket->peerPort()));
//初试连接发送数据
m_TcpSocket->write("你好客户端!准备开始新的数据传输旅程吧!");
//6.连接信号,接受客户端数据
connect(m_TcpSocket, &QTcpSocket::readyRead, this, &MainWindow::slotReadyRecv);
connect(m_TcpSocket, &QTcpSocket::disconnected, this, &MainWindow::slotDisconnect);
}
void MainWindow::slotReadyRecv()
{
QString data = QString::fromUtf8(m_TcpSocket->readAll());
ui->ReceivePlainText->appendPlainText(data);
ui->ReceivePlainText->appendPlainText("\n-----------------");
}
void MainWindow::slotReadySend()
{
QString sendData = ui->SendPlainText->toPlainText();
m_TcpSocket->write(sendData.toUtf8());
}
void MainWindow::slotDisconnect()
{
ui->ReceivePlainText->appendPlainText("Connect Finished!");
emit updateLogInfo("连接结束!");
}
void MainWindow::slotListenPort()
{
m_TcpSever->listen(QHostAddress::Any, ui->PortComBox->currentText().toUInt());
emit updateLogInfo("启动监听成功!");
ui->StartListenBtn->setText("监听中");
}
void MainWindow::slotOpenFileBtnClicked()
{
QString fileName = QFileDialog::getOpenFileName( this, tr( "打开待发送数据" ), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr( "txt 文件 (*.txt)" ) );
if ( !fileName.isNull() )
{
ui->SendPlainText->clear();
SendContentList.clear();
//设置
ui->pushButton->setText( fileName );
QFile file( fileName );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ))
{
emit updateLogInfo("mcp 流程控制文件打开失败!" );
return;
}
else{
emit updateLogInfo("mcp 流程控制文件打开成功!" );
}
QTextStream outs( &file );
outs.setCodec( "UTF-8" );
ui->SendPlainText->insertPlainText(outs.readAll());
SendContent = ui->SendPlainText->toPlainText();
SendContentList = ui->SendPlainText->toPlainText().split('\n');
file.close();
}
}
void MainWindow::OutPutInfo(QString info)
{
ui->RunTimeInfoInput->appendPlainText("[Info]: " + info);
}
void MainWindow::SendThread(QTextDocument *document)
{
QTextCursor cursor( document);
cursor.setPosition(0);
for (int i = 0; i <MainWindow::Instance->SendContentList.length(); i++)
{
//发送数据
emit MainWindow::Instance->updateLogInfo(QString("已发送序号 %1: ").arg(i+1)+ MainWindow::Instance->SendContentList[i]);
emit MainWindow::Instance->writeToSocket(MainWindow::Instance->SendContentList[i]);
cursor.insertText(">>> ");
cursor.movePosition(QTextCursor::StartOfLine);
cursor.movePosition(QTextCursor::Down);
MainWindow::Instance->ui->SendPlainText->verticalScrollBar()->setValue(cursor.blockNumber() - 5);
_sleep(MainWindow::Instance->ui->comboBox->currentText().toDouble() * 1000);
}
MainWindow::Instance->ui->SendBtn->setEnabled(true);
MainWindow::Instance->ui->SendBtn->setText("再次发送");
}
void MainWindow::on_pushButton_clicked()
{
if(QDesktopServices::openUrl(QUrl::fromLocalFile(ui->pushButton->text())))
{
emit updateLogInfo("系统打开数据文件成功!");
}
else
{
emit updateLogInfo("系统打开数据文件失败!");
}
}
void MainWindow::slotSendBtnClicked()
{
ui->SendPlainText->clear();
ui->SendPlainText->setPlainText(SendContent);
MainWindow::Instance->ui->SendBtn->setEnabled(false);
qRegisterMetaType<QTextBlock>("QTextBlock");
qRegisterMetaType<QTextDocument*>("QTextDocument*");
qRegisterMetaType<QTextCursor>("QTextCursor");
std::thread t_thread(MainWindow::SendThread, MainWindow::Instance->ui->SendPlainText->document());
t_thread.detach();
}
void MainWindow::slotUpdateInfo(QString info)
{
OutPutInfo(info);
}
void MainWindow::slotWriteToSocket(QString data)
{
m_TcpSocket->write(data.toUtf8());
}
void MainWindow::on_pushButton_2_clicked()
{
QString fileName = QFileDialog::getOpenFileName( this, tr( "打开待发送数据" ), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr( "mcp 文件 (*.mcp)" ) );
if ( !fileName.isNull() )
{
ui->ConfigFilePathLB->setText(fileName);
OutPutInfo(fileName);
}
}
void MainWindow::on_pushButton_3_clicked()
{
emit writeToSocket("MCP=" + ui->ConfigFilePathLB->text());
}
void MainWindow::on_pushButton_4_clicked()
{
emit writeToSocket("StartMeasure");
}
void MainWindow::on_pushButton_5_clicked()
{
emit writeToSocket("StopMeasure");
}
void MainWindow::on_OnTopCheck_stateChanged(int arg1)
{
}
void MainWindow::on_OnTopCheck_toggled(bool checked)
{
Qt::WindowFlags m_flags = windowFlags();
if (checked)
{
setWindowFlags(m_flags | Qt::WindowStaysOnTopHint);
this->show();
}
else
{
setWindowFlags(NULL);
this->show();
}
}
四、TCP相关解释
这里就是当一个新的连接来了之后,处理的一些响应,我这里只做了一对一的连接通信,并没有考虑到具体向某一个 客户端通信,这里要注意一下。
void MainWindow::slotNewConnect()
{
//处理客户端请求
m_TcpSocket= m_TcpSever->nextPendingConnection();
ui->ReceivePlainText->appendPlainText(QString("receive connect from IP: %1 Port: %2 ").arg(m_TcpSocket->peerName()).arg(m_TcpSocket->peerPort()));
emit updateLogInfo(QString("接收到来自 IP: %1 端口: %2 的连接").arg(m_TcpSocket->peerName()).arg(m_TcpSocket->peerPort()));
//初试连接发送数据
m_TcpSocket->write("你好客户端!准备开始新的数据传输旅程吧!");
//6.连接信号,接受客户端数据
connect(m_TcpSocket, &QTcpSocket::readyRead, this, &MainWindow::slotReadyRecv);
connect(m_TcpSocket, &QTcpSocket::disconnected, this, &MainWindow::slotDisconnect);
}
这里就是写入数据到socket里面的
void MainWindow::slotWriteToSocket(QString data)
{
m_TcpSocket->write(data.toUtf8());
}