I am new to the world of PyQt.I am using PyQt designer for designing the UI and coding to provide functionality in it.But unfortunately I am getting confused to link with the UI.By importing the class we generally doing in examples.But when I try my own code its not happening.
Any hints for how designer and other parts interacts will be super helpful.
Thanks in advance!
Have you tried:
class ImageViewer(QtGui.QMainWindow, ImageViewerUI.Ui_MainWindow):
because by default pyuic4 create the class Ui_MainWindow and not Ui_mainWindow
winBase, winForm = uic.loadUiType("mainWindow.ui") # this is the
file created whith Qt Designer
class Window(winBase, winForm):
def __init__(self, parent = None)
super(winBase, self).__init__(parent)
self.setupUi(self)
Related
I need to add some features to a graphics widget in a form I created using the Qt Designer.
For example I would normally do something like this:
class custom_gv(QGraphicsView):
def __init__(self):
super().__init__()
def zoom(self):
# custom code here
But in this case the graphics view is a part of the window I made in Qt Designer. I know you can use the "promote to" feature in Qt designer but I don't know how to utilise that in code, especially considering that I use this method to use Qt Designer windows:
from PyQt5.uic import loadUiType
custom_window = loadUiType('ui.ui')
class Window(QMainWindow, custom_window):
def __init__(self):
QMainWindow.__init__(self)
custom_window.__init__(self)
self.setupUi(self)
So how would I go about customising the code of the graphics view in my window when I use Qt Designer?
The most common way to solve this is by using widget promotion. This will allow you to replace a widget defined in Qt Designer with your own custom class. The steps for doing this are as follows:
In Qt Designer, select the QGraphicsView you want to replace, then right-click it and select Promote to... . In the dialog, set Promoted class name to "custom_gv", and set Header file to the python import path for the module that contains this class (e.g. "mypkg.widgets"). Then click Add, and Promote, and you will see the class change from "QGraphicsView" to "custom_gv" in the Object Inspector pane.
When the Qt Designer ui file is converted into PyQt code, it will automatically add an import statement like this:
from mypkg.widgets import custom_gv
and then in the converted code it will replace something like this:
self.graphicsView = QtWidgets.QGraphicsView(MainWindow)
with this:
self.graphicsView = custom_gv(MainWindow)
So the code in the ui file knows nothing about the custom class: it's just a name that is imported from elsewhere. That means you are completely free to write the custom class in any way you like.
In PyQt, this mechanism works in the same way with pyuic as it does with the uic module. The loadUi and loadUiType functions generate exactly the same code as pyuic does. The only difference is that the pyuic tool writes the generated code to a file, whereas the uic module loads it directly via exec.
I can't get the GUI for my application to run in the manner that I need it to. My question is, given the below criteria, how do I go about setting up and running the GUI properly. The lack of good documentation that I have found is insanely frustrating (maybe I'm looking in the wrong places?).
I have a main window in a file called MainCustomerWindow.py containing a class by the same name. This is where all the code from the qt designer is. I have another class file called GUIController. The GUIController class does just that, controls the multiple GUI windows. It is in this GUIController class that I am trying to instantiate and run the MainCustomerWindow. Here is the code I have been trying.
def setup_window(self):
APP = QtWidgets.QApplication(sys.argv)
Window = MainCustomerWindow()
Window.setupUi(QtWidgets.QMainWindow)
Window.show()
sys.exit(APP.exec_())
Just as a side note, I come from JavaFX and Swing, and don't fully understand the workflow for pyqt5. So if someone could add an explanation for that as well it would be greatly appreciated.
The class generated by Qt Designer is not a widget, it is a class used to fill an existing widget, so you must create an object in the window, assuming you have used the "Main Window" template, then the widget must be QMainWindow (if it is another maybe you should use QDialog or QWidget), then you have to create another class that belongs to the design, and using the method setupUi() you must pass the widget to fill it:
def setup_window(self):
app = QtWidgets.QApplication(sys.argv)
# create window
window = QtWidgets.QMainWindow()
ui = MainCustomerWindow()
# fill window
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
Although a better option is to create a new class and have it inherit from both:
class MainWindow(QtWidgets.QMainWindow, MainCustomerWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
If you want to get detailed information I recommend you read the following:
http://pyqt.sourceforge.net/Docs/PyQt5/designer.html
You can try taking the code you have there and adding it to the main statement at the end of your app's script. You can also have this statement instantiate your class where the init method contains the setupui() call. For example:
if __name__ == '__main__':
app = QWidgets.QApplication(sys.argv)
window = QMainWindow()
main_window = MainCustomerWindow()
window.show()
sys.exit(app.exec())
This code first sets up the PyQt app as an instance of QApplication. Next it instantiates an instance of QMainWindow so that PyQt knows what to display as the main app starts. In my experience, I've put setupui() in the init method of the app class. In your case, in the init method of MainCustomerWindow Finally, window.show() tells PyQt to begin rendering the main window.
This question already has answers here:
QtDesigner changes will be lost after redesign User Interface
(2 answers)
Closed 4 years ago.
I've been looking for a better way to work with frontends made using qtDesigner connected to a python backend. All the methods I have found have the following form:
Make GUI in designer
Output to python code using pyuic (usually with -x option)
Write backend code inside this output file
This methodology is not simple to maintain or edit. Any time you change the UI, it completely breaks workflow: you have to reconvert, generate a new file, fix that file back up to where you were before, then finally get back on track. This requires a lot of manual copy-paste of code, which is an invitation to errors on multiple levels (newly generated file layout may not be the same, manually fixing name changes while pasting, etc.). You can also end up losing work if you aren't careful, since you could accidentally overwrite the file and destroy the backend code.
Also, this doesn't use any of the control in qtDesigner like the Signal/Slot and Action editors. These must be here for something, but I can't find a way to actually direct these to call backend functions.
Is there a better way to work with this, possibly using the features of qtDesigner?
You don't have to add your code in the output file :
If you take a 'home.py' generated by PYUIC, containing a QMainWindow which name set by QtDesigner/generated by Puic would be Ui_Home(), your main code could be :
from home import Ui_Home
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class window_home(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
#set up the user interface from Designer
self.ui = Ui_Home()
self.ui.setupUi(parent)
#then do anything as if you were in your output file, for example setting an image for a QLabel named "label" (using QtDesigner) at the root QMainWindow :
self.ui.label.setPixmap(QPixmap("./pictures/log.png"))
def Home():
f=QMainWindow()
c=window_home(f)
f.show()
r=qApp.exec_()
if __name__=="__main__":
qApp=QApplication(sys.argv)
Home()
I found an even cleaner method for working with this, that does not require preemptive conversion after each edit at all. Instead it takes the .ui file itself, so all you need to do is restart the program itself to update the design.
import sys
import os
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5 import uic
path = os.path.dirname(__file__) #uic paths from itself, not the active dir, so path needed
qtCreatorFile = "XXXXX.ui" #Ui file name, from QtDesigner, assumes in same folder as this .py
Ui_MainWindow, QtBaseClass = uic.loadUiType(path + qtCreatorFile) #process through pyuic
class MyApp(QMainWindow, Ui_MainWindow): #gui class
def __init__(self):
#The following sets up the gui via Qt
super(MyApp, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
#set up callbacks
self.ui.NAME OF CONTROL.ACTION.connect(self.test)
def test(self):
#Callback Function
if __name__ == "__main__":
app = QApplication(sys.argv) #instantiate a QtGui (holder for the app)
window = MyApp()
window.show()
sys.exit(app.exec_())
Note that this is Qt5. Qt5 and Qt4 are not API compatible, so it will be a little different in Qt4 (and presumably earlier as well).
I need to add some features to a graphics widget in a form I created using the Qt Designer.
For example I would normally do something like this:
class custom_gv(QGraphicsView):
def __init__(self):
super().__init__()
def zoom(self):
# custom code here
But in this case the graphics view is a part of the window I made in Qt Designer. I know you can use the "promote to" feature in Qt designer but I don't know how to utilise that in code, especially considering that I use this method to use Qt Designer windows:
from PyQt5.uic import loadUiType
custom_window = loadUiType('ui.ui')
class Window(QMainWindow, custom_window):
def __init__(self):
QMainWindow.__init__(self)
custom_window.__init__(self)
self.setupUi(self)
So how would I go about customising the code of the graphics view in my window when I use Qt Designer?
The most common way to solve this is by using widget promotion. This will allow you to replace a widget defined in Qt Designer with your own custom class. The steps for doing this are as follows:
In Qt Designer, select the QGraphicsView you want to replace, then right-click it and select Promote to... . In the dialog, set Promoted class name to "custom_gv", and set Header file to the python import path for the module that contains this class (e.g. "mypkg.widgets"). Then click Add, and Promote, and you will see the class change from "QGraphicsView" to "custom_gv" in the Object Inspector pane.
When the Qt Designer ui file is converted into PyQt code, it will automatically add an import statement like this:
from mypkg.widgets import custom_gv
and then in the converted code it will replace something like this:
self.graphicsView = QtWidgets.QGraphicsView(MainWindow)
with this:
self.graphicsView = custom_gv(MainWindow)
So the code in the ui file knows nothing about the custom class: it's just a name that is imported from elsewhere. That means you are completely free to write the custom class in any way you like.
In PyQt, this mechanism works in the same way with pyuic as it does with the uic module. The loadUi and loadUiType functions generate exactly the same code as pyuic does. The only difference is that the pyuic tool writes the generated code to a file, whereas the uic module loads it directly via exec.
I'm working on a plugin for Avogadro (chemistry software) that uses pyqt.
I've some problem with connecting a method to the clicked signal of a button.
I've my class:
class Controller(object):
def __init__(self):
self.ui = MyDialog() # self.ui.run is a QPushButton
self.ui.run.clicked.connect(self.on_run_click)
def on_run_click(self):
1/0
class MyDialog(QDialog,Ui_Dialog): # ui designer compiled
def __init__(self):
QDialog.__init__(self)
self.setupUi(self)
Why when I click the button the on_run_click isn't called?
Unless they've considerably changed something recently, this doesn't seem like the way to connect signals in PyQt. I'm more used to:
self.connect(self.ui.run, QtCore.SIGNAL("clicked()"),
self, QtCore.SLOT("on_run_click()"))
The problem is that Avogadro python wrappers don't support the new signal syntax as described in Tim's blog post:
http://timvdm.blogspot.com/2008/12/avogadro-gets-new-python-wrappers.html