首页 > 解决方案 > 将 Qt Widget 引用到其他文件中的其他 Python 类中

问题描述

我有两个不同的 Python 文件。一个具有 GUI 详细信息,另一个具有使用 Watchdog API 监视文件夹的代码

图形用户界面文件:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'csvExcel.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import os
from Main_File import Watcher, DataFrameTableWidget


class Ui_MainWindow(object):

    def __init__(self):

        self.file_Name = None

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.start_button = QtWidgets.QPushButton(self.centralwidget)
        self.start_button.setAutoFillBackground(False)
        self.start_button.setAutoDefault(False)
        self.start_button.setDefault(False)
        self.start_button.setFlat(False)
        self.start_button.setObjectName("start_button")
        self.start_button.clicked.connect(lambda: self.start_button_click())
        self.gridLayout_2.addWidget(self.start_button, 0, 0, 1, 1)
        self.Br_button = QtWidgets.QPushButton(self.centralwidget)
        self.Br_button.setObjectName("Br_button")
        self.Br_button.clicked.connect(lambda: self.browse_button())
        self.gridLayout_2.addWidget(self.Br_button, 2, 0, 1, 1)
        self.label = QtWidgets.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.gridLayout_2.addWidget(self.label, 2, 1, 1, 1, QtCore.Qt.AlignHCenter)
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        self.gridLayout_2.addWidget(self.tableWidget, 3, 0, 1, 2)
        self.gridLayout.addLayout(self.gridLayout_2, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.start_button.setToolTip(_translate("MainWindow", "Start The Program"))
        self.start_button.setText(_translate("MainWindow", "Start"))
        self.Br_button.setToolTip(_translate("MainWindow", "Browse the File Location to Watch on"))
        self.Br_button.setText(_translate("MainWindow", "Browse"))
        self.label.setText(_translate("MainWindow", "Sensor CSV To Excel"))

    def start_button_click(self):
        watcher = Watcher(self.file_Name)
        if self.start_button.text() == "Start":
            self.start_button.setText("Stop")
            w = DataFrameTableWidget(self.tableWidget)
            watcher.emitter.newDataFrameSignal.connect(w.append_dataframe)
            watcher.run()
        elif self.start_button.text() == "Stop":
            self.start_button.setText("Start")
            watcher.stop_watcher()

    def browse_button(self):
        self.file_Name = QtWidgets.QFileDialog.getExistingDirectory(None, 'Open working directory', os.getcwd(), QtWidgets.QFileDialog.ShowDirsOnly)
        print(self.file_Name)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())

具有看门狗实现的 Python 代码文件

import os
import pandas as pd
from PyQt5 import QtCore, QtWidgets
from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer
import time
from Append_Function import append_df_to_excel


class Emitter(QtCore.QObject):
    newDataFrameSignal = QtCore.pyqtSignal(pd.DataFrame)


class Watcher:
    def __init__(self, filename):
        self.watch_dir = os.getcwd()
        self.directory_to_watch = os.path.join(self.watch_dir, filename)
        self.emitter = Emitter()
        self.observer = Observer()
        self.event_handler = Handler(
            emitter=self.emitter,
            patterns=["*.CSV"],
            ignore_patterns=["*.tmp"],
            ignore_directories=True
        )

    def run(self):
        self.observer.schedule(self.event_handler, self.directory_to_watch, recursive=False)
        self.observer.start()

    def stop_watcher(self):
        self.observer.stop()


class Handler(PatternMatchingEventHandler):
    def __init__(self, *args, emitter=None, **kwargs):
        super(Handler, self).__init__(*args, **kwargs)
        self._emitter = emitter
        self.file_name = time.strftime("%Y%m%d-%H%M%S")+".xlsx"

    def on_any_event(self, event):

        if event.is_directory:
            return None
        elif event.event_type == 'created':
            # Take any action here when a file is first created.
            print("Received created event - %s." % event.src_path)

            if os.path.isfile(os.path.join(os.getcwd(), self.file_name)):

                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=1, index_col=0))
                df = pd.read_csv(event.src_path, header=1)

            else:
                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=0, index_col=0))
                df = pd.read_csv(event.src_path, header=0)

            self._emitter.newDataFrameSignal.emit(df.copy())
            df.set_index(df.columns.values.tolist()[0], inplace=True)

        elif event.event_type == 'modified':
            print("Modified created event - %s." % event.src_path)

            if os.path.isfile(os.path.join(os.getcwd(), self.file_name)):

                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=1, index_col=0))
                df = pd.read_csv(event.src_path, header=1)

            else:

                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=0, index_col=0))
                df = pd.read_csv(event.src_path, header=0)

            self._emitter.newDataFrameSignal.emit(df.copy())
            df.set_index(df.columns.values.tolist()[0], inplace=True)


class DataFrameTableWidget(QtWidgets.QTableWidget):

    @QtCore.pyqtSlot(pd.DataFrame)
    def append_dataframe(self, df):
        df = df.copy()
        if df.columns.size > self.columnCount():
            self.setColumnCount(df.columns.size)
        r = self.rowCount()
        self.insertRow(r)
        for c, column in enumerate(df):
            it = QtWidgets.QTableWidgetItem(column)

            self.setItem(r, c, it)
        i = self.rowCount()
        for r, row in df.iterrows():
            self.insertRow(self.rowCount())
            for c, (column, value) in enumerate(row.iteritems()):
                it = QtWidgets.QTableWidgetItem(str(value))
                self.setItem(i+r, c, it)

在此文件中,您可以看到我使用了一个函数“Append_Function”,它实际上是将数据附加到 Excel 文件中(如果需要,我将编辑以添加函数代码)。

我的问题

在 Watchdog 实现文件中,您可以看到该 DataFrameTableWidget 类中有一个自定义 Pyslot。生成数据框时它会激活。相应地,来自数据框的数据显示在 QWidget 表中,因为 DataFrameTableWidget 类继承了 QTableWidget。

现在你可以看到我已经为我的应用程序制作了一个单独的 GUI,它有一个表格小部件。我希望将 pandas 数据框中的数据显示到我的 GUI 表小部件中,而不是显示到我的 WatchDog 实现文件中的 DataFrameTableWidget 类继承的 QTableWidget 中。

我在想以某种方式使用 GUI 中的 QTableWidget 初始化 DataFrameTableWidget 类可能会起作用。但我不确定我是否可以将 QTableWidget 传递给 DataFrameTaleWidget 类初始化(即init)函数,以便我可以将我的 GUI 表小部件引用到我的看门狗实现文件中。

我尽力在这里弄清楚我的问题。但是,如果在理解时仍然遇到问题,我将编辑并尝试使其更清晰。

谢谢!

更新代码版本

csvExcelGUI.py

from PyQt5 import QtCore, QtGui, QtWidgets
import os
from Main_File import Watcher, DataFrameTableWidget


class Ui_MainWindow(object):

    def __init__(self):

        self.file_Name = None

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.start_button = QtWidgets.QPushButton(self.centralwidget)
        self.start_button.setAutoFillBackground(False)
        self.start_button.setAutoDefault(False)
        self.start_button.setDefault(False)
        self.start_button.setFlat(False)
        self.start_button.setObjectName("start_button")
        #self.start_button.clicked.connect(lambda: self.start_button_click())
        self.gridLayout_2.addWidget(self.start_button, 0, 0, 1, 1)
        self.Br_button = QtWidgets.QPushButton(self.centralwidget)
        self.Br_button.setObjectName("Br_button")
        self.Br_button.clicked.connect(lambda: self.browse_button())
        self.gridLayout_2.addWidget(self.Br_button, 2, 0, 1, 1)
        self.label = QtWidgets.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.gridLayout_2.addWidget(self.label, 2, 1, 1, 1, QtCore.Qt.AlignHCenter)
        #self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget = DataFrameTableWidget(self.centralwidget)
        self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        self.gridLayout_2.addWidget(self.tableWidget, 3, 0, 1, 2)
        self.gridLayout.addLayout(self.gridLayout_2, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.start_button.setToolTip(_translate("MainWindow", "Start The Program"))
        self.start_button.setText(_translate("MainWindow", "Start"))
        self.Br_button.setToolTip(_translate("MainWindow", "Browse the File Location to Watch on"))
        self.Br_button.setText(_translate("MainWindow", "Browse"))
        self.label.setText(_translate("MainWindow", "Sensor CSV To Excel"))


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.start_button.clicked.connect(self.start_button_click)
        self.watcher = Watcher()
        self.watcher.emitter.newDataFrameSignal.connect(self.tableWidget.append_dataframe)
        self.file_Name = ""

    def start_button_click(self):
        self.watcher.set_filename(self.file_Name)
        if self.start_button.text() == "Start":
            self.start_button.setText("Stop")
            self.watcher.run()
        elif self.start_button.text() == "Stop":
            self.start_button.setText("Start")
            self.watcher.stop_watcher()

    def browse_button(self):
        self.file_Name = QtWidgets.QFileDialog.getExistingDirectory(None, 'Open working directory', os.getcwd(), QtWidgets.QFileDialog.ShowDirsOnly)
        print(self.file_Name)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    # MainWindow = QtWidgets.QMainWindow()
    # ui = Ui_MainWindow()
    # ui.setupUi(MainWindow)
    # MainWindow.show()
    w = MainWindow()
    w.show()

    sys.exit(app.exec_())

Main_File.py

import os
import pandas as pd
from PyQt5 import QtCore, QtWidgets
from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer
import time
from Append_Function import append_df_to_excel


class Emitter(QtCore.QObject):
    newDataFrameSignal = QtCore.pyqtSignal(pd.DataFrame)


class Watcher:
    def __init__(self):
        self.watch_dir = os.getcwd()
        self.directory_to_watch = None
        self.emitter = Emitter()
        self.observer = Observer()
        self.event_handler = Handler(
            emitter=self.emitter,
            patterns=["*.CSV"],
            ignore_patterns=["*.tmp"],
            ignore_directories=True
        )

    def set_filename(self, filename):
        self.directory_to_watch = os.path.join(self.watch_dir, filename)

    def run(self):
        self.observer.schedule(self.event_handler, self.directory_to_watch, recursive=False)
        self.observer.start()

    def stop_watcher(self):
        self.observer.stop()


class Handler(PatternMatchingEventHandler):
    def __init__(self, *args, emitter=None, **kwargs):
        super(Handler, self).__init__(*args, **kwargs)
        self._emitter = emitter
        self.file_name = time.strftime("%Y%m%d-%H%M%S")+".xlsx"

    def on_any_event(self, event):

        if event.is_directory:
            return None
        elif event.event_type == 'created':
            # Take any action here when a file is first created.
            print("Received created event - %s." % event.src_path)

            if os.path.isfile(os.path.join(os.getcwd(), self.file_name)):

                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=1, index_col=0))
                df = pd.read_csv(event.src_path, header=1)

            else:
                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=0, index_col=0))
                df = pd.read_csv(event.src_path, header=0)

            self._emitter.newDataFrameSignal.emit(df.copy())
            df.set_index(df.columns.values.tolist()[0], inplace=True)

        elif event.event_type == 'modified':
            print("Modified created event - %s." % event.src_path)

            if os.path.isfile(os.path.join(os.getcwd(), self.file_name)):

                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=1, index_col=0))
                df = pd.read_csv(event.src_path, header=1)

            else:

                append_df_to_excel(os.path.join(os.getcwd(), self.file_name),
                                   pd.read_csv(event.src_path, header=0, index_col=0))
                df = pd.read_csv(event.src_path, header=0)

            self._emitter.newDataFrameSignal.emit(df.copy())
            df.set_index(df.columns.values.tolist()[0], inplace=True)


class DataFrameTableWidget(QtWidgets.QTableWidget):

    @QtCore.pyqtSlot(pd.DataFrame)
    def append_dataframe(self, df):
        df = df.copy()
        if df.columns.size > self.columnCount():
            self.setColumnCount(df.columns.size)
        r = self.rowCount()
        self.insertRow(r)
        for c, column in enumerate(df):
            it = QtWidgets.QTableWidgetItem(column)

            self.setItem(r, c, it)
        i = self.rowCount()
        for r, row in df.iterrows():
            self.insertRow(self.rowCount())
            for c, (column, value) in enumerate(row.iteritems()):
                it = QtWidgets.QTableWidgetItem(str(value))
                self.setItem(i+r, c, it)

标签: pythonpyqtpyqt5

解决方案


您的代码有以下错误:

  • 使用该行:w = DataFrameTableWidget(self.tableWidget),您只是指出 Data Frame qTableWidget 是 QTableWidget 的子级(即,它将被放置在小部件内),并且不会替换它。

  • watcher = Watcher(self.file_Name)是一个局部变量,当它执行完 start_button_click 时将被删除。

假设您的代码在添加 GUI 之前可以工作,我将进行以下修改:

  1. 更改self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)self.tableWidget = DataFrameTableWidget(self.centralwidget),如果您有 .ui,它将教您如何使用如何通过 Qt Designer 设置新的小部件。
  2. 实现一个 set_filename 方法,这样就不需要在每次按下按钮时都创建一个新的 Watcher 对象。
  3. 使对象成为类的对象观察者成员。

Main_File.py

# ...

class Watcher:
    def __init__(self):
        self.watch_dir = os.getcwd()
        self.emitter = Emitter()
        self.observer = Observer()
        self.event_handler = Handler(
            emitter=self.emitter,
            patterns=["*.CSV"],
            ignore_patterns=["*.tmp"],
            ignore_directories=True
        )
    def set_filename(self, filename):
        self.directory_to_watch = os.path.join(self.watch_dir, filename)

    # ...

主文件

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'csvExcel.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import os
from Main_File import Watcher, DataFrameTableWidget


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.start_button = QtWidgets.QPushButton(self.centralwidget)
        self.start_button.setAutoFillBackground(False)
        self.start_button.setAutoDefault(False)
        self.start_button.setDefault(False)
        self.start_button.setFlat(False)
        self.start_button.setObjectName("start_button")
        self.gridLayout_2.addWidget(self.start_button, 0, 0, 1, 1)
        self.Br_button = QtWidgets.QPushButton(self.centralwidget)
        self.Br_button.setObjectName("Br_button")
        self.Br_button.clicked.connect(lambda: self.browse_button())
        self.gridLayout_2.addWidget(self.Br_button, 2, 0, 1, 1)
        self.label = QtWidgets.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.gridLayout_2.addWidget(self.label, 2, 1, 1, 1, QtCore.Qt.AlignHCenter)
        self.tableWidget = DataFrameTableWidget(self.centralwidget)
        self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        self.gridLayout_2.addWidget(self.tableWidget, 3, 0, 1, 2)
        self.gridLayout.addLayout(self.gridLayout_2, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.start_button.setToolTip(_translate("MainWindow", "Start The Program"))
        self.start_button.setText(_translate("MainWindow", "Start"))
        self.Br_button.setToolTip(_translate("MainWindow", "Browse the File Location to Watch on"))
        self.Br_button.setText(_translate("MainWindow", "Browse"))
        self.label.setText(_translate("MainWindow", "Sensor CSV To Excel"))


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.start_button.clicked.connect(self.start_button_click)
        self.watcher = Watcher()
        self.watcher.emitter.newDataFrameSignal.connect(self.tableWidget.append_dataframe)
        self.file_Name = ""

    def start_button_click(self):
        self.watcher.set_filename(self.file_Name)
        if self.start_button.text() == "Start":
            self.start_button.setText("Stop")
            self.watcher.run()
        elif self.start_button.text() == "Stop":
            self.start_button.setText("Start")
            self.watcher.stop_watcher()

    def browse_button(self):
        self.file_Name = QtWidgets.QFileDialog.getExistingDirectory(None, 'Open working directory', os.getcwd(), QtWidgets.QFileDialog.ShowDirsOnly)
        print(self.file_Name)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

推荐阅读