英文:
In PySide6, if a `QMainWindow` has a pushbutton connected to it's own partial function, it could be opened many times, why?
问题
以下是您的代码的翻译部分:
import sys
from functools import partial
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout,
QMainWindow, QPushButton, QStatusBar, QWidget)
class UiTest(QMainWindow):
def __init__(self):
self.app = QApplication.instance()
if self.app is None:
self.app = QApplication(sys.argv)
super().__init__()
self.setObjectName(u"test_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.setWindowTitle("Test partial")
self.horizontalLayout = QHBoxLayout(self.centralwidget)
self.PB_no_partial = QPushButton(self.centralwidget)
self.PB_no_partial.setObjectName(u"PB_no_partial")
self.PB_no_partial.setText("no partial")
self.PB_no_partial.clicked.connect(self.PB_no_partial_clicked)
self.PB_own_partial = QPushButton(self.centralwidget)
self.PB_own_partial.setObjectName(u"PB_own_partial")
self.PB_own_partial.setText("own partial")
self.PB_own_partial.clicked.connect(self.PB_own_partial_clicked)
self.PB_others_partial = QPushButton(self.centralwidget)
self.PB_others_partial.setObjectName(u"PB_others_partial")
self.PB_others_partial.setText("other's partial")
self.PB_others_partial.clicked.connect(self.PB_others_partial_clicked)
self.horizontalLayout.addWidget(self.PB_no_partial)
self.horizontalLayout.addWidget(self.PB_own_partial)
self.horizontalLayout.addWidget(self.PB_others_partial)
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.statusbar = QStatusBar(self)
self.statusbar.setObjectName(u"statusbar")
self.setStatusBar(self.statusbar)
self.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(self)
def PB_no_partial_clicked(self):
self.no_partial = UiNoPartial()
self.no_partial.show()
def PB_own_partial_clicked(self):
self.own_partial = UiOwnPartial()
self.own_partial.show()
def PB_others_partial_clicked(self):
if not hasattr(self, "own_partial"):
self.own_partial = UiOwnPartial()
self.others_partial = UiOthersPartial(self.own_partial)
self.others_partial.show()
def show(self):
super().show()
sys.exit(self.app.exec())
class UiNoPartial(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("No partial")
self.setObjectName(u"no_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.PB_no_partial = QPushButton(self.centralwidget)
self.PB_no_partial.setObjectName(u"PB_no_partial")
self.PB_no_partial.clicked.connect(self.PB_no_partial_clicked)
def PB_no_partial_clicked(self):
print("PB_no_partial_clicked")
class UiOwnPartial(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Own partial")
self.setObjectName(u"own_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.PB_own_partial = QPushButton(self.centralwidget)
self.PB_own_partial.setObjectName(u"PB_own_partial")
self.PB_own_partial.clicked.connect(partial(self.PB_own_partial_clicked, "aaa"))
def PB_own_partial_clicked(self, text:str):
if text == "aaa":
print("aaa")
else:
print("bbb")
class UiOthersPartial(QMainWindow):
def __init__(self, others):
super().__init__()
self.setWindowTitle("Other's partial")
self.setObjectName(u"others_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.others = others
self.PB_others_partial = QPushButton(self.centralwidget)
self.PB_others_partial.setObjectName(u"PB_others_partial")
self.PB_others_partial.clicked.connect(partial(self.others.PB_own_partial_clicked, "bbb"))
if __name__ == "__main__":
test = UiTest()
test.show()
至于您的问题,PySide6中的行为是受到连接信号和槽函数的方式的影响的。在PB_own_partial_clicked
函数中,使用了functools.partial
来连接槽函数,这允许将参数传递给槽函数。这样,每次点击"own partial"按钮时,都会创建一个新的UiOwnPartial
对象,因此您会看到多个窗口打开。
而对于"other's partial"按钮,它与已创建的UiOwnPartial
对象的槽函数连接,因此只会打开一个窗口。这是因为当按钮点击时,它会检查是否已经创建了UiOwnPartial
对象,如果没有,则创建一个新的,否则使用已经存在的对象。这就解释了为什么"own partial"和"other's partial"的行为不同。
这种行为与PyQt5/6或PySide2中的情况可能会有所不同,因为不同的版本可能有不同的信号和槽连接机制。如果需要更多关于特定版本的信息,建议查阅相关文档或进行实际测试。
英文:
Here is my code:
import sys
from functools import partial
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout,
QMainWindow, QPushButton, QStatusBar, QWidget)
class UiTest(QMainWindow):
def __init__(self):
self.app = QApplication.instance()
if self.app is None:
self.app = QApplication(sys.argv)
super().__init__()
self.setObjectName(u"test_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.setWindowTitle("Test partial")
self.horizontalLayout = QHBoxLayout(self.centralwidget)
self.PB_no_partial = QPushButton(self.centralwidget)
self.PB_no_partial.setObjectName(u"PB_no_partial")
self.PB_no_partial.setText("no partial")
self.PB_no_partial.clicked.connect(self.PB_no_partial_clicked)
self.PB_own_partial = QPushButton(self.centralwidget)
self.PB_own_partial.setObjectName(u"PB_own_partial")
self.PB_own_partial.setText("own partial")
self.PB_own_partial.clicked.connect(self.PB_own_partial_clicked)
self.PB_others_partial = QPushButton(self.centralwidget)
self.PB_others_partial.setObjectName(u"PB_others_partial")
self.PB_others_partial.setText("other's partial")
self.PB_others_partial.clicked.connect(self.PB_others_partial_clicked)
self.horizontalLayout.addWidget(self.PB_no_partial)
self.horizontalLayout.addWidget(self.PB_own_partial)
self.horizontalLayout.addWidget(self.PB_others_partial)
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.statusbar = QStatusBar(self)
self.statusbar.setObjectName(u"statusbar")
self.setStatusBar(self.statusbar)
self.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(self)
def PB_no_partial_clicked(self):
self.no_partial = UiNoPartial()
self.no_partial.show()
def PB_own_partial_clicked(self):
self.own_partial = UiOwnPartial()
self.own_partial.show()
def PB_others_partial_clicked(self):
if not hasattr(self, "own_partial"):
self.own_partial = UiOwnPartial()
self.others_partial = UiOthersPartial(self.own_partial)
self.others_partial.show()
def show(self):
super().show()
sys.exit(self.app.exec())
class UiNoPartial(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("No partial")
self.setObjectName(u"no_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.PB_no_partial = QPushButton(self.centralwidget)
self.PB_no_partial.setObjectName(u"PB_no_partial")
self.PB_no_partial.clicked.connect(self.PB_no_partial_clicked)
def PB_no_partial_clicked(self):
print("PB_no_partial_clicked")
class UiOwnPartial(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Own partial")
self.setObjectName(u"own_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.PB_own_partial = QPushButton(self.centralwidget)
self.PB_own_partial.setObjectName(u"PB_own_partial")
self.PB_own_partial.clicked.connect(partial(self.PB_own_partial_clicked, "aaa"))
def PB_own_partial_clicked(self, text:str):
if text == "aaa":
print("aaa")
else:
print("bbb")
class UiOthersPartial(QMainWindow):
def __init__(self, others):
super().__init__()
self.setWindowTitle("Other's partial")
self.setObjectName(u"others_partial")
self.centralwidget = QWidget(self)
self.centralwidget.setObjectName(u"centralwidget")
self.others = others
self.PB_others_partial = QPushButton(self.centralwidget)
self.PB_others_partial.setObjectName(u"PB_others_partial")
self.PB_others_partial.clicked.connect(partial(self.others.PB_own_partial_clicked, "bbb"))
if __name__ == "__main__":
test = UiTest()
test.show()
Now, run this code, and interesting things happen:
- when I click "no partial" pushbutton for many times, only one "no partial" window would be opened;
- when I click "own partial" pushbutton for many times, each time one new "own partial" window would be opened;
- when I click "other's partial" pushbutton for many times, only one "other's partial" window would be opened.
So we can conclude: in PySide6, if one QMainWindow
object has a pushbutton connected to it's own partial function, it could be opened many times, or it could be opened only once event though it be opened by user many times.
I wonder why this could happen? what makes it different? Why "own partial" is different from "othere's partial"?
I didn't test it on other python QT versions like PyQt5/6 or PySide2, but I guess same thing would happen. Anyone has PyQt5/6 or PySide2 could have a try.
My environment:<br>
windows 10<br>
python 3.10.1<br>
PySide6 6.2.2.1<br>
答案1
得分: 1
当你调用 partial
时,它会创建对每个被调用参数的引用,这些引用会一直存在,直到新的 partial
对象被取消引用。
因此,当你运行 partial(self.PB_own_partial_clicked, "aaa")
时,你实际上创建了对 self
的引用,这导致了 UiOwnPartial
实例最终持有对 partial
的引用,而 partial
又持有对自身的引用。
因此,即使你在 UiTest
窗口中覆盖了 self.own_partial
属性,UiOwnPartial
窗口仍然可以继续存在,因为Python检测到在 partial
对象中仍然存在对窗口的引用。
英文:
My guess is that when you call partial
, it creates a reference to each of its called arguments which will stay around until the new partial
object is dereferenced.
Thus, when you run partial(self.PB_own_partial_clicked, "aaa")
, you end up creating a reference to self
which then results in a situation where the UiOwnPartial
instance ends up with a reference to partial
which holds a reference to itself.
Because of that, even when you overwrite the self.own_partial
property in the UiTest
window, the UiOwnPartial
window can continue to exist since Python detects that a reference to the window still exists in the partial
object.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论