理解 pyqt 中的 connectSlotsByName() 时遇到问题?

发布于 2024-08-25 02:45:25 字数 2987 浏览 4 评论 0原文

我无法理解 pyuic4 主要使用的 connectSlotsByName() 方法。到目前为止,该类在 PyQt 文件中是单个类,这是可以的,因为我们可以使用 self ,它将始终与单个对象关联。但是当我们尝试时要使用不同文件中的各种类,就会出现问题并需要使用 connectSlotsByName() .. 这是我遇到的奇怪的情况..

我创建了一个堆叠的小部件..

  • 我在上面放置了我的第一个小部件.. 它 有一个名为“下一步>”的按钮。

  • 单击“下一步”时,它会隐藏当前的 小部件并添加另一个具有“单击我”按钮的小部件。

这里的问题是第二个“单击我”按钮的单击事件未捕获。这是我可以为我的原始问题提供的一个最小示例。请帮助我..

这是文件No.1..(其中有父级堆叠小部件及其第一页)。单击“下一步”时,它会添加第二个页面,该页面在 file2 中具有“clickme”按钮。

from PyQt4 import QtCore, QtGui

import file2

class Ui_StackedWidget(QtGui.QStackedWidget):

    def __init__(self,parent=None):

        QtGui.QStackedWidget.__init__(self,parent)

        self.setObjectName("self")
        self.resize(484, 370)
        self.setWindowTitle(QtGui.QApplication.translate("self", "stacked widget", None, QtGui.QApplication.UnicodeUTF8))

        self.createWidget1()

    def createWidget1(self):

        self.page=QtGui.QWidget()
        self.page.setObjectName("widget1")


        self.pushButton=QtGui.QPushButton(self.page)        
        self.pushButton.setGeometry(QtCore.QRect(150, 230, 91, 31))
        self.pushButton.setText(QtGui.QApplication.translate("self", "Next >", None, QtGui.QApplication.UnicodeUTF8))


        self.addWidget(self.page)


        QtCore.QMetaObject.connectSlotsByName(self.page)

          QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.showWidget2)


    def showWidget2(self):

        self.page.hide()

        obj=file2.widget2()
        obj.createWidget2(self)


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    ui = Ui_StackedWidget()
    ui.show()
    sys.exit(app.exec_()) 

这是 file2

from PyQt4 import QtGui,QtCore

class widget2():

    def createWidget2(self,parent):

        self.page = QtGui.QWidget()
        self.page.setObjectName("page")

        self.parent=parent

        self.groupBox = QtGui.QGroupBox(self.page)
        self.groupBox.setGeometry(QtCore.QRect(30, 20, 421, 311))
        self.groupBox.setObjectName("groupBox")
        self.groupBox.setTitle(QtGui.QApplication.translate("self", "TestGroupBox", None, QtGui.QApplication.UnicodeUTF8))

        self.pushButton = QtGui.QPushButton(self.groupBox)
        self.pushButton.setGeometry(QtCore.QRect(150, 120, 92, 28))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText(QtGui.QApplication.translate("self", "Click Me", None, QtGui.QApplication.UnicodeUTF8))        

        self.parent.addWidget(self.page)
        self.parent.setCurrentWidget(self.page)

        QtCore.QMetaObject.connectSlotsByName(self.page)

        QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.printMessage)


    def printMessage(self):

        print("Hai")

虽然在两个小部件(我的意思是页面)中,

QtCore.QMetaObject.connectSlotsByName(self.page)

第二个对话框中的单击信号未得到处理。预先感谢..可能是一个初学者的问题..

I couldn't understand the connectSlotsByName() method which is predominently used by pyuic4.. As far the class is single in a PyQt file it's ok since we can use self which will be associated with a single object throughout.. But when we try to use various classes from different files the problem and the need to use connectSlotsByName() arises.. Here's what i encountered which is weird..

I created a stacked widget..

  • I placed my first widget on it.. It
    has a button called "Next >".

  • On clicking next it hides the current
    widget and adds another widget which has the "click me" button..

The problem here is the click event for "click me" button in second is not captured.. It's a minimal example that i can give for my original problem.. Please help me..

This is file No.1..(which has the parent stacked widget and it's first page). On clicking next it adds the second page which has "clickme" button in file2..

from PyQt4 import QtCore, QtGui

import file2

class Ui_StackedWidget(QtGui.QStackedWidget):

    def __init__(self,parent=None):

        QtGui.QStackedWidget.__init__(self,parent)

        self.setObjectName("self")
        self.resize(484, 370)
        self.setWindowTitle(QtGui.QApplication.translate("self", "stacked widget", None, QtGui.QApplication.UnicodeUTF8))

        self.createWidget1()

    def createWidget1(self):

        self.page=QtGui.QWidget()
        self.page.setObjectName("widget1")


        self.pushButton=QtGui.QPushButton(self.page)        
        self.pushButton.setGeometry(QtCore.QRect(150, 230, 91, 31))
        self.pushButton.setText(QtGui.QApplication.translate("self", "Next >", None, QtGui.QApplication.UnicodeUTF8))


        self.addWidget(self.page)


        QtCore.QMetaObject.connectSlotsByName(self.page)

          QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.showWidget2)


    def showWidget2(self):

        self.page.hide()

        obj=file2.widget2()
        obj.createWidget2(self)


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    ui = Ui_StackedWidget()
    ui.show()
    sys.exit(app.exec_()) 

Here's file2

from PyQt4 import QtGui,QtCore

class widget2():

    def createWidget2(self,parent):

        self.page = QtGui.QWidget()
        self.page.setObjectName("page")

        self.parent=parent

        self.groupBox = QtGui.QGroupBox(self.page)
        self.groupBox.setGeometry(QtCore.QRect(30, 20, 421, 311))
        self.groupBox.setObjectName("groupBox")
        self.groupBox.setTitle(QtGui.QApplication.translate("self", "TestGroupBox", None, QtGui.QApplication.UnicodeUTF8))

        self.pushButton = QtGui.QPushButton(self.groupBox)
        self.pushButton.setGeometry(QtCore.QRect(150, 120, 92, 28))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText(QtGui.QApplication.translate("self", "Click Me", None, QtGui.QApplication.UnicodeUTF8))        

        self.parent.addWidget(self.page)
        self.parent.setCurrentWidget(self.page)

        QtCore.QMetaObject.connectSlotsByName(self.page)

        QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.printMessage)


    def printMessage(self):

        print("Hai")

Though in both the widgets(i mean pages)

QtCore.QMetaObject.connectSlotsByName(self.page)

the clicked signal in second dialog isn't getting processed. Thanks in advance.. Might be a beginner question..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

橘寄 2024-09-01 02:45:25

首先,这是一个最小的工作示例:

from sys import argv, exit
from PyQt4 import QtCore, QtGui

class widget2(QtGui.QWidget):

    def __init__(self, args):
        self.app = MainApp(args)
        QtGui.QWidget.__init__(self)
        self.setObjectName('I')

        self._layout = QtGui.QVBoxLayout(self)
        self.setLayout(self._layout)

        self.pushButtoninWidget2 = QtGui.QPushButton(self)
        self.pushButtoninWidget2.setObjectName("pushButtoninWidget2")
        self.pushButtoninWidget2.setText('Click NOW!')
        self._layout.addWidget(self.pushButtoninWidget2)

        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot()
    def on_pushButtoninWidget2_clicked(self):
        print("Hai")

class MainApp(QtGui.QApplication):
    def __init__(self, args):
        QtGui.QApplication.__init__(self, args)

if __name__ == "__main__":
    main = widget2(argv)
    main.show()
    exit(main.app.exec_())

当您尝试按名称连接插槽时,您必须为插槽提供正确的名称,然后某人(moc、uic 或您通过调用 connectSlotsByName)必须连接它们。此类插槽的正确名称是:“on_PyQtObjectName_PyQtSignalName”。

请注意,如果我在示例中省略了 @QtCore.pyqtSlot(),则每个适当的重载都会执行一次 slot (在本例中为两次)。

您确实需要直接调用 connectSlotsByNames,因为没有 moc,当您在 C++ 中使用 QT 时,它会为您完成此操作,并且您不使用 uic 和 .ui 文件。如果你想隐式连接插槽(我总是这样做,除了在.ui中直接连接的插槽),你最好使用更多的pytonish语法:button.clicked.connect(self._mySlot)。

并查看 https://riverbankcomputing.com /static/Docs/PyQt5/signals_slots.html#connecting-slots-by-name

At first, here is the minimal working example:

from sys import argv, exit
from PyQt4 import QtCore, QtGui

class widget2(QtGui.QWidget):

    def __init__(self, args):
        self.app = MainApp(args)
        QtGui.QWidget.__init__(self)
        self.setObjectName('I')

        self._layout = QtGui.QVBoxLayout(self)
        self.setLayout(self._layout)

        self.pushButtoninWidget2 = QtGui.QPushButton(self)
        self.pushButtoninWidget2.setObjectName("pushButtoninWidget2")
        self.pushButtoninWidget2.setText('Click NOW!')
        self._layout.addWidget(self.pushButtoninWidget2)

        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot()
    def on_pushButtoninWidget2_clicked(self):
        print("Hai")

class MainApp(QtGui.QApplication):
    def __init__(self, args):
        QtGui.QApplication.__init__(self, args)

if __name__ == "__main__":
    main = widget2(argv)
    main.show()
    exit(main.app.exec_())

When you trying to connect slots by name, you must give proper names to the slots and then someone (moc, uic, or you by calling connectSlotsByName) must connect them. Proper name for such a slot is: "on_PyQtObjectName_PyQtSignalName".

Note, that, if I'd omitted @QtCore.pyqtSlot() in the example, slot would be executed once for every appropriate overload (twice in this case).

You DO need to call connectSlotsByNames directly, cause there is no moc, which do it for you when you use QT in C++, and you do not use uic and .ui file. If you want to connect slots implicitly (I'm always doing so, except slots, connected directly in .ui), you'd better use more pytonish syntaxe: button.clicked.connect(self._mySlot).

And take a look at https://riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html#connecting-slots-by-name

余生再见 2024-09-01 02:45:25

更好的问题是“为什么不直接使用新型信号和槽?”。它们要简单得多,不需要任何奇怪的命名约定:

from sys import argv, exit
from PyQt4 import QtCore, QtGui

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        self._layout = QtGui.QVBoxLayout()
        self.setLayout(self._layout)

        self._button = QtGui.QPushButton()
        self._button.setText('Click NOW!')
        self._layout.addWidget(self._button)

        self._button.clicked.connect(self._printMessage)

    @QtCore.pyqtSlot()
    def _printMessage(self):
        print("Hai")

if __name__ == "__main__":
    app = QtGui.QApplication(argv)

    main = MyWidget()
    main.show()
    exit(app.exec_())

A better question is "Why not just use new-style signals and slots?". They're much simpler and don't require any weird naming conventions:

from sys import argv, exit
from PyQt4 import QtCore, QtGui

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        self._layout = QtGui.QVBoxLayout()
        self.setLayout(self._layout)

        self._button = QtGui.QPushButton()
        self._button.setText('Click NOW!')
        self._layout.addWidget(self._button)

        self._button.clicked.connect(self._printMessage)

    @QtCore.pyqtSlot()
    def _printMessage(self):
        print("Hai")

if __name__ == "__main__":
    app = QtGui.QApplication(argv)

    main = MyWidget()
    main.show()
    exit(app.exec_())
萌酱 2024-09-01 02:45:25

您不需要调用 connectSlotsByName(),只需删除这些行即可。

file2 中,调用 QtCore.QMetaObject.connectSlotsByName(self.page) 尝试执行此操作:

QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self.on_pushButton_clicked())

self.on_pushBotton_clicked() 起,这对您不起作用code> 槽未定义。
我发现在 PyQt 中创建您自己的连接是最简单的...我建议从您的两个类中删除对 connectSlotsByName 的调用...您不需要它。

另外,您的 wdiget1 类应设置其 pushButton 的名称(最好是“pushButton”以外的名称,以避免与 widget2 中的按钮混淆)。

You do not need to call connectSlotsByName(), just remove those lines.

In file2, calling QtCore.QMetaObject.connectSlotsByName(self.page) tries to do this:

QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self.on_pushButton_clicked())

That will not work for you since self.on_pushBotton_clicked() slot is not defined.
I find it is easiest to create your own connections in PyQt... I recommend removing the calls to connectSlotsByName from your both classes... you do not need it.

Also, your wdiget1 class should set the name of it's pushButton (preferably something other then "pushButton" to avoid confusion with the button in widget2).

醉城メ夜风 2024-09-01 02:45:25

非常感谢jcoon的回复..但是经过很长一段时间,我把头撞在墙上,我找到了解决方案..

问题是..

self.obj=test_reuse_stacked1.widget2()
self.obj.createWidget2(self)

而不是obj..

Thank you so much jcoon for your reply.. But after a very long time banging my head against the wall i found the solution..

The problem was..

self.obj=test_reuse_stacked1.widget2()
self.obj.createWidget2(self)

instead of obj..

各自安好 2024-09-01 02:45:25

这是@MarkVisser 的 QT4 代码更新为 QT5:

from sys import argv, exit
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget


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

        self._layout = QtWidgets.QVBoxLayout()
        self.setLayout(self._layout)

        self._button = QtWidgets.QPushButton()
        self._button.setText('Click NOW!')
        self._layout.addWidget(self._button)

        self._button.clicked.connect(self._print_message)

    @QtCore.pyqtSlot()
    def _print_message(self):
        print("Hai")


if __name__ == "__main__":
    app = QApplication(argv)
    main = MyWidget()
    main.show()
    exit(app.exec_())

Here is @MarkVisser's QT4 code updated to QT5:

from sys import argv, exit
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget


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

        self._layout = QtWidgets.QVBoxLayout()
        self.setLayout(self._layout)

        self._button = QtWidgets.QPushButton()
        self._button.setText('Click NOW!')
        self._layout.addWidget(self._button)

        self._button.clicked.connect(self._print_message)

    @QtCore.pyqtSlot()
    def _print_message(self):
        print("Hai")


if __name__ == "__main__":
    app = QApplication(argv)
    main = MyWidget()
    main.show()
    exit(app.exec_())
oО清风挽发oО 2024-09-01 02:45:25

另一个使用Qt for Python最小工作示例,又名PySide2/6
关键要素:

  • 要连接的小部件必须具有 .setObjectName
  • 连接函数必须用 @QtCore.Slot() 装饰
  • 两个对象(函数和小部件)必须是传递对象的成员(这里是self
from PySide2 import QtCore, QtWidgets
# or from PySide6 import QtCore, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self):
        super(Widget, self).__init__()
        layout = QtWidgets.QVBoxLayout(self)
        self.button = QtWidgets.QPushButton(self)
        self.button.setObjectName('button')
        self.button.setText('Click Me!')
        layout.addWidget(self.button)

        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.Slot()
    def on_button_clicked(self):
        print(f'Hai from {self.sender()}')


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    main = Widget()
    main.show()
    app.exec_()

我真的无法让它变得更小

Another minimal working example with Qt for Python aka PySide2/6.
Key ingredients:

  • widget to connect MUST have .setObjectName
  • function to connect MUST be decorated with @QtCore.Slot()
  • both objects (function AND widget) MUST be members of passed object (self here)
from PySide2 import QtCore, QtWidgets
# or from PySide6 import QtCore, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self):
        super(Widget, self).__init__()
        layout = QtWidgets.QVBoxLayout(self)
        self.button = QtWidgets.QPushButton(self)
        self.button.setObjectName('button')
        self.button.setText('Click Me!')
        layout.addWidget(self.button)

        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.Slot()
    def on_button_clicked(self):
        print(f'Hai from {self.sender()}')


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    main = Widget()
    main.show()
    app.exec_()

I couldn't get mit any smaller really ????

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文