当前位置: 首页 > 面试题库 >

在运行时替换QWidget对象

羊禄
2023-03-14
问题内容

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

  1. 修改从pyuic4生成的py文件,然后用我的一个LineEdit替换所有QLineEdit对象。该解决方案并不是真正的最佳解决方案,因为每次运行pyuic4时,我都会丢失对所做的修改,并将其保存到生成的输出文件中。
  2. 编写一个新类,在我的窗口或对话框中递归搜索QLineEdit小部件类型,并将其替换为我的LineEdit。这个解决方案好得多。它使我也可以对其他对象执行相同的操作,也可以根据需要扩展它,而无需关心对话框或窗口。

到目前为止,我可以编写一个模块(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>

为什么会这样?如何在运行时替换QWidget?

更新资料

这里是有关对象包装的一些其他详细信息:在模块WidgetReplace内,如果我转储得到的QEditLine和LineEdit对象:

<PyQt4.QtGui.QLineEdit object at 0x05378618>
    Reference count: 7
    Address of wrapped object: 051FAC40
    Created by: Python
    To be destroyed by: C/C++
    Parent wrapper: <PyQt4.QtGui.QGridLayout object at 0x05378588>
    Next sibling wrapper: NULL
    Previous sibling wrapper: <PyQt4.QtGui.QLabel object at 0x05378930>
    First child wrapper: NULL

<LineEdit.LineEdit object at 0x05378978>
    Reference count: 3
    Address of wrapped object: 051FAC40
    Created by: Python
    To be destroyed by: C/C++
    Parent wrapper: <__main__.Dialog object at 0x0535FBB8>
    Next sibling wrapper: <PyQt4.QtGui.QGridLayout object at 0x05378780>
    Previous sibling wrapper: NULL
    First child wrapper: NULL

相反,如果我从主转储我的行编辑,则会得到跟随,它代表已删除的QLineEdit对象:

<PyQt4.QtGui.QLineEdit object at 0x05378618>
    Reference count: 2
    Address of wrapped object: 00000000
    Created by: Python
    To be destroyed by: C/C++
    Parent wrapper: NULL
    Next sibling wrapper: NULL
    Previous sibling wrapper: NULL
    First child wrapper: NULL

这是我的代码

对话框 ui和生成文件可以从DropBox
dialog.ui和dialog.py下载。

主要

import sys
from PyQt4.QtGui import QDialog, QApplication
from dialog import Ui_Form
from WidgetReplacer import WidgetReplacer

class Dialog(QDialog, Ui_Form):

    def __init__(self, parent = None):
        super(Dialog, self).__init__(parent)

        # Set up the user interface from Designer.
        self.setupUi(self)
        WidgetReplacer().replace_all_qlineedit(self)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Dialog()

    window.show()

    print window.txt_line_1
    window.txt_line_1.setText("Hello Text 1")

    sys.exit(app.exec_())

线编辑

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 "----------------------------------"

问题答案:

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

宣传小部件以使用自定义类的方法如下:

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

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

    from myapp.LineEdit import LineEdit


 类似资料:
  • 问题内容: 假设我在Spring容器中定义了一个bean(例如BeanA),并且此bean被注入到对象中。(例如BeanAUser) 在运行时,我可以使用另一个bean实例替换spring容器中的原始BeanA吗?并且还将这个新的bean实例重新注入BeanAUser中以替换原始的BeanA吗? 问题答案: 使用代理可以轻松实现。创建接口的委派实现,并切换要委派的对象。

  • 我刚来盖茨比 查询本身非常适合在构建时获取数据,并将其作为道具传递给呈现每个菜单项的菜单组件。但是,在运行时,我希望再次从数据库中提取数据,并让它更新数据,例如,如果有价格变化,等等。 我知道我可以重建整个项目,但我希望这是一个后备方案。 如何让查询将数据发送到Menu组件,然后[再次发送数据?]当DB调用完成时。 当前未按预期工作的代码: index.jsx

  • 问题内容: 我有一个小部件,当切换选项时,它会改变。这会使所有布局和小部件失效。我保留所有布局的列表,因此可以使用类似于以下答案的方法删除它们: 如何摆脱旧的布局并设置新的布局? 该文档非常简洁,显然不适用于python: QWidget.setLayout(self,QLayout) QLayout参数将其所有权转移到Qt。 将此窗口小部件的布局管理器设置为布局。 如果此小部件上已经安装了布局管

  • 问题内容: 请考虑以下情形。我有一个带有bean的Spring应用程序上下文,该bean的属性应该是可配置的,认为或。可变的应用程序配置由单独的Bean管理,我们称之为。 管理员现在可以更改配置值,例如电子邮件地址或数据库URL,我想在运行时重新初始化配置的bean。 假设我不能只是简单地修改上述可配置bean的属性(例如,通过或构造函数注入创建),而必须重新创建bean本身。 关于如何实现这一点

  • 我使用Netbeans和JavaFx Scene Builder构建了一个JavaFx项目。 在我完成复制粘贴之前,一切工作都很顺利。 这些文件是: 以下是文件:

  • TL;dr:有可能制作一个可重复使用的模板文字吗? 我一直在尝试使用模板文字,但我想我只是不明白,现在我很沮丧。我的意思是,我想我明白了,但“它”不应该是它的工作方式,或者它应该如何得到。它应该会有所不同。 我看到的所有示例(甚至标记的模板)都要求在声明时而不是运行时进行“替换”,这对我来说对模板来说是完全无用的。也许我疯了,但对我来说,“模板”是一个文档,它包含在使用时被替换的标记,而不是在创建