python - PyQt4: Replace QWidget objects at runtime -
in application have replace qlineedit elements customized qlineedit. there different solutions:
- modify generated py file pyuic4 , replace there qlineedit objects 1 lineedit. solution not best, because every time run pyuic4 lose modification did generated output file.
- write new class search recursively inside window or dialog qlineedit widget types , replace them 1 lineedit. solution better. allows me same other objects or extend want without care dialog or window.
so far, write module (widgetreplacer) search recursively qgridlayout items , search if there qlineedit children. if yes, replace one.
the problem when try access 1 of lineedit objects following error:
runtimeerror: wrapped c/c++ object of type qlineedit has been deleted
and if @ output notice modified qlineedit object has sitll old id:
old qt_obj <pyqt4.qtgui.qlineedit object @ 0x0543c930> replaced txt_line_1 lineedit new qt_obj <lineedit.lineedit object @ 0x0545b4b0> ---------------------------------- ... ---------------------------------- <pyqt4.qtgui.qlineedit object @ 0x0543c930>
question
why happen this? how can replace qwidgets @ runtime?
update
here additional details regarding ojects wrapping: inside module widgetreplace if dump qeditline , lineedit objects get:
<pyqt4.qtgui.qlineedit object @ 0x05378618> reference count: 7 address of wrapped object: 051fac40 created by: python destroyed by: c/c++ parent wrapper: <pyqt4.qtgui.qgridlayout object @ 0x05378588> next sibling wrapper: null previous sibling wrapper: <pyqt4.qtgui.qlabel object @ 0x05378930> first child wrapper: null
and
<lineedit.lineedit object @ 0x05378978> reference count: 3 address of wrapped object: 051fac40 created by: python destroyed by: c/c++ parent wrapper: <__main__.dialog object @ 0x0535fbb8> next sibling wrapper: <pyqt4.qtgui.qgridlayout object @ 0x05378780> previous sibling wrapper: null first child wrapper: null
instead if dump line edit main, follow, represent deleted qlineedit object:
<pyqt4.qtgui.qlineedit object @ 0x05378618> reference count: 2 address of wrapped object: 00000000 created by: python destroyed by: c/c++ parent wrapper: null next sibling wrapper: null previous sibling wrapper: null first child wrapper: null
here code
dialog ui , generate file can dowloaded dropbox dialog.ui , dialog.py
main
import sys pyqt4.qtgui import qdialog, qapplication dialog import ui_form widgetreplacer import widgetreplacer class dialog(qdialog, ui_form): def __init__(self, parent = none): super(dialog, self).__init__(parent) # set user interface 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_())
lineedit
from pyqt4.qtgui import qlineedit, qvalidator, qpalette 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 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 lineedit import lineedit pyqt4.qtcore import qregexp pyqt4 import qtgui class widgetreplacer(): def __init__(self): pass def replace_all_qlineedit(self, qt_dlg): children = self._get_all_gridlayout(qt_dlg) items = [] child in children: new_items = self._find_all_obj_in_layout(child, qtgui.qlineedit) items.extend(new_items) 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() in range(layout_rows): 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") # 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 "----------------------------------"
don't replace widgets @ runtime: promote widgets in qt designer line-edits automatically replaced custom class when gui module generated.
here's how promote widget use custom class:
in qt designer, select line-edits want replace, right-click them , select "promote to...". in dialog, set "promoted class name" "lineedit", , set "header file" python import path module contains class (e.g. myapp.lineedit
). click "add", , "promote", , see class change "qlineedit" "lineedit" in object inspector pane.
now when re-generate ui module pyuic, should see uses custom lineedit class , there line @ bottom of file this:
myapp.lineedit import lineedit
Comments
Post a Comment