如何在 PyQt5 中的文件对话框后启动 table 的交互式视图?

How to launch an interactive view of a table after file dialog in PyQt5?

使用 PyQt5,我制作了两个小部件。第一个小部件是 select 文件的用户提示,带有确认 selected 文件路径的警报。 BackEnd读取selected数据文件并处理数据;为了 MWE,dataBackEnd 中定义为二维数组,selected 文件仅用于获取文件路径。第二个小部件加载 table 的视图供用户查看。 (它还与这个问题无关,但我的用例是我想让用户通过单击特定单元格来 select rows/columns。)我可以得到第二个小部件可以自己工作,但是如果我首先加载第一个小部件,table 不会加载。 我认为我没有遗漏任何 .close().exec_()方法,所以我不确定为什么第二个小部件不会加载。这个错误的原因是什么,我该如何避免它?我在之前的尝试中尝试过使用 on_clicked() 方法,但我不确定如何将其应用于不同类型的 widgets/tables/etc 不相同。

下面的代码用于二维数组的 table 视图。

import sys
from PyQt5 import QtWidgets, QtGui, QtCore
import numpy as np

class BackEnd():

    def __init__(self):
        super().__init__()
        # ...
        nrows, ncols = 50, 10
        self.data = np.arange(nrows * ncols).reshape((nrows, ncols)).astype(str)

class TableModel(QtCore.QAbstractTableModel):

    """
    An instance of this class is created inside the constructor
    of the class 'TableWindow'.
    """

    def __init__(self, data):
        super(TableModel, self).__init__()
        self._data = data

    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            # See below for the nested-list data structure.
            # .row() indexes into the outer list,
            # .column() indexes into the sub-list
            return self._data[index.row()][index.column()]

    def rowCount(self, index):
        # The length of the outer list.
        return len(self._data)

    def columnCount(self, index):
        # The following takes the first sub-list, and returns
        # the length (only works if all rows are an equal length)
        return len(self._data[0])

class TableWindow(QtWidgets.QMainWindow):

    """
    This class is used to view the raw data file via gui.
    """

    def __init__(self, data):
        super().__init__()
        self.table = QtWidgets.QTableView()
        self.model = TableModel(data)
        self.table.setModel(self.model)
        self.setCentralWidget(self.table)
        self.setWindowTitle("Select 'row' if each student corresponds to a row; otherwise, select 'column'")

通过下面的 运行 代码片段,应该能够看到一个显示 table(第二个小部件)视图的弹出窗口。

back_end = BackEnd()

## initialize application
app = QtWidgets.QApplication(sys.argv)

## view data file
window = TableWindow(back_end.data.tolist())
window.show()

## exit application
sys.exit(app.exec_())

当尝试组合这两个小部件时,上面的代码片段应该被注释掉。下面的代码用于文件 selection 小部件(第一个小部件)。

class MainWindow(QtWidgets.QMainWindow):


    """
    This class contains all GUI methods.
    """

    def __init__(self):
        self._backend = BackEnd()
        self._fpath = None
        super().__init__()
        self.initialize_ui()

    @property
    def backend(self):
        return self._backend

    @property
    def fpath(self):
        return self._fpath

    def initialize_ui(self):
        self.select_input_data_file()
        self.verify_input_data_file()
        # self.close()
        self.interact_with_table()

    def select_input_data_file(self):
        dialog = QtWidgets.QFileDialog(
            self,
            "Select input file",
            "path",
            "",
            supportedSchemes=["file"],
            options=QtWidgets.QFileDialog.DontUseNativeDialog)
        fpath = dialog.getOpenFileName(None, 'Open file', '/home')[0]
        self._fpath = fpath
        # dialog.close()
        # dialog = None

    def verify_input_data_file(self):
        alert = QtWidgets.QMessageBox()
        alert.setText('The input filepath you selected is: \n{}'.format(self.fpath))
        alert.exec_()
        # alert.close()
        # alert = None

    def interact_with_table(self):
        window = TableWindow(self.backend.data.tolist())
        window.show()

下面的代码是我尝试让用户使用第一个小部件 select 一个文件(成功)然后显示数据 table(不成功)。

## initialize application
app = QtWidgets.QApplication(sys.argv)

## view data file
window = MainWindow()
window.show()

## exit application
sys.exit(app.exec_())

MainWindow.interact_with_table 中,TableWindow 小部件被分配给局部变量。当 interact_with_table returns 时,此变量超出范围并且 TableWindow 的引用计数变为零。这将导致 TableWindow 对象在下一个垃圾回收周期中被删除。一种解决方案是对 table window 进行持久引用,例如将其分配给 MainWindow 的实例变量,即

def interact_with_table(self):
    self.table_window = TableWindow(self.backend.data.tolist())
    self.table_window.show()