PyQt 发送值到不同的问题 class
PyQt Issue sending values to different class
在下面的代码中,我试图找出将数据从 "Data_Class" Class 共享到 "Tab_2" Class 的最佳方式。具体来说,我试图在单击按钮时从 tab1 中的 "Data_Class" 中获取值以填充 tab2 中的 QLineEdit。我也尝试过使用信号并直接发送到 "Tab_2" class,但我能得到的最好的是在 "Tab_2" 中打印但不填充 QLineEdit 的值。
在 "MainWindow" Class 中,我构建并分离数据,然后使用 FlowLayout 嵌入 "Data_Class",同时将数据发送到 "Data_Class" 以创建按钮并为其设置值,但是现在我无法将数据发送到 "Tab_2" Class.
还有,"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_()
新信号只能在 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_()
@S. Nick的响应是错误的,因为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
这是一个糟糕的编程实践,因为不验证 self 对 class 的归属会隐藏许多错误,就像在这种情况下一样。
在 OOP 中,对象之间的交互必须发生在两个对象都存在的范围内,在您的情况下 class Data_Class 的对象存在并且属于 Tab_2 的对象也存在,目前没有您的代码部分存在,因此您必须创建它。
为此,我们将属于 Tab_2 的对象保留为 class 的成员,我们将在您创建 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) # <----
...
在下面的代码中,我试图找出将数据从 "Data_Class" Class 共享到 "Tab_2" Class 的最佳方式。具体来说,我试图在单击按钮时从 tab1 中的 "Data_Class" 中获取值以填充 tab2 中的 QLineEdit。我也尝试过使用信号并直接发送到 "Tab_2" class,但我能得到的最好的是在 "Tab_2" 中打印但不填充 QLineEdit 的值。
在 "MainWindow" Class 中,我构建并分离数据,然后使用 FlowLayout 嵌入 "Data_Class",同时将数据发送到 "Data_Class" 以创建按钮并为其设置值,但是现在我无法将数据发送到 "Tab_2" Class.
还有,"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_()
新信号只能在 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_()
@S. Nick的响应是错误的,因为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
这是一个糟糕的编程实践,因为不验证 self 对 class 的归属会隐藏许多错误,就像在这种情况下一样。
在 OOP 中,对象之间的交互必须发生在两个对象都存在的范围内,在您的情况下 class Data_Class 的对象存在并且属于 Tab_2 的对象也存在,目前没有您的代码部分存在,因此您必须创建它。
为此,我们将属于 Tab_2 的对象保留为 class 的成员,我们将在您创建 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) # <----
...