Как обновить значения между PyQt5 Tabs, созданными как классы - PullRequest
2 голосов
/ 04 мая 2019

У меня есть 2 вкладки в PyQT5, созданные как отдельные классы.1 класс (вкладка) предназначен для загрузки файла Excel, второй - для установки правил удаления ненужных строк.Когда я загружаю файл, мне нужно отправить все заголовки в QComboBox на другой вкладке, чтобы я мог создавать правила.Не могу заставить это работать.

import sys
from PyQt5.QtWidgets import *
import pandas as pd


class BOMAppWindow(QDialog):
    def __init__(self):
        super().__init__()

        self.setGeometry(250, 150, 1400, 600)

        mainTabWidget = QTabWidget()     # --------- TABS UI ----------
        mainTabWidget.addTab(FileOpenTab(), "File Open")
        mainTabWidget.addTab(RowRemoveRulesTab(), "Row Delete Rules")

        mainVbox = QVBoxLayout()
        mainVbox.addWidget(mainTabWidget)

        self.setLayout(mainVbox)


df = pd.DataFrame()   # pandas dataframe as container for excel spreadsheet
header_list = []


class FileOpenTab(QDialog):
    def __init__(self):
        super().__init__()

        vbox = QVBoxLayout()
        h_top_box = QHBoxLayout()
        excel_load_button = QPushButton("Open Excel File")
        h_top_box.addWidget(excel_load_button)  # ---- Adding Widgets to HBox

        # ----------------  Adding Table Widget -----------

        self.excel_table = QTableWidget()

        vbox.addLayout(h_top_box)         #-----Create Vertical Box Layout
        vbox.addWidget(self.excel_table)
        self.setLayout(vbox)

        excel_load_button.clicked.connect(self.set_file_data)  
# ----------- Open Excel Button Clicked Event
        self.show()

    def file_path(self):       # -----------    file dialog box
        filter_excel_only = "Excel Files (*.xlsx)"
        filename = QFileDialog.getOpenFileName(self, 'Open Excel File', "", filter_excel_only)
        return filename[0]


    def set_file_data(self):                
        path_text = self.file_path()
        if path_text:
            global df
            df = pd.read_excel(path_text, na_filter=False)  
            self.post_dataframe(df)
            RowRemoveRulesTab().update_select_list()

    def post_dataframe(self, dataframe):
        column_count = dataframe.shape[1]
        row_count = dataframe.shape[0]
        self.excel_table.setColumnCount(column_count)
        self.excel_table.setRowCount(row_count)
        self.excel_table.setHorizontalHeaderLabels(list(dataframe.columns))

    def header_list(self):
        return list(df.columns)


class RowRemoveRulesTab(QDialog):
    def __init__(self):
        super().__init__()

        hbox = QHBoxLayout()
        groupBox1 = QGroupBox("Rule 1:")
        vbox1 = QVBoxLayout()

        self.rule1select = QComboBox()
        self.rule1select.addItems(FileOpenTab().header_list())

        vbox1.addWidget(self.rule1select)

        groupBox1.setLayout(vbox1)
        hbox.addWidget(groupBox1)

        self.setLayout(hbox)

        self.show()

    def update_select_list(self):
        self.rule1select.clear()
        self.rule1select.addItems(FileOpenTab().header_list())
        print(FileOpenTab().header_list())


app = QApplication(sys.argv)
bomAppWindow = BOMAppWindow()
bomAppWindow.show()
app.exec()

Мне нужна последняя функция на второй вкладке (или любой другой способ ее обработки) update_select_list (self): обновить QComboBox списком заголовков из файла Excel, загруженного первымКласс FileOpenTab.Теперь QComboBox остается пустым после загрузки файла.

1 Ответ

1 голос
/ 04 мая 2019

Ключевым моментом вашей проблемы является то, что вы предполагаете, что каждый раз, когда вы выполняете FileOpenTab (), он всегда будет одним и тем же виджетом, но это не так.То же самое касается RowRemoveRulesTab.Вместо этого вы должны сохранить объект в переменной и повторно использовать его.

С другой стороны, у вас есть проблемы с дизайном, в этом случае вы должны использовать Принцип единой ответственности где это указывает на то, что каждый класс имеет функцию и должен предоставлять методы для доступа других объектов к информации, в Qt / PyQt самый простой способ передачи информации - через сигналы, в этом случае, когда датафрейм загружен, будет испущен сигналс новыми заголовками, и этот сигнал должен быть подключен к методу другого класса, чтобы он обновлял информацию QComboBox.

from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd


class FileOpenTab(QtWidgets.QWidget):
    headersChanged = QtCore.pyqtSignal(list)

    def __init__(self, parent=None):
        super(FileOpenTab, self).__init__(parent)

        excel_load_button = QtWidgets.QPushButton(
            "Open Excel File", clicked=self.load_file
        )
        self.excel_table = QtWidgets.QTableWidget()

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(excel_load_button)
        lay.addWidget(self.excel_table)

    @QtCore.pyqtSlot()
    def load_file(self):
        filter_excel_only = "Excel Files (*.xlsx)"
        filename, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Open Excel File", "", filter_excel_only
        )
        if filename:
            df = pd.read_excel(filename, na_filter=False)
            self.fill_table(df)

    def fill_table(self, dataframe):
        row_count, column_count = dataframe.shape
        self.excel_table.setColumnCount(column_count)
        self.excel_table.setRowCount(row_count)
        headers = list(dataframe.columns)
        self.excel_table.setHorizontalHeaderLabels(headers)
        self.headersChanged.emit(headers)


class RowRemoveRulesTab(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(RowRemoveRulesTab, self).__init__(parent)

        self.rule_select = QtWidgets.QComboBox()
        group_box = QtWidgets.QGroupBox("Rule 1:")

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.rule_select)
        group_box.setLayout(vbox)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(group_box)

    @QtCore.pyqtSlot(list)
    def update_items(self, items):
        self.rule_select.clear()
        self.rule_select.addItems(items)


class BOMAppWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(BOMAppWindow, self).__init__(parent)

        file_open_tab = FileOpenTab()
        row_remove_rules_tab = RowRemoveRulesTab()

        file_open_tab.headersChanged.connect(row_remove_rules_tab.update_items)

        mainTabWidget = QtWidgets.QTabWidget()
        mainTabWidget.addTab(file_open_tab, "File Open")
        mainTabWidget.addTab(row_remove_rules_tab, "Row Delete Rules")

        self.setCentralWidget(mainTabWidget)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = BOMAppWindow()
    w.show()
    sys.exit(app.exec_())
...