PyQt Ошибка отправки значений в другой класс - PullRequest
0 голосов
/ 20 мая 2018

в приведенном ниже коде я пытаюсь найти лучший способ обмена данными из класса «Data_Class» в класс «Tab_2».В частности, я пытаюсь получить значения из «Data_Class» в tab1, чтобы заполнить QLineEdit в tab2 при нажатии кнопок.Я пытался использовать сигналы и отправлять напрямую в класс "Tab_2", но лучшее, что я могу получить, это значения, которые нужно распечатать в "Tab_2", но не заполнить QLineEdit.
В классе "MainWindow", который я создаю иотделить данные, а затем внедрить «Data_Class» с помощью FlowLayout при отправке данных в «Data_Class» для создания кнопок, а также установить их значения, но теперь я не могу передать данные, отправленные в класс «Tab_2».
Кроме того, сигнал в «Data_Class» не работает, я просто оставил его в любом случае.
Кто-нибудь знает, что я должен делать, чтобы получить значения правильно, или есть какие-либо предложения?Благодарю.

import functools
import sys
from PyQt5.QtCore import pyqtSignal, QSize,  QRect, Qt, QPoint
from PyQt5.QtWidgets import QLineEdit, QPushButton,QVBoxLayout, QScrollArea, QWidget, \
    QApplication, QTabWidget, QStyle, QSizePolicy, QLayout


class Data_Class(QWidget):
    data_Signal = pyqtSignal(str)
    def __init__(self, item_num=None, item_data=None):
        super(Data_Class, self).__init__()
        self.tab_2 = Tab_2
        self.num = item_num
        self.dat = item_data
        self.setFixedWidth(150)
        self.layout = QVBoxLayout()
        self.btn = QPushButton()
        self.btn.setText(str(self.num))
        self.layout.addWidget(self.btn)
        self.setLayout(self.layout)
        self.btn_click = functools.partial(self.set_btns, btn_data=self.dat)
        self.btn.clicked.connect(self.btn_click)

    def set_btns(self, btn_data):
        print(btn_data)
        self.data_Signal.emit(btn_data)

class MainWindow(QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.resize(368,315)
        self.vbox = QVBoxLayout()
        self.tabWidget = QTabWidget()
        self.tabWidget.setTabPosition(QTabWidget.North)
        self.vbox.addWidget(self.tabWidget)
        self.tab1 = QWidget()
        self.tabWidget.addTab(self.tab1, ("tab1"))
        self.tab2 = QWidget()
        self.tabWidget.addTab(self.tab2, ("tab2"))
        self.layout1 = QVBoxLayout()
        self.layout2 = QVBoxLayout()
        self.tab1.setLayout(self.layout1)
        self.tab2.setLayout(self.layout2)
        self.scrollarea = QScrollArea(self)
        self.scrollarea.setWidgetResizable(True)
        self.widgets = QWidget()
        self.Layout = FlowLayout(self.widgets) ##############FlowLayout
        self.scrollarea.setWidget(self.widgets)
        self.layout1.addWidget(self.scrollarea)
        self.layout2.addWidget(Tab_2(self))
        self.setLayout(self.vbox)
        self.items =[]
        self.extract()

    def extract(self):
        mydict = {'num': 1, 'data': 'data1'},{'num': 2, 'data': 'data2'}, {'num': 3, 'data': 'data3'}, \
                 {'num': 4, 'data': 'data4'},{'num': 5, 'data': 'data5'},{'num': 6, 'data': 'data6'}, \
                 {'num': 7, 'data': 'data7'}, {'num': 8, 'data': 'data8'}, {'num': 9, 'data': 'data9'}, \
                 {'num': 10, 'data': 'data10'}, {'num': 11, 'data': 'data11'}, {'num': 12, 'data': 'data12'}
        self.items[:] = mydict
        for item in self.items:
            self.add_btns(item)

    def add_btns(self, item):
        layout = self.Layout ##################FlowLayout
        item_num = item['num']
        item_data = item['data']
        widget = Data_Class(item_num, item_data)
        layout.addWidget(widget)

class Tab_2(QWidget):
    def __init__(self, parent=None):
        super(Tab_2, self).__init__(parent)
        self.data_class = Data_Class
        self.vert_layout = QVBoxLayout(self)
        self.line_edit = QLineEdit()
        self.vert_layout.addWidget(self.line_edit)
        self.setLayout(self.vert_layout)
        self.data_class(self).data_Signal.connect(self.set_line_edit)

    def set_line_edit(self, btn_data):
        print(btn_data)
        self.line_edit.setText(btn_data)

class FlowLayout(QLayout):
    def __init__(self, parent=None, margin=-0, hspacing=-0, vspacing=-0):
        super(FlowLayout, self).__init__(parent)
        self._hspacing = hspacing
        self._vspacing = vspacing
        self._items = []
        self.setContentsMargins(margin, margin, margin, margin)

    def __del__(self):
        del self._items[:]

    def addItem(self, item):
        self._items.append(item)

    def horizontalSpacing(self):
        if self._hspacing >= 0:
            return self._hspacing
        else:
            return self.smartSpacing(
                QStyle.PM_LayoutHorizontalSpacing)

    def verticalSpacing(self):
        if self._vspacing >= 0:
            return self._vspacing
        else:
            return self.smartSpacing(
                QStyle.PM_LayoutVerticalSpacing)

    def count(self):
        return len(self._items)

    def itemAt(self, index):
        if 0 <= index < len(self._items):
            return self._items[index]

    def takeAt(self, index):
        if 0 <= index < len(self._items):
            return self._items.pop(index)

    def expandingDirections(self):
        return Qt.Orientations(0)

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return self.doLayout(QRect(0, 0, width, 0), True)

    def setGeometry(self, rect):
        super(FlowLayout, self).setGeometry(rect)
        self.doLayout(rect, False)

    def sizeHint(self):
        return self.minimumSize()

    def minimumSize(self):
        size = QSize()
        for item in self._items:
            size = size.expandedTo(item.minimumSize())
        left, top, right, bottom = self.getContentsMargins()
        size += QSize(left + right, top + bottom)
        return size

    def doLayout(self, rect, testonly):
        left, top, right, bottom = self.getContentsMargins()
        effective = rect.adjusted(+left, +top, -right, -bottom)
        x = effective.x()
        y = effective.y()
        lineheight = 0
        for item in self._items:
            widget = item.widget()
            hspace = self.horizontalSpacing()
            if hspace == -1:
                hspace = widget.style().layoutSpacing(
                    QSizePolicy.PushButton,
                    QSizePolicy.PushButton, Qt.Horizontal)
            vspace = self.verticalSpacing()
            if vspace == -1:
                vspace = widget.style().layoutSpacing(
                    QSizePolicy.PushButton,
                    QSizePolicy.PushButton, Qt.Vertical)
            nextX = x + item.sizeHint().width() + hspace
            if nextX - hspace > effective.right() and lineheight > 0:
                x = effective.x()
                y = y + lineheight + vspace
                nextX = x + item.sizeHint().width() + hspace
                lineheight = 0
            if not testonly:
                item.setGeometry(
                    QRect(QPoint(x, y), item.sizeHint()))
            x = nextX
            lineheight = max(lineheight, item.sizeHint().height())
        return y + lineheight - rect.y() + bottom

    def smartSpacing(self, pm):
        parent = self.parent()
        if parent is None:
            return -1
        elif parent.isWidgetType():
            return parent.style().pixelMetric(pm, None, parent)
        else:
            return parent.spacing()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = MainWindow()
    wnd.show()
    app.exec_()

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Ответ @ S.Ник неправильный, так как QWidget наследует от QObject и поэтому поддерживает сигналы.Давайте проверим это с помощью следующего кода:

import sys

from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QObject

if __name__ == '__main__':
    app = QApplication(sys.argv)
    obj = QWidget()
    assert(isinstance(obj, QObject))
    obj.show()
    sys.exit(app.exec_())

Ошибка вызвана плохой практикой программирования, например, в вашем коде вы видите следующее:

self.data_class = Data_Class
...
self.data_class(self).data_Signal.connect(self.set_line_edit)

Что эквивалентно:

Data_Class(self).some_xxxx

, если self было бы Data_Class, это было бы допустимо, но в этом случае self равно Tab_2, поэтому используйте код следующего формата:

SOME_CLASS(self).some_xxx

это плохая практика программирования, так как отсутствие проверки принадлежности себя к классу может скрыть много ошибок, как и в этом случае.


В ООП взаимодействия между объектами должны происходить в областях, гдеоба объекта существуют, в вашем случае, когда существуют объекты класса Data_Class и объект, принадлежащий Tab_2, в настоящее время не существует части вашего кода, которая существует, поэтому вы должны создать ее.

для этого мысохраните объект, который принадлежит Tab_2, как член класса, и мы будем использовать его в цикле, в котором вы создаете for:

class MainWindow(QWidget):
    def __init__(self):
        ...
        self.layout1.addWidget(self.scrollarea)
        self.tab_object = Tab_2(self) # <-----
        self.layout2.addWidget(self.tab_object)  # <-----
        ...

    def add_btns(self, item):
        layout = self.Layout ##################FlowLayout
        item_num = item['num']
        item_data = item['data']
        widget = Data_Class(item_num, item_data) # <-----
        widget.data_Signal.connect(self.tab_object.set_line_edit) # <-----
        layout.addWidget(widget)


class Tab_2(QWidget):
    def __init__(self, parent=None):
        super(Tab_2, self).__init__(parent)
        #self.data_class = Data_Class # <----
        self.vert_layout = QVBoxLayout(self)
        self.line_edit = QLineEdit()
        self.vert_layout.addWidget(self.line_edit)
        self.setLayout(self.vert_layout)
        #self.data_class(self).data_Signal.connect(self.set_line_edit)  # <----
...
0 голосов
/ 21 мая 2018

Новые сигналы должны быть определены только в подклассах QObject.Попробуйте:

import functools
import sys
from PyQt5.QtCore import pyqtSignal, QSize,  QRect, Qt, QPoint,    QObject  # +++
from PyQt5.QtWidgets import QLineEdit, QPushButton,QVBoxLayout, QScrollArea, QWidget, \
    QApplication, QTabWidget, QStyle, QSizePolicy, QLayout

# +++  New signals should only be defined in sub-classes of QObject.  
class _Signals(QObject):
    data_Signal = pyqtSignal(str)

class Data_Class(QWidget):
    #data_Signal = pyqtSignal(str)
    Signals = _Signals()
    def __init__(self, item_num=None, item_data=None):
        super(Data_Class, self).__init__()
        self.tab_2 = Tab_2
        self.num = item_num
        self.dat = item_data
        self.setFixedWidth(150)
        self.layout = QVBoxLayout()
        self.btn = QPushButton()
        self.btn.setText(str(self.num))
        self.layout.addWidget(self.btn)
        self.setLayout(self.layout)
        self.btn_click = functools.partial(self.set_btns, btn_data=self.dat)
        self.btn.clicked.connect(self.btn_click)

    def set_btns(self, btn_data):
        print(btn_data)
        #self.data_Signal.emit(btn_data)
        self.Signals.data_Signal.emit(btn_data)

class MainWindow(QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.resize(368,315)
        self.vbox = QVBoxLayout()
        self.tabWidget = QTabWidget()
        self.tabWidget.setTabPosition(QTabWidget.North)
        self.vbox.addWidget(self.tabWidget)
        self.tab1 = QWidget()
        self.tabWidget.addTab(self.tab1, ("tab1"))
        self.tab2 = QWidget()
        self.tabWidget.addTab(self.tab2, ("tab2"))
        self.layout1 = QVBoxLayout()
        self.layout2 = QVBoxLayout()
        self.tab1.setLayout(self.layout1)
        self.tab2.setLayout(self.layout2)
        self.scrollarea = QScrollArea(self)
        self.scrollarea.setWidgetResizable(True)
        self.widgets = QWidget()
        self.Layout = FlowLayout(self.widgets) ##############FlowLayout
        self.scrollarea.setWidget(self.widgets)
        self.layout1.addWidget(self.scrollarea)
        self.layout2.addWidget(Tab_2(self))
        self.setLayout(self.vbox)
        self.items =[]
        self.extract()

    def extract(self):
        mydict = {'num': 1, 'data': 'data1'},{'num': 2, 'data': 'data2'}, {'num': 3, 'data': 'data3'}, \
                 {'num': 4, 'data': 'data4'},{'num': 5, 'data': 'data5'},{'num': 6, 'data': 'data6'}, \
                 {'num': 7, 'data': 'data7'}, {'num': 8, 'data': 'data8'}, {'num': 9, 'data': 'data9'}, \
                 {'num': 10, 'data': 'data10'}, {'num': 11, 'data': 'data11'}, {'num': 12, 'data': 'data12'}
        self.items[:] = mydict
        for item in self.items:
            self.add_btns(item)

    def add_btns(self, item):
        layout = self.Layout ##################FlowLayout
        item_num = item['num']
        item_data = item['data']
        widget = Data_Class(item_num, item_data)
        layout.addWidget(widget)

class Tab_2(QWidget):
    def __init__(self, parent=None):
        super(Tab_2, self).__init__(parent)
        self.data_class = Data_Class
        self.vert_layout = QVBoxLayout(self)
        self.line_edit = QLineEdit()
        self.vert_layout.addWidget(self.line_edit)
        self.setLayout(self.vert_layout)
        #self.data_class(self).data_Signal.connect(self.set_line_edit)
        self.data_class(self).Signals.data_Signal.connect(self.set_line_edit)

    def set_line_edit(self, btn_data):
        print(btn_data)
        self.line_edit.setText(btn_data)

class FlowLayout(QLayout):
    def __init__(self, parent=None, margin=-0, hspacing=-0, vspacing=-0):
        super(FlowLayout, self).__init__(parent)
        self._hspacing = hspacing
        self._vspacing = vspacing
        self._items = []
        self.setContentsMargins(margin, margin, margin, margin)

    def __del__(self):
        del self._items[:]

    def addItem(self, item):
        self._items.append(item)

    def horizontalSpacing(self):
        if self._hspacing >= 0:
            return self._hspacing
        else:
            return self.smartSpacing(
                QStyle.PM_LayoutHorizontalSpacing)

    def verticalSpacing(self):
        if self._vspacing >= 0:
            return self._vspacing
        else:
            return self.smartSpacing(
                QStyle.PM_LayoutVerticalSpacing)

    def count(self):
        return len(self._items)

    def itemAt(self, index):
        if 0 <= index < len(self._items):
            return self._items[index]

    def takeAt(self, index):
        if 0 <= index < len(self._items):
            return self._items.pop(index)

    def expandingDirections(self):
        return Qt.Orientations(0)

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return self.doLayout(QRect(0, 0, width, 0), True)

    def setGeometry(self, rect):
        super(FlowLayout, self).setGeometry(rect)
        self.doLayout(rect, False)

    def sizeHint(self):
        return self.minimumSize()

    def minimumSize(self):
        size = QSize()
        for item in self._items:
            size = size.expandedTo(item.minimumSize())
        left, top, right, bottom = self.getContentsMargins()
        size += QSize(left + right, top + bottom)
        return size

    def doLayout(self, rect, testonly):
        left, top, right, bottom = self.getContentsMargins()
        effective = rect.adjusted(+left, +top, -right, -bottom)
        x = effective.x()
        y = effective.y()
        lineheight = 0
        for item in self._items:
            widget = item.widget()
            hspace = self.horizontalSpacing()
            if hspace == -1:
                hspace = widget.style().layoutSpacing(
                    QSizePolicy.PushButton,
                    QSizePolicy.PushButton, Qt.Horizontal)
            vspace = self.verticalSpacing()
            if vspace == -1:
                vspace = widget.style().layoutSpacing(
                    QSizePolicy.PushButton,
                    QSizePolicy.PushButton, Qt.Vertical)
            nextX = x + item.sizeHint().width() + hspace
            if nextX - hspace > effective.right() and lineheight > 0:
                x = effective.x()
                y = y + lineheight + vspace
                nextX = x + item.sizeHint().width() + hspace
                lineheight = 0
            if not testonly:
                item.setGeometry(
                    QRect(QPoint(x, y), item.sizeHint()))
            x = nextX
            lineheight = max(lineheight, item.sizeHint().height())
        return y + lineheight - rect.y() + bottom

    def smartSpacing(self, pm):
        parent = self.parent()
        if parent is None:
            return -1
        elif parent.isWidgetType():
            return parent.style().pixelMetric(pm, None, parent)
        else:
            return parent.spacing()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    wnd = MainWindow()
    wnd.show()
    app.exec_()

enter image description here

...