Python 在运行时替换QWidget对象

Python 在运行时替换QWidget对象,python,pyqt,pyqt4,qt-designer,Python,Pyqt,Pyqt4,Qt Designer,在我的应用程序中,我必须用定制的QLineEdit替换所有QLineEdit元素。为此,有不同的解决方案: 修改从pyuic4生成的py文件,并将其中的所有QLineEdit对象替换为我的单线编辑。这个解决方案并不是最好的,因为每次运行pyuic4时,我都会丢失对生成的输出文件所做的修改 编写一个新类,在我的窗口或对话框中递归搜索QLineEdit小部件类型,并将其替换为我的单线编辑。这个解决方案要好得多。它允许我也对其他对象执行相同的操作,或者根据需要扩展它,而不必关心对话框或窗口 到目前为止

在我的应用程序中,我必须用定制的QLineEdit替换所有QLineEdit元素。为此,有不同的解决方案:

  • 修改从pyuic4生成的py文件,并将其中的所有QLineEdit对象替换为我的单线编辑。这个解决方案并不是最好的,因为每次运行pyuic4时,我都会丢失对生成的输出文件所做的修改
  • 编写一个新类,在我的窗口或对话框中递归搜索QLineEdit小部件类型,并将其替换为我的单线编辑。这个解决方案要好得多。它允许我也对其他对象执行相同的操作,或者根据需要扩展它,而不必关心对话框或窗口
  • 到目前为止,我可以编写一个模块(WidgetReplacer),递归搜索QGridLayout项,并搜索是否有QLineEdit子项。如果是,则用我的替换

    问题是,当我尝试访问其中一个LineEdit对象时,会出现以下错误:

    RuntimeError: wrapped C/C++ object of type QLineEdit has been deleted
    
    如果我查看我的输出,我会注意到修改后的QLineEdit对象具有旧id:

    old qt_obj <PyQt4.QtGui.QLineEdit object at 0x0543C930>
    Replaced txt_line_1 with LineEdit
    new qt_obj <LineEdit.LineEdit object at 0x0545B4B0>
    ----------------------------------
    ...
    ----------------------------------
    <PyQt4.QtGui.QLineEdit object at 0x0543C930>
    
    LineEdit

    from PyQt4.QtGui import QLineEdit, QValidator, QPalette
    from PyQt4 import QtCore
    
    class LineEdit(QLineEdit):
    
        def __init__(self, parent=None):
            super(LineEdit, self).__init__(parent)
    
            self.color_red = QPalette()
            self.color_red.setColor(QPalette.Text, QtCore.Qt.red)
    
            self.color_black = QPalette()
            self.color_black.setColor(QPalette.Text, QtCore.Qt.red)
    
            # Make connections
            self.textChanged.connect(self.verify_text)
    
        def verify_text(self, text):
            validator = self.validator()
            is_valid = QValidator.Acceptable
    
            if validator is not None:
                is_valid = validator.validate(text, 0)
    
            if is_valid == QValidator.Acceptable:
                self.setPalette(self.color_black)
            elif is_valid in [QValidator.Invalid, QValidator.Intermediate]:
                self.setPalette(self.color_red)
    
    WidgetReplacer

    import sip
    from LineEdit import LineEdit
    from PyQt4.QtCore import QRegExp
    from PyQt4 import QtGui
    
    class WidgetReplacer():
    
        def __init__(self):
            pass
    
        def replace_all_qlineedit(self, qt_dlg):
            children = self._get_all_gridlayout(qt_dlg)
    
            items = []
            for child in children:
                new_items = self._find_all_obj_in_layout(child, QtGui.QLineEdit)
                items.extend(new_items)
    
            for item in items:
                layout = item[0]
                row = item[1]
                column = item[2]
                qt_obj = item[3]
                self._replace_qlineedit_from_gridlayout(qt_dlg, qt_obj,
                                                        layout, row, column)
    
        def _get_all_gridlayout(self, qt_dlg):
            return qt_dlg.findChildren(QtGui.QGridLayout, QRegExp("gridLayout_[0-9]"))
    
        def _find_all_obj_in_layout(self, layout, qt_type):
            # Output list format:
            # layout, row, col, qt_obj,
            objects = []
            if type(layout) == QtGui.QGridLayout:
                layout_cols = layout.columnCount()
                layout_rows = layout.rowCount()
                for i in range(layout_rows):
                    for j in range(layout_cols):
                        item = layout.itemAtPosition(i, j)
    #                    print "item(",i, j, "):", item
    
                        if type(item) == QtGui.QWidgetItem:
                            if type(item.widget()) == qt_type:
                                new_obj = [layout, i, j, item.widget()]
                                objects.append(new_obj)
    
            elif type(layout) in [QtGui.QHBoxLayout, QtGui.QVBoxLayout]:
                raise SyntaxError("ERROR: Find of Qt objects in QHBoxLayout or QVBoxLayout still not supported")
    #            for i in range(layout.count()):
    #                item = layout.itemAt(i)
    
            return objects
    
        def _replace_qlineedit_from_gridlayout(self, parent, qt_obj, layout, row, column):
            print "old qt_obj", qt_obj
            obj_name = qt_obj.objectName()
            layout.removeWidget(qt_obj)
            sip.delete(qt_obj)
            qt_obj = LineEdit(parent)
            qt_obj.setObjectName(obj_name)
    
            layout.addWidget(qt_obj, row, column)
            print "Replaced", obj_name, "with LineEdit"
    
            print "new qt_obj", qt_obj
            print "----------------------------------"
    

    我没有通读你所有的代码

    但我的猜测是,即使您在布局中替换了小部件,
    window.txt\u line\u 1
    仍然指向已删除的对象。 因此,在替换过程中,还必须更新此属性

    所以,加上

    setattr(parent, obj_name, qt_obj);
    

    从gridlayout中替换qlineedit可能会起作用。

    我没有看完你所有的代码

    但我的猜测是,即使您在布局中替换了小部件,
    window.txt\u line\u 1
    仍然指向已删除的对象。 因此,在替换过程中,还必须更新此属性

    所以,加上

    setattr(parent, obj_name, qt_obj);
    

    从gridlayout替换qlineedit可能会奏效。

    不要在运行时替换小部件:在Qt Designer中升级小部件,以便在生成GUI模块时由自定义类自动替换行编辑

    下面介绍如何将小部件升级为使用自定义类:

    在Qt Designer中,选择所有要替换的行编辑,然后右键单击它们并选择“升级到…”。在对话框中,将“升级的类名”设置为“LineEdit”,并将“头文件”设置为包含此类的模块的python导入路径(例如
    myapp.LineEdit
    )。然后单击“添加”和“升级”,您将在对象检查器窗格中看到类从“QLineEdit”更改为“LineEdit”

    现在,当您使用pyuic重新生成ui模块时,您应该看到它使用了您的自定义LineEdit类,并且在文件底部会有一个额外的行,如下所示:

        from myapp.LineEdit import LineEdit
    

    不要在运行时替换小部件:在Qt Designer中升级小部件,以便在生成GUI模块时,行编辑自动被自定义类替换

    下面介绍如何将小部件升级为使用自定义类:

    在Qt Designer中,选择所有要替换的行编辑,然后右键单击它们并选择“升级到…”。在对话框中,将“升级的类名”设置为“LineEdit”,并将“头文件”设置为包含此类的模块的python导入路径(例如
    myapp.LineEdit
    )。然后单击“添加”和“升级”,您将在对象检查器窗格中看到类从“QLineEdit”更改为“LineEdit”

    现在,当您使用pyuic重新生成ui模块时,您应该看到它使用了您的自定义LineEdit类,并且在文件底部会有一个额外的行,如下所示:

        from myapp.LineEdit import LineEdit
    

    我明白你的意思,但我不知道怎么做。如果我只是将您的行从网格布局复制到\u replace\u qlineedit\u中,它将不起作用。你能告诉我更多的细节吗?你有可能执行我的例子吗?我理解你的意思,但我不知道怎么做。如果我只是将您的行从网格布局复制到\u replace\u qlineedit\u中,它将不起作用。你能告诉我更多的细节吗?你有可能执行我的例子吗?这是一个更好更简单的解决方案,就像我试图做的那样。谢谢你,埃库罗!伙计,你刚刚把我的水变成了酒。。。谢谢,这是一个更好更简单的解决方案,就像我尝试做的那样。谢谢你,埃库罗!伙计,你刚刚把我的水变成了酒。。。谢谢
    setattr(parent, obj_name, qt_obj);
    
        from myapp.LineEdit import LineEdit