Loading A PyQt5 UI Via A Class - python

I'm currently trying to update my PySide code using PyQt5. And I have a class called "loader.py" that used to use "QUiLoader" from "PySide.QtUiTools", but as far as I know in PyQt5 this module has been changed by "uic".
So the problem here is that I changed my "QUiLoader" import from "uic" but I always get this error:
ui_loader.py", line 4, in <module> class UiLoader(uic): TypeError: module() takes at most 2 arguments (3 given)
Original Code in Pyside
Here is where I got the code for my PySide app
Code in PyQt5
ui_loader.py
from PyQt5 import uic
from PyQt5.QtCore import QMetaObject
class UiLoader(uic):
def __init__(self, base_instance):
uic.__init__(self, base_instance)
self.base_instance = base_instance
def createWidget(self, class_name, parent=None, name=''):
if parent is None and self.base_instance:
return self.base_instance
else:
# create a new widget for child widgets
widget = uic.createWidget(self, class_name, parent, name)
if self.base_instance:
setattr(self.base_instance, name, widget)
return widget
def load_ui(ui_file, base_instance=None):
loader = UiLoader(base_instance)
widget = loader.load(ui_file)
QMetaObject.connectSlotsByName(widget)
return widget
main.py
from PyQt5.QtWidgets import QMainWindow, QApplication
from ui_loader import load_ui
import sys
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
load_ui('my_interface.ui', self)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
main()
I have also tried to used submethod of the class and refactoring all the code but it was useless.

You can actually load the ui using uic and then just inherit that ui into a class then self.setupUI()
ui_MainWindow, QtBaseClass = uic.loadUiType("main_window.ui")
class MainWindow(QMainWindow, ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
Another way as musicamante is suggesting would be like this:
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("main_window.ui", self)

Related

pyqt5 "AttributeError: type object 'Window' has no attribute label" but it does?

I am trying to create a UI for a text game.
This works fine, however I wanted to create my own simple print function to print to the parts of the UI (in the example the QLabel) this works, if the function is in the UI file but when I move the functions to another file, I get
"AttributeError: type object 'Window' has no attribute 'label'"
even though my IDE says Window.label exists before running it.
Is this some quirk or QT? or am I making a mistake?
UI.py
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.show()
import game
self.label = QLabel("Text")
self.label.setAlignment(Qt.AlignCenter | Qt.AlignTop)
self.output = QTextEdit()
self.output.setReadOnly(True)
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(self.label,0,0,1,10)
grid.addWidget(self.output,1,0,10,10)
self.setLayout(grid)
game.Game.test()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
sys.exit(app.exec_())
Game.py
from UI import Window
class Game():
def print_UI(self,*Args, **Kwargs):
Window.setup.output.insertPlainText(*Args, **Kwargs)
def print_label(self,*Args, **Kwargs):
Window.label.setText(*Args, **Kwargs)
def test():
Game.print_label("HI")
You can pass window object as a parameter to the constructor of Game instead of importing game in Window class and importing Window again in game as that was leaving the label member uninitialized
UI.py
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import game
class Window(QWidget):
def __init__(self):
super().__init__()
self.show()
self.label = QLabel("Text")
self.label.setAlignment(Qt.AlignCenter | Qt.AlignTop)
self.output = QTextEdit()
self.output.setReadOnly(True)
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(self.label,0,0,1,10)
grid.addWidget(self.output,1,0,10,10)
self.setLayout(grid)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
game.Game(ex).test()
sys.exit(app.exec_())
game.py
class Game():
def __init__(self,window):
self.Window = window
def print_UI(self,*Args, **Kwargs):
self.Window.setup.output.insertPlainText(*Args, **Kwargs)
def print_label(self,*Args, **Kwargs):
self.Window.label.setText(*Args, **Kwargs)
def test(self):
self.print_label("HI")
I believe the issue is that you're trying to do object-oriented programming, but not actually doing object-oriented programming. For instance, you're trying to use your Window class within Game.py's Game class by just importing it and calling its functions. Instead, what you've got to do is use inheritance. Namely, your Game.py's Game class should inherit from your UI.py's Window class.
Change your Game.py to the following:
from UI import Window
class Game(Window): # Game is inheriting from Window
def __init__(self):
Window.__init__(self) # Game is inheriting Window class attributes & functions
def print_UI(self,*Args, **Kwargs):
self.setup.output.insertPlainText(*Args, **Kwargs) # self refers to Game as well as Window class
def print_label(self,*Args, **Kwargs):
self.label.setText(*Args, **Kwargs) # self refers to Game as well as Window class
def test():
Game.print_label("HI")
Instead of using Window.__init__(self), you can check out an explanation of the super() function.

How to show the stackwidget?

I'm trying to use the stackWidget to show different widgets .
However when I pressed the item on the listWdget , stackWidget below will not be displayed.
Here is my code,and I don't know where is wrong.
#!/usr/bin/python
# music_1.py
import sys
from PyQt4 import QtGui, QtCore
from music_ui import Ui_Form
class music(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.listWidget.insertItem(0,("Warm"))
self.ui.listWidget.insertItem(1,("Funny"))
self.ui.listWidget.insertItem(2,("Terror"))
self.ui.stackedWidget=QtGui.QStackedWidget()
warm=Warm()
funny=Funny()
terror=Terror()
self.ui.stackedWidget.addWidget(warm)
self.ui.stackedWidget.addWidget(funny)
self.ui.stackedWidget.addWidget(terror)
self.connect(self.ui.listWidget,QtCore.SIGNAL("currentRowChanged(int)"),self.ui.stackedWidget,QtCore.SLOT("setCurrentIndex(int)"))
class Warm(QtGui.QWidget):
def __init__(self,parent=None):
super(Warm,self).__init__(parent)
w1=QtGui.QPushButton("w1")
w2=QtGui.QPushButton("w2")
buttonLayout=QtGui.QHBoxLayout()
buttonLayout.addStretch(1)
buttonLayout.addWidget(w1)
buttonLayout.addWidget(w2)
class Funny(QtGui.QWidget):
def __init__(self,parent=None):
super(Funny,self).__init__(parent)
f1=QtGui.QPushButton("f1")
f2=QtGui.QPushButton("f2")
f3=QtGui.QPushButton("f3")
buttonLayout=QtGui.QHBoxLayout()
buttonLayout.addStretch(1)
buttonLayout.addWidget(f1)
buttonLayout.addWidget(f2)
buttonLayout.addWidget(f3)
class Terror(QtGui.QWidget):
def __init__(self,parent=None):
super(Terror,self).__init__(parent)
t1=QtGui.QPushButton("t1")
t2=QtGui.QPushButton("t2")
buttonLayout=QtGui.QHBoxLayout()
buttonLayout.addStretch(1)
buttonLayout.addWidget(t1)
buttonLayout.addWidget(t2)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = music()
myapp.show()
sys.exit(app.exec_())
I never worked with UI Files but this is my guess:
self.ui.stackedWidget=QtGui.QStackedWidget()
here you create a QStackedWidget which gets assigned to the class. The problem is that it is not added to the UI that is getting displayed but just to the instance of the Ui_Form. What you have to do is either:
Add the QStackedWidget in the UI Designer and erase the line above
or
Add the QStackedWidget to one of your layouts
which can be done like this:
self.ui.mySuperCoolLayout.addWidget(self.ui.stackedWidget)

PyQt: Trying to display SQLite DB in QTableView: 'argument 1 has unexpected type 'PyQt4.QtCore.pyqtWrapperType'

Ok, I fixed it, make sure to call the class with Model()
However, the below code does not work, and results in segfault for some reason. I fixed it by putting the DB and model stuff directly into the main GUI class.
I have a Ui element called table, and following code:
import sqlite3
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import QtSql
from PyQt4.Qt import *
from ui.mainWindow import *
class Database(QtSql.QSqlDatabase) :
def __init__(self, parent = None):
super(Database, self).__init__(parent)
self.addDatabase("QSQLITE")
self.setDatabaseName('/db/daily.sql')
self.open()
class Model(QtSql.QSqlTableModel):
def __init__(self, parent = None, db=Database()):
super(Model, self).__init__(parent)
self.setTable('body')
self.select()
class Gui(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self,parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.tableModel = Model()
self.ui.table.setModel(self.tableModel)
self.ui.table.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = Gui()
myapp.show()
sys.exit(app.exec_())
And get the following error:
TypeError: QTableView.setModel(QAbstractItemModel): argument 1 has unexpected type 'PyQt4.QtCore.pyqtWrapperType'
If I set up the Database and Model directly in the Gui class, the program starts, but the table is empty (DB is populated).
What causes this error?

Qt mdi application with custiom UI from QtDesigner

Assume I have two UI files from Qt Designer:mainform.ui stores mdiArea and figureslist.ui stores listView.
Now I'd like to create a mdi application, that can open numbers of figureList windows.
import sys
from PyQt4 import QtGui
#from PyQt4.QtGui import *
from PyQt4 import QtCore, QtGui, uic
class HelloWorldApplication(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self, args)
self.maindialog = MainUI(None)
class MainUI(QtGui.QMainWindow):
def __init__(self, parent):
QtGui.QMainWindow.__init__(self, parent)
self.ui = uic.loadUi("mainform.ui")
self.ui.show()
# create child and show it
child = self.createFiguresListView()
# problem here (*)
child.show()
def createFiguresListView(self):
child = FiguresListView()
self.ui.mdi.addSubWindow(child)
return child
class FiguresListView(QtGui.QWidget):
def __init__(self):
super(FiguresListView, self).__init__()
self.ui = uic.loadUi("figureslist.ui")
app = HelloWorldApplication(sys.argv)
sys.exit(app.exec_())
But unfortunately my child window shows up collapsed without layout described in figureslist.ui, but acts like mdi child, but if I replace code marked with (*) to child.ui.show() it shows actual layout, but doesn't act like mdi child.
What's wrong?
You forgot to set the parent for the ui (also, if you didn't specified minimum size in Designer, you need to do it here):
class FiguresListView(QtGui.QWidget):
def __init__(self):
super(FiguresListView, self).__init__()
self.ui = uic.loadUi("figureslist.ui", self)
#self.setMinimumSize(400, 200)

PyQt : why adding a dummy class definition in my file make the application crash?

Consider the code below:
#!/usr/bin/env python
from PyQt4 import QtCore, QtGui
import os,sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.listWidget = QtGui.QListWidget(None)
self.setCentralWidget(self.listWidget)
if __name__ == '__main__':
app = QtGui.QApplication (sys.argv)
mainWin = MainWindow ()
mainWin.show ()
sys.exit (app.exec_())
Works ok.
Now if I add a dummy class (that inherits from a QtGui module's class) in the global scope ...
class MainWindow(QtGui.QMainWindow):
... # unchanged
class MyWidget(QtGui.QWidget):
def __init__(self):
super(MyWidget, self).__init__()
if __name__ == '__main__':
... # unchanged
... when i launch the script i get the error:
TypeError: argument 1 of
QMainWindow.setCentralWidget() has an
invalid type
This error message is cryptic for me as i can't connect it to the modification done.
Do you have an idea what could be the source of this error?
Can't reproduce the problem as reported: the following exact code
from PyQt4 import QtCore, QtGui
import os, sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.listWidget = QtGui.QListWidget(None)
self.setCentralWidget(self.listWidget)
class MyWidget(QtGui.QWidget):
def __init__(self):
super(MyWidget, self).__init__()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
runs just fine for me (showing an empty window of course). So I guess it's down to versions details! I'm using system-supplied Python 2.5.1 on Mac OS X 10.5.7 and adding a
print QtCore.PYQT_VERSION_STR
shows I'm on version 4.5.1 of PyQt. What about you?
I have not worked with PyQt before, but didn't you forget to call the constructor of the superclass here?
class MyWidget(QtGui.QWidget):
def __init__(self):
# Where is the call to QtGui.QWidget's init ?
pass

Categories