In my application I have to replace all QLineEdit elements with customized QLineEdit. To do that there are different solutions:
Modify the generated py file from pyuic4 and replace there all QLineEdit objects with my one LineEdit. This solution is not really the best, because every time I run pyuic4 I lose the modification I did into the generated output file.
Write a new class that search recursively inside my window or dialog for QLineEdit widget types and replace them with my one LineEdit. This solution is much better. It allows to me to do the same also with other objects or extend it as I want without to care about the dialog or window.
So far, I could write a module (WidgetReplacer) which search recursively for QGridLayout items and search if there are QLineEdit children. If yes, then replace it with my one.
The problem is that when I try to access one of my LineEdit objects I get the following error:
RuntimeError: wrapped C/C++ object of type QLineEdit has been deleted
And if I look at my output I notice that the modified QLineEdit object has sitll the old 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>
Question
Why happen this? How can I replace QWidgets at runtime?
Update
Here some additional details regarding the ojects wrapping:
Inside the module WidgetReplace if I dump the QEditLine and LineEdit objects I get:
<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
and
<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
Instead if I dump my line edit from the main, I get follow, which represent the deleted QLineEdit object:
<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
Here my code
Dialog
The ui and generate file can be dowloaded from DropBox dialog.ui and dialog.py
main
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_())
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 "----------------------------------"
Don't replace the widgets at runtime: promote the widgets in Qt Designer so that the line-edits are automatically replaced by your custom class when the GUI module is generated.
Here's how to promote a widget to use a custom class:
In Qt Designer, select all the line-edits you want to replace, then right-click them and select "Promote to...". In the dialog, set "Promoted class name" to "LineEdit", and set "Header file" to the python import path for the module that contains this class (e.g. myapp.LineEdit). Then click "Add", and "Promote", and you will see the class change from "QLineEdit" to "LineEdit" in the Object Inspector pane.
Now when you re-generate your ui module with pyuic, you should see that it uses your custom LineEdit class and there will be an extra line at the bottom of the file like this:
from myapp.LineEdit import LineEdit
I didn't go through all of your code...
My guess though is, that even though you've replaced the widget in the layout, window.txt_line_1 still points to the deleted object.
So, in your replacement-procedure you'll also have to update this attribute.
So, adding
setattr(parent, obj_name, qt_obj);
to _replace_qlineedit_from_gridlayout might do the trick.
Related
I want to get the submenu That is QuitProgram <- This is name of submenu but it is in UI file.
How can I get it in a variable set its action to quit program?
File menu object name is 'actionQuit_FromProgram' <- This is a submenu.
Python File:
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QFileDialog, QMenuBar
from PyQt5.QtGui import *
import sys
import os
import qdarkgraystyle
path = os.path.abspath(os.getcwd())
import qrcode
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('main.ui', self)
#self.show()
self.button = self.findChild(QtWidgets.QPushButton, 'qrgenerator')
self.button.clicked.connect(self.QrCodeGenerator) # Remember to pass the definition/method, not the return value!
self.input = self.findChild(QtWidgets.QLineEdit, 'qredit')
self.button1 = self.findChild(QtWidgets.QPushButton, 'qropen')
self.button1.clicked.connect(self.OpenQRCode)
self.menu1 = self.findChild(QMenuBar,'actionQuit_FromProgram')
print(self.menu1)
#self.menu1.triggered.connect(qApp.quit)
self.show()
def QrCodeGenerator(self):
# Generate QR code
self.url = qrcode.make(self.qredit.text())
if self.qredit.text() == '':
QMessageBox.warning(self, "Error", "Please Type In Something To Generate Qr Code")
else:
self.url.save("filename.png","PNG")
def OpenQRCode(self):
fname = QFileDialog.getOpenFileName(self, 'Open file',
path,"Image files (*.jpg *.gif *.png *.svg)")[0]
self.label_2.setPixmap(QPixmap(fname))
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(qdarkgraystyle.load_stylesheet())
window = Ui()
app.exec_()
If you're using loadUi (or setupUi if you're using files generated by pyuic), all elements in the object inspector (the tree view that lists all widgets on your UI) become available as instance attributes, according to their object name.
So, if your action is called actionQuit_FromProgram in the inspector, you can directly access it using self.actionQuit_FromProgram.
This also means that:
all those findChild are absolutely useless: you already have access to self.qrgenerator, self.qredit, etc;
in any case, findChild should be used with the correct class of the object you're looking for: I sincerely doubt that actionQuit_FromProgram is a QMenuBar (so, using findChild(QMenuBar, ...) won't work at all; if it is an action, use findChild(QAction, ...); if it's a submenu, use findChild(Qmenu, ...);
there's usually just one menu bar for each QMainWindow, and it is easily accessible using self.menuBar();
Using PyQt 5 I have been trying to find a way to get the old parent from a drag and drop operation on an item in a QTreeView situation using QStandardItemModel and QStandarItems.
I really want to avoid creating my own model if possible.
My current attempt is to store the current parent in the item when it is created as the "old parent" and it should not be updated in the move so I can reference it update the values in the old parent items and then update the "old parent" in the moved item to the new current parent.
I can not seem to get it to work though, here is the code I am trying to use to store the "old parent" when the item is created:
item.setData(parent.index(),(Qt.UserRole+3))
When I run this however I get the following error:
QVariant::save: unable to save type 'QModelIndex' (type id: 42).
and I can not reference the old parent at this point...
I found one reference using c++ and a lot of "pointer casting" but I could not figure out how to convert the code to Python and PyQt 5.
C++ Reference: https://forum.qt.io/topic/1690/qvariant-save-load-unable-to-save-type-x/19
Thanks for any help!
The model has some signals that fire whenever an item's children are inserted or removed, so these could be used to automatically update the item.
After some experimentation, I found that the signals need to be used with a queued connection, so that the model has a chance to fully update:
model.rowsInserted.connect(slot, type=QtCore.Qt.QueuedConnection)
model.rowsRemoved.connect(slot, type=QtCore.Qt.QueuedConnection)
But other than that, the implementation is quite simple. There is no need to store any extra information in the items, as the updates can be performed dynamically.
Here is a basic demo script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Window(QtWidgets.QTreeView):
def __init__(self):
super(Window, self).__init__()
self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
self.setDragDropOverwriteMode(False)
self.header().hide()
model = QtGui.QStandardItemModel(self)
model.rowsInserted.connect(
self.sumItems, type=QtCore.Qt.QueuedConnection)
model.rowsRemoved.connect(
self.sumItems, type=QtCore.Qt.QueuedConnection)
self.setModel(model)
parent = model.invisibleRootItem()
for index in range(3):
item = QtGui.QStandardItem('0')
parent.appendRow(item)
for row in range(1, 5):
child = QtGui.QStandardItem(str(row))
item.appendRow(child)
self.expandAll()
def sumItems(self, index, first, last):
if index.isValid():
total = 0
parent = self.model().itemFromIndex(index)
for row in range(parent.rowCount()):
child = parent.child(row)
if child is not None:
total += int(child.text())
parent.setText(str(total))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(700, 100, 250, 300)
window.show()
sys.exit(app.exec_())
In my application I have to replace all QLineEdit elements with customized QLineEdit. To do that there are different solutions:
Modify the generated py file from pyuic4 and replace there all QLineEdit objects with my one LineEdit. This solution is not really the best, because every time I run pyuic4 I lose the modification I did into the generated output file.
Write a new class that search recursively inside my window or dialog for QLineEdit widget types and replace them with my one LineEdit. This solution is much better. It allows to me to do the same also with other objects or extend it as I want without to care about the dialog or window.
So far, I could write a module (WidgetReplacer) which search recursively for QGridLayout items and search if there are QLineEdit children. If yes, then replace it with my one.
The problem is that when I try to access one of my LineEdit objects I get the following error:
RuntimeError: wrapped C/C++ object of type QLineEdit has been deleted
And if I look at my output I notice that the modified QLineEdit object has sitll the old 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>
Question
Why happen this? How can I replace QWidgets at runtime?
Update
Here some additional details regarding the ojects wrapping:
Inside the module WidgetReplace if I dump the QEditLine and LineEdit objects I get:
<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
and
<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
Instead if I dump my line edit from the main, I get follow, which represent the deleted QLineEdit object:
<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
Here my code
Dialog
The ui and generate file can be dowloaded from DropBox dialog.ui and dialog.py
main
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_())
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 "----------------------------------"
Don't replace the widgets at runtime: promote the widgets in Qt Designer so that the line-edits are automatically replaced by your custom class when the GUI module is generated.
Here's how to promote a widget to use a custom class:
In Qt Designer, select all the line-edits you want to replace, then right-click them and select "Promote to...". In the dialog, set "Promoted class name" to "LineEdit", and set "Header file" to the python import path for the module that contains this class (e.g. myapp.LineEdit). Then click "Add", and "Promote", and you will see the class change from "QLineEdit" to "LineEdit" in the Object Inspector pane.
Now when you re-generate your ui module with pyuic, you should see that it uses your custom LineEdit class and there will be an extra line at the bottom of the file like this:
from myapp.LineEdit import LineEdit
I didn't go through all of your code...
My guess though is, that even though you've replaced the widget in the layout, window.txt_line_1 still points to the deleted object.
So, in your replacement-procedure you'll also have to update this attribute.
So, adding
setattr(parent, obj_name, qt_obj);
to _replace_qlineedit_from_gridlayout might do the trick.
In reference to a previous question, I need some help with keeping references in my application.
First a snippet from my code.
from PyQt4 import QtGui
import os, os.path
import sys
class mainWindowHandler():
equationEditor = []
_listview = None
_window = None
def __init__(self):
return
def showAddEquation(self):
"""Creates a new instance of the dynamic editor for adding an equation"""
#create a horizontal split layout
window = QtGui.QWidget()
layout = QtGui.QHBoxLayout()
current = len(self.equationEditor) - 1
de = QtGui.QPushButton(str(current))
self.equationEditor.append(de)
de.clicked.connect(self.clicked)
#fill list view with items from equation collection
listview = QtGui.QListWidget()
for equation in self.equationEditor:
item = QtGui.QListWidgetItem()
item.setText(equation.text())
listview.addItem(item)
layout.addWidget(listview)
layout.addWidget(de)
window.setWindowTitle("Equation {}".format(str(current))
window.setLayout(layout)
self._window = window
self._listview = listview
window.show()
return window
def clicked(self):
"""Method for handling the button events in the solver settings\n
signal = the button hit\n"""
return self.showAddEquation()
if __name__ == "__main__":
path = os.path.dirname(os.path.abspath(__file__))
app = QtGui.QApplication(sys.argv)
ewh = mainWindowHandler()
window = ewh.showAddEquation()
sys.exit(app.exec_())
The application will (later) create a window that allows the manipulation of certain settings - in my code example represented by the QPushButton. These settings are later written to a txt-file, but until then I save them in form of there widget. I simply add the widget to a collection and recall them from there. That works well on the Python-level.
Now, I have a button that creates a new instance of the window from inside of the window itself. That works too. But only until the third instance. At that point I loose the reference to my QPushButton on the Qt-level. I get the
wrapped C/C++ object of type `QPushButton` has been deleted
error when trying to retrieve the buttons from my collection (equationEditor). In Python they are still there, but obviously the corresponding Qt-objects where destroyed because I somewhere mishandled the references.
Can someone point out a better solution or how I can keep the references?
Thanks...
Edit:
As there seem to be some confusions I will try to explain the functionality a bit more in detail.
The program starts and creates a window "Equation 1" with a QListViewand a QPushButton "1". In the list view all available QPushButton are listed (at start only 1 item). In my actual program the QPushButton is QWidget with some text fields and the QPushButton.
If the user clicks "1" then the button "1" should disappear and a new instance of QPushButton named "2" should appear at the position of "1". Additionally, the listview should now hold two items "1" and "2" and the window should have the title "Equation 2". If it is a new window or the same as before with new contents is not relevant. Both variants would be okay. The former is the way it is implemented at the moment. Visible should by only one window at a time.
All instances of QPushButton should by collected in a small list (called equationEditor) to keep them in the memory. In my actual program this is used for saving all changes made in the widgets without writing the changes to a temp file.
Later, if the user selects item "1" in the QListView then the current visible QPushButton should be replaced by the QPushButton "1" (from the collection equationEditor) or if he selects the second item the QPushButton "2" should be shown.
Why?
The widget that will be used later contains a lot of editable data. As the user could edit that at any time it is easier to keep the widgets in memory without showing them instead of repopulating all the data again. As soon as the user selects one in the QListView the corresponding widget should be shown in the window so that he can edited the data in the widget again.
It's quite hard to understand what exactly you're trying to do. Looking at your code I wonder why it is even working twice before failing.
Btw. I just saw, that there is a quite accurate description of why it's failing in the previous post, given by Schollii
Anyways, I think you should make a new class for the equation window. The main class can then keep track of all opened windows in the equationEditor list. It can also add the values of the other opened windows to a new one, once created.
Here is how it would look like
from PyQt4 import QtGui
import os, os.path
import sys
class ShowAddEquation(QtGui.QWidget):
"""Creates a new instance of the dynamic editor for adding an equation"""
def __init__(self,parent=None):
super(ShowAddEquation, self).__init__(parent=parent)
#create a horizontal split layout
layout = QtGui.QHBoxLayout()
self.current = 0
self.de = QtGui.QPushButton(str(self.current))
self.listview = QtGui.QListWidget()
layout.addWidget(self.listview)
layout.addWidget(self.de)
self.setWindowTitle("Equation Editor")
self.setLayout(layout)
self.show()
def setCurrent(self, current):
self.current=current
self.de.setText(str(self.current))
class mainWindowHandler():
equationEditor = []
def __init__(self):
return
def clicked(self):
se = ShowAddEquation()
self.equationEditor.append(se)
se.de.clicked.connect(self.clicked)
current = len(self.equationEditor) - 1
se.setCurrent(current)
for equation in self.equationEditor:
item = QtGui.QListWidgetItem()
item.setText(str(equation.current))
se.listview.addItem(item)
if __name__ == "__main__":
path = os.path.dirname(os.path.abspath(__file__))
app = QtGui.QApplication(sys.argv)
ewh = mainWindowHandler()
ewh.clicked()
sys.exit(app.exec_())
So, after understanding the approach given in the first answer I have solved my problem. Here is the working code
# -*- coding: utf-8 -*-
"""
Created on Sat Sep 3 14:31:15 2016
"""
from PyQt4 import QtGui
from PyQt4 import QtCore
import os, os.path
import sys
class mainWindowHandler():
equationEditor = []
_listview = None
_window = None
def __init__(self):
return
def showAddEquation(self):
"""Creates a new instance of the dynamic editor for adding an equation"""
#create a horizontal split layout
self._window = QtGui.QWidget()
layout = QtGui.QHBoxLayout()
self._listview = QtGui.QListWidget()
layout.addWidget(self._listview)
self._listview.clicked[QtCore.QModelIndex].connect(self.changed)
self._window.setLayout(layout)
#populate the right side of the layout with a button
self.clicked()
self._window.show()
return self._window
def clicked(self):
"""Make a new button instance and add it to the window and the collection"""
window = self._window
layout = window.layout()
current = len(self.equationEditor) - 1
de = QtGui.QPushButton(str(current))
self.equationEditor.append(de)
de.clicked.connect(self.clicked)
#close the currently shown button
item = layout.takeAt(1)
if item is not None:
item.widget().close()
layout.addWidget(de)
#fill list view with items from material collection
item = QtGui.QListWidgetItem()
item.setText(de.text())
self._listview.addItem(item)
self._window.setWindowTitle("Equation Editor {}".format(str(current)))
def changed(self, index):
"""hide the object on the right side of the layout and show the button at position index in the collection"""
layout = self._window.layout()
item = layout.takeAt(1)
item.widget().close()
# insert the selected button from the collection
de = self.equationEditor[index.row()]
layout.insertWidget(1, de)
self._window.setWindowTitle("Equation Editor {}".format(str(index.row() - 1)))
de.show()
if __name__ == "__main__":
path = os.path.dirname(os.path.abspath(__file__))
app = QtGui.QApplication(sys.argv)
ewh = mainWindowHandler()
window = ewh.showAddEquation()
sys.exit(app.exec_())
I am developping an application with PyQt based on a QWidget. I put my whole app inside a class (named "Example"). Inside this app, I have a button which calls to another QWidget window (named "Report Widget") I designed on QtDesigner and opens it.
The problem is that I don't know how to do this. Here is the method I use (which comes from something I found on internet).
On my main class "Example", a method defines the Button calling for the "Report Widget" :
ReportBtn = QtGui.QPushButton("Generate report")
ReportBtn.clicked.connect(self.ShowReportWidget)
The second line calls the ShowReportWidget method of the Example (main) class :
def ShowReportWidget(self):
self.f = QtGui.QWidget()
self.ReportWidget = ReportWidget(self.f)
self.ReportWidget.show()
This method calls the class ReportWidget, which is a class from the Example (main) class :
class ReportWidget(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self)
self.ui = rw.Ui_ReportWidget()
self.ui.setupUi(parent)
and finally, this class refers to an outer class (Ui_ReportWidget), contained in another separate Python file (the one generated from the QtDesigner .ui file), which I import as rw in the beginning of my script.
The problem is that with this method, when I click on the Report Widget button, a new window pops but is empty. The content of the Ui_ReportWidget class is not loaded.
I hope my question is clear enough.
Thanks
SetupUi takes an Qwidget as input , while the init() function should take the calling QObject as the parent.
def ShowReportWidget(self):
self.f = QtGui.QWidget()
self.ReportWidget = ReportWidget(self)
self.ReportWidget.setupUi(self.f)
self.f.exec_()
class ReportWidget(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self,parent)
def setupUi(self,Widget):
self.ui = rw.Ui_ReportWidget()
self.ui.setupUi(Widget)