将更改数据从选项卡传递到选项卡

时间:2014-12-14 13:13:14

标签: python qt pyqt pyside pyqtgraph

我正在尝试使用两个标签构建程序。在Tab1中,我将图像中的点坐标(x,y)选择为值self.a。除了图像,我还在Tab1中有一些其他UI(即表格)。现在,我想将值self.a传递给Tab2(不继承所有其他东西)。请记住,单击新点时可以不断更新self.a。

from PySide import QtGui, QtCore
import pandas as pd
import pyqtgraph as pg
import numpy as np
QVariant = lambda value=None: value


class Widget(QtGui.QWidget):

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

        v_global_layout = QtGui.QVBoxLayout()
        v_global_layout.addWidget(TabDialog())
        v_global_layout.setAlignment(QtCore.Qt.AlignTop)

        self.setLayout(v_global_layout)


class TabDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        tab_widget = QtGui.QTabWidget()

        tab_widget.addTab(Tab1(), "1")
        tab_widget.addTab(Tab2(), "2")

        main_layout = QtGui.QVBoxLayout()
        main_layout.addWidget(tab_widget)
        self.setLayout(main_layout)


class Tab1(QtGui.QTabWidget):
    def __init__(self):
        super().__init__()
        layout = QtGui.QHBoxLayout()
        self.fig = pg.PlotWidget(name='Example: Selecting scatter points')

        self.plot_area = self.fig.plotItem
        self.a = pg.ScatterPlotItem(pxMode=False)
        spots = []
        for i in range(10):
            for j in range(10):
                spots.append({'pos': (1*i, 1*j), 'size': 1, 'pen': {'color': 'w', 'width': 2},
                              'brush': pg.intColor(i*10+j, 100)})
        self.a.addPoints(spots)

        self.plot_area.addItem(self.a)

        self.a.dataModel = DataFrameModel()
        self.a.dataTable = QtGui.QTableView()
        self.a.dataTable.setModel(self.a.dataModel)

        layout.addWidget(self.a.dataTable)
        layout.addWidget(self.fig)
        self.setLayout(layout)

        self.a.array = np.zeros((0, 2))

        def clicked(self, points):
            for p in points:
                p.setPen('b', width=2)
                position = p.viewPos()
                self.array = np.append(self.array, np.array([[position.x(), position.y()]]), axis=0)
            c = range(len(self.array))
            c = list(map(str, c))
            self.dataModel.signalUpdate(self.array, columns=c)
            self.dataModel.printValues() # also: print(self.array)
        self.a.sigClicked.connect(clicked)


class Tab2(QtGui.QTabWidget):
    def __init__(self):
        super().__init__()
        layout = QtGui.QHBoxLayout()

        ##### Here I want to use Tab1.a and not inherit all the other stuff(layout) #####
        #print("values = ", Tab1.a.array) # a should change when a new point is selected in Tab1
        #####################################
        self.setLayout(layout)


class DataFrameModel(QtCore.QAbstractTableModel):
    """ data model for a DataFrame class """
    def __init__(self):
        super(DataFrameModel, self).__init__()
        self.df = pd.DataFrame()

    def signalUpdate(self, dataIn, columns):
        self.df = pd.DataFrame(dataIn, columns)
        self.layoutChanged.emit()

    def printValues(self):
        print("DataFrame values:\n", self.df.values)

    def values(self):
        return self.df.values

    #------------- table display functions -----------------
    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role != QtCore.Qt.DisplayRole:
            return QVariant()

        if orientation == QtCore.Qt.Horizontal:
            try:
                return self.df.columns.tolist()[section]
            except (IndexError, ):
                return QVariant()
        elif orientation == QtCore.Qt.Vertical:
            try:
                # return self.df.index.tolist()
                return self.df.index.tolist()[section]
            except (IndexError, ):
                return QVariant()

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role != QtCore.Qt.DisplayRole:
            return QVariant()

        if not index.isValid():
            return QVariant()
        return QVariant(str(self.df.ix[index.row(), index.column()]))

    def rowCount(self, index=QtCore.QModelIndex()):
        return self.df.shape[0]

    def columnCount(self, index=QtCore.QModelIndex()):
        return self.df.shape[1]


if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)

    main_window = Widget()
    main_window.setGeometry(100, 100, 640, 480)
    main_window.show()

    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:1)

在这种情况下,您只需使用信号即可完成工作。

在这里,您尝试像静态属性一样访问Tab1.a,而不是静态属性。理想情况下,我们应该尝试解耦​​不同的小部件。我们应该尽量将它们之间的依赖性保持在最低限度,并将它们中的每一个视为无知并且彼此不知道。 TabDialog可以是了解每个小部件及其之间的连接的人(在这种情况下,Tab1Tab2)。因此,TabDialog可以负责这些小部件之间的通信。

为此,我们将两个标签作为TabDialog类的属性,如下所示:

# Have the tabs as this dialog's class properties
self.tab1 = Tab1(image)
self.tab2 = Tab2()

tab_widget.addTab(self.tab1, "1")
tab_widget.addTab(self.tab2, "2")

在类Tab2中,我们假设您要使用Tab1.a映射的值为points_from_tab1_a

class Tab2(QtGui.QTabWidget):
    def __init__(self):
        super().__init__()
        layout = QtGui.QHBoxLayout()

        self.points_from_tab1_a = []
        self.setLayout(layout)

现在,在TabDialog中,我们将sigClicked的{​​{1}}信号与更新tab1.a的方法相关联:

tab2.points_from_tab1_a

这应该可以解决问题。因此,在完成这些更改后,您的完整代码段将如下所示:

self.tab1.a.sigClicked.connect(self.pointChanged)

def pointChanged(self, points):
    tab2.points_from_tab1_a = tab1.a

使用信号和插槽概念,随意更改它以满足您的需求。希望这很有用。