Pyside2中子進程的啓動與關閉

Pyside2是Qt框架的Python實現,藉着Python的大熱,對推廣Qt框架也是很好的推動,Qt對線程有專門的類QThread,但是在C++下的子線程處理用在Pyside2中雖然能正常退出程序,但是返回的code始終不是0。所以採用信號告知運行結束的方式進行處理。

C++線程處理:

Ui_process爲用戶操作處理類,將用戶操作轉給不同的類處理。在這裏有File_process、Track_process及各自對應的子線程。

#ifndef UI_PROCESS_H
#define UI_PROCESS_H

#include <QObject>
#include <QThread>

class File_process;
class Track_process;
class Track_data;

class Ui_process : public QObject
{
    Q_OBJECT
public:
    explicit Ui_process(QObject *parent = nullptr);
    ~Ui_process();

    void get_filter_conditions(QMap<QString, QVariant>* filter, QList<Track_data* >* list);

public slots:
    void sl_open_files();
    void sl_split_data_to_files();
    void sl_exit_application();

signals:
    void si_open_files(QStringList files_name);

    void si_split_data_to_files(QStringList files_name);

    void si_send_track_to_model(Track_data* data);

    void si_clear_model_();

    void si_send_filter_and_track_to_process(QMap<QString, QVariant>* filter,
                                             QList<Track_data* >* list);

    void si_updte_model_by_filter(int row, bool flag);

private:
    void init_connects();

    /***************************************************************************
     @Date     2021-05-23
     @Author   qiaowei
     @Contact  [email protected]
     @Version  1.0
     @Brief    Create a sub thread
     @Param    thread sub thread
     @Param    process pointer moved into sub thread
    ***************************************************************************/
    void start_sub_thread(QThread& thread, QObject* process);

private:
    // 文件處理類及對應子線程
    File_process* file_process_;
    QThread file_thread_;

    // 航跡處理類及對應子線程
    Track_process* track_process_;
    QThread track_thread_;

};

#endif // UI_PROCESS_H

Ui_process類實現:

#include <QApplication>
#include <QFileDialog>
#include <QtDebug>
#include <QMetaType>
#include "ui_process.h"
#include "file_process.h"
#include "track_process.h"
#include "../data_modules/track_data.h"

Ui_process::Ui_process(QObject *parent)
    : QObject(parent)
    , file_process_(new File_process())
    , track_process_(new Track_process())
{
    init_connects();
}

Ui_process::~Ui_process()
{
    if ((nullptr != track_process_)
            && (thread() == track_process_->thread())) {
        delete track_process_;
        track_process_ = nullptr;
    }

    track_thread_.quit();
    track_thread_.wait();

    if ((nullptr != file_process_)
            && (thread() == file_process_->thread())) {
        delete file_process_;
        file_process_ = nullptr;
    }

    file_thread_.quit();
    file_thread_.wait();
}

void Ui_process::get_filter_conditions(QMap<QString, QVariant> *filter, QList<Track_data *> *list)
{
    start_sub_thread(track_thread_, track_process_);

    emit si_send_filter_and_track_to_process(filter, list);
}

void Ui_process::sl_open_files()
{
    QStringList files_list = QFileDialog::getOpenFileNames();

    if ( !files_list.isEmpty()) {
        emit si_clear_model_();

        start_sub_thread(file_thread_, file_process_);

        emit si_open_files(files_list);
    }
}

void Ui_process::sl_split_data_to_files()
{
    QStringList files_list = QFileDialog::getOpenFileNames();

    if ( !files_list.isEmpty()) {
        start_sub_thread(file_thread_, file_process_);

        emit si_split_data_to_files(files_list);
    }
}

void Ui_process::sl_exit_application()
{
    QApplication::closeAllWindows();
}

void Ui_process::init_connects()
{
    connect(this, &Ui_process::si_split_data_to_files,
            file_process_, &File_process::sl_split_data_to_files);

    connect(this, &Ui_process::si_send_filter_and_track_to_process,
            track_process_, &Track_process::sl_filter_track_data);

    connect(this, &Ui_process::si_open_files,
            file_process_, &File_process::sl_open_files_to_show);

    connect(file_process_, &File_process::si_send_track_to_model,
            this, &Ui_process::si_send_track_to_model);

    connect(track_process_, &Track_process::si_update_track_by_filter,
            this, &Ui_process::si_updte_model_by_filter);
}

void Ui_process::start_sub_thread(QThread &thread, QObject *process)
{
    if ( !thread.isRunning()) {
        if (nullptr != process) {
            process->moveToThread(&thread);

            connect(&thread, &QThread::finished, process, &QObject::deleteLater);

            thread.start();
        }
    }
}

在析構函數中對子線程進行的比對,當線程不爲空指針且在主線程中,說明子線程未啓動,直接delete;反之,子線程已啓動,使用quit,wait方法進行關閉處理。

Python處理:

在UiProcess類中定義關閉子線程函數sl_stop_sub_thread(self, code: int),當在子線程運行的函數結束時,發射結束信號,調用sl_stop_sub_thread(self, code: int)

# !/usr/bin/env python
# encoding: utf-8
# @File    : ui_process_module.py
# @Time    : 2021/5/17
# @Author  : qiaowei
# @Version : 1.0
# @Email   : [email protected]
# @License : (C) Copyright 2013-2021
# @Brief   :


import ctypes
from PySide2.QtCore import QObject
from PySide2.QtCore import QThread
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QFileDialog
from PySide2.QtCore import Slot
from PySide2.QtCore import Signal
from process_package.data_process_module import DataProcess


class UiProcess(QObject):
    def __init__(self):
        super(UiProcess, self).__init__()
        # 在構造函數中創建變量對象__data_process,__thread,在私有函數__instance中實例化
        self.__data_process = None
        self.__thread = None

        self.__instance()
        self.__connect()


    @Slot()
    def sl_open_track_files(self):
        files = QFileDialog.getOpenFileNames()[0]
        if 0 != len(files):
            pass


    @Slot()
    def sl_split_data_to_files(self):
        """
        打開文件,將文件內容按條件保存到不同的文件中

        :return: None
        """
        files = QFileDialog.getOpenFileNames()[0]
        # 選取文件數量不爲0
        if 0 != len(files):
            if self.__setup_sub_thread(self.__thread, self.__data_process):
                self.si_split_data_to_files.emit(files)


    @Slot()
    def sl_quit_application(self):
        """
        Slot function, quit application

        :return: None
        """
        QApplication.closeAllWindows()


    @Slot(int)
    def sl_stop_sub_thread(self, code: int):
        """
        根據標誌位關閉子線程

        :param code: 子線程標誌位。0爲__thread

        :return: None
        """
        if 0 == code:
            self.__thread.exit()


    def __instance(self):
        self.__data_process = DataProcess()
        self.__thread = QThread()


    def __connect(self):
        # 打開文件列表,將文件的數據根據條件保存到不同文件中
        self.si_split_data_to_files.connect(self.__data_process.sl_split_data_to_files)
        # 子線程的任務結束後調用線程關閉函數
        self.__data_process.si_stop_sub_thread.connect(self.sl_stop_sub_thread)


    def __setup_sub_thread(self, thread: QThread, process: QObject):
        """
        啓動子線程

        :param thread: 要啓動的子線程
        :param process: 遷移到子線程中的變量

        :return: True 子線程正常啓動;False 子線程啓動失敗
        """
        if not thread.isRunning():
            process.moveToThread(thread)
            thread.start()

            return True

        return False

    # Signal
    # 打開文件,讀取數據,顯示到Model/View
    si_open_files = Signal(list)

    # 打開文件,讀取數據,將數據根據條件保存到不同文件中
    si_split_data_to_files = Signal(list)

遷入子線程的類,sl_split_data_to_files(self, file_list: list)函數在運行結束前發射結束信號

# !/usr/bin/env python
# encoding: utf-8
# @File    : data_process_module.py
# @Time    : 2021/5/17
# @Author  : qiaowei
# @Version : 1.0
# @Email   : [email protected]
# @License : (C) Copyright 2013-2021
# @Brief   : 處理數據類
# @History : 20210521 添加sl_split_data_to_files函數


from PySide2.QtCore import QObject
from PySide2.QtCore import QDateTime
from PySide2.QtCore import QFile
from PySide2.QtCore import QIODevice
from PySide2.QtCore import QTextStream
from PySide2.QtCore import Slot
from PySide2.QtCore import Signal
from data_module.constant_module import SYS_RECV_PROCESS


class DataProcess(QObject):
    def __init__(self):
        super(DataProcess, self).__init__()


    def sl_open_files_to_show_track(self, file_list: list):
        if 0 == len(file_list):
            return
        


    @Slot(list)
    def sl_split_data_to_files(self, file_list: list):
        """
        根據傳入的文件名列表。依次讀取每個文件中數據並按設置保存到新建的文件中

        :param file_list: 打開的文件名列表

        :return: None
        """
        if 0 == len(file_list):
            return

        time = QDateTime().currentDateTime().toString()

        # 創建保存process數據的文檔
        save_process_file = QFile(file_list[0].replace('.log', '_PROCESS_.log'))
        # save_process_file = QFile('process.log')

        try:
            for name in file_list:
                file = QFile(name)
                if not file.exists():
                    return
                if not file.open(QIODevice.ReadOnly | QIODevice.Text):
                    return

                in_stream = QTextStream(file)
                # in_stream.setCodec('utf-8')
                in_stream.setAutoDetectUnicode(True)

                # 續寫文件模式打開新創建的文件
                if save_process_file.open(QFile.WriteOnly | QFile.Truncate | QFile.Append):
                    out_stream_process = QTextStream(save_process_file)

                # 按行遍歷文件,將符合要求的數據保存到save_process_file文件中
                while not in_stream.atEnd():
                    content = in_stream.readLine()
                    if SYS_RECV_PROCESS in content:
                        out_stream_process << content.replace('sysRecv 1 process', '') << '\n'

                file.close()
                save_process_file.close()
        except IOError as io_error:
            print('File error:' + str(io_error))
        finally:
            if file.isOpen():
                file.close()
            if save_process_file.isOpen():
                save_process_file.close()
            # 發射退出子線程的信號
            self.si_stop_sub_thread.emit(0)


    # 信號,線程完成任務後,向調用線程的對象發射信號
    si_stop_sub_thread = Signal(int)

運行結果如下:

這是目前我能想到的處理方式,如有更好的,希望不吝賜教

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章