当前位置: 首页 > article >正文

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());
}

http://www.kler.cn/a/9813.html

相关文章:

  • 基于LLaMA-Factory微调Llama3
  • 「QT」几何数据类 之 QPolygon 多边形类
  • 2024年11月8日上海帆软用户大会
  • python可视化进阶
  • 封装的数字滚动组件的实现代码
  • 科技革命前沿:救援机器人!
  • 透过Gartner最新报告,认识“超级边缘”
  • Java 包详细讲解
  • ChatGPT想干掉开发人员,做梦去吧
  • ERTEC200P-2 PROFINET设备完全开发手册(4-2)
  • 4.9--计算机网络之TCP篇之TCP 重传、滑动窗口、流量控制、拥塞控制--(复习+大总结)---好好沉淀,沉下心来
  • 真题详解(Flynn分类)-软件设计(四十六)
  • 【Linux】线程概念详析
  • 博客平台用户模块设计原则:构建简洁、高效的用户体验
  • 100种思维模型之非共识思维模型-48
  • 板块模型构建、k点选定及Miller指数对表面分类
  • 代码随想录算法训练营第五十二天 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
  • 液压传动与控制实验教学培训系统平台
  • Bootloader的作用
  • [ 应急响应基础篇 ] Windows系统隐藏账户详解(Windows留后门账号)
  • 从存算分离说起:金融行业数据库分布式改造之路
  • 【Linux】工具(5)——gdb
  • 浏览器:好用的浏览器插件,亲测好用
  • 分布式场景下,Apache YARN、Google Kubernetes 如何解决资源管理问题?
  • Quaternion插值方法
  • FFMPEG VCL Pack Crack显示位置支持或光标