Qt uses std::thread to update QPlainTextEdit content


Introduction: Record Qt using std::thread to update QPlainTextEdit content

When writing a simple server-side sending software, it is necessary to indicate what content is being sent, and it is necessary to mark the corresponding content in QPlainText. This is applied. It is also driven by singleton and standard std::thread. Some are not finished, the following is all open source code.

1. Demonstration

Qt uses std::thread to update QPlainTextEdit

Two, part of the code explanation

1. Start function

The following is the startup function of the entire function thread, because some things in the interface are used, some types need to be registered, and they are also run separately

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. Thread function

The static function is used here, and the data refresh thread also sends a signal to notify the main interface to update the content, and also uses the signal slot mechanism.

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("再次发送");
}

3. Code snippet

1. Main function

The main function here sets up a window using the Fusion style

#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 source file

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

Four, TCP related explanation

Here are some responses that are processed when a new connection comes. I only made one-to-one connection communication here, and did not consider communicating with a certain client. Please pay attention here.

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

This is where data is written to the socket

void MainWindow::slotWriteToSocket(QString data)
{
    
    
    m_TcpSocket->write(data.toUtf8());
}

Guess you like

Origin blog.csdn.net/qq_43680827/article/details/130119521