Working with PyQt and Qt designer ui files - python

I'm new to PyQt and I'm trying to work with ui files directly from within my PyQt script. I have two ui files, mainwindow.ui and landing.ui. Clicking on a button 'pushButton' on the main window should open the landing window. However, clicking on the button does not work as I expected. Here is the code(I'm just trying to work stuff out so the code is pretty rough):
from PyQt4 import QtCore, uic
from PyQt4 import QtGui
import os
CURR = os.path.abspath(os.path.dirname('__file__'))
form_class = uic.loadUiType(os.path.join(CURR, "mainwindow.ui"))[0]
landing_class = uic.loadUiType(os.path.join(CURR, "landing.ui"))[0]
def loadUiWidget(uifilename, parent=None):
uifile = QtCore.QFile(uifilename)
uifile.open(QtCore.QFile.ReadOnly)
ui = uic.loadUi(uifilename)
uifile.close()
return ui
#QtCore.pyqtSlot()
def clicked_slot():
"""this is called when login button is clicked"""
LandingPage = loadUiWidget(os.path.join(CURR, "landing.ui"))
center(LandingPage)
icon(LandingPage)
LandingPage.show()
class MyWindow(QtGui.QMainWindow, form_class):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.pushButton.clicked.connect(clicked_slot)
class LandingPage(QtGui.QMainWindow, landing_class):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
def center(self):
""" Function to center the application
"""
qRect = self.frameGeometry()
centerPoint = QtGui.QDesktopWidget().availableGeometry().center()
qRect.moveCenter(centerPoint)
self.move(qRect.topLeft())
def icon(self):
""" Function to set window icon
"""
appIcon = QtGui.QIcon("icon.png")
self.setWindowIcon(appIcon)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
pixmap = QtGui.QPixmap(os.path.join(CURR, "splash.png"))
splash = QtGui.QSplashScreen(pixmap)
splash.show()
app.processEvents()
MainWindow = MyWindow(None)
center(MainWindow)
icon(MainWindow)
MainWindow.show()
splash.finish(MainWindow)
sys.exit(app.exec_())
What mistake I'm I making??

There are two main problems with your script: firstly, you are not constructing the path to the ui files correctly; and secondly, you are not keeping a reference to the landing-page window (and so it will get garbage-collected immediately after it is shown).
Here is how the part of the script that loads the ui files should be structured:
import os
from PyQt4 import QtCore, QtGui, uic
# get the directory of this script
path = os.path.dirname(os.path.abspath(__file__))
MainWindowUI, MainWindowBase = uic.loadUiType(
os.path.join(path, 'mainwindow.ui'))
LandingPageUI, LandingPageBase = uic.loadUiType(
os.path.join(path, 'landing.ui'))
class MainWindow(MainWindowBase, MainWindowUI):
def __init__(self, parent=None):
MainWindowBase.__init__(self, parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.handleButton)
def handleButton(self):
# keep a reference to the landing page
self.landing = LandingPage()
self.landing.show()
class LandingPage(LandingPageBase, LandingPageUI):
def __init__(self, parent=None):
LandingPageBase.__init__(self, parent)
self.setupUi(self)

Related

Why does the QMainWindow not show? [duplicate]

I am loading a QMainWindow from an .ui file - it's working fine but window events like resize won't be triggered. I can't really figure out what I am doing wrong.
This is the code:
class TestWindow(QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QUiLoader()
file = QFile(abspath("ui/mainwindow.ui"))
file.open(QFile.ReadOnly)
self.window = loader.load(file, parent)
file.close()
self.window.show()
def resizeEvent(self, event):
print "resize"
app = QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
The .ui file can be found here.
It seems that you have a confusion, but for you to understand call the test method of TestWindow:
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
file.open(QtCore.QFile.ReadOnly)
self.window = loader.load(file, parent)
file.close()
self.window.show()
self.show()
def resizeEvent(self, event):
print("resize")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
And if you move the small window observe that the event is triggered.
Why does that happen?: QUiLoader creates a widget based on the .ui that unlike uic.loadUi() or ui.loadUiType() of PyQt5 does not load in the main widget but creates a new widget, maybe that's a disadvantage but that's the limitations.
So depending on what you want to do there are several options:
To load the .ui with QUiLoader() it is not necessary to have TestWindow as a parent since it can be a QObject that monitors the events through an event filter.
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class Manager(QtCore.QObject):
def __init__(self, parent_widget=None, parent=None):
super(Manager, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
file.open(QtCore.QFile.ReadOnly)
self.window = loader.load(file, parent_widget)
file.close()
self.window.installEventFilter(self)
self.window.show()
self.setParent(self.window)
self.window.destroyed.connect(lambda *args: print(">>>>>>"))
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.Close and self.window is obj:
self.window.removeEventFilter(self)
elif event.type() == QtCore.QEvent.Resize and self.window is obj:
print("resize")
return super(Manager, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = Manager()
sys.exit(app.exec_())
Another option is to make the self.widow the centralwidget (the QMainWindow in the .ui will be the centralwidget of the TestWindow, so the resize will be from the TestWindow not from the .ui but as if the size of the .ui is changed, the same will happen with TestWindow):
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
if file.open(QtCore.QFile.ReadOnly):
self.window = loader.load(file, parent)
file.close()
self.setCentralWidget(self.window)
self.show()
def resizeEvent(self, event):
print("resize")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
The previous methods only serve to notify you of the event but if you want to overwrite it is better that you use pyuic converting the .ui to .py

PyQt: Connecting a button in a dialog

I'm writing my first PyQt program, but I have a problem with a pushbutton. I read some other Q&A's but I wasn't able to solve it.
Basically I have a main window with a menu bar. By clicking on the menu item "actionSelect", a new dialog called SelectFiles is opened. It contains a pushbutton called "ChooseDirButton" that should open the select directory widget and change the "ShowPath" linedit text with the selected directory.
My code looks like this:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import TeraGui
class MainWindow(QMainWindow, TeraGui.Ui_MainWindow):
path = ""
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.actionSelect.triggered.connect(self.Select)
def Select(self):
dialog = QDialog()
dialog.ui = TeraGui.Ui_SelectFiles()
dialog.ui.setupUi(dialog)
dialog.setAttribute(Qt.WA_DeleteOnClose)
dialog.exec_()
def ChooseDirectory():
global path
path = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
self.ShowPath.setText(path)
app = QApplication(sys.argv)
form = MainWindow()
form.show()
app.exec_()
I'm not able to let the ChooseDirectory method be executed when the pushbutton "ChooseDirButton" is clicked. I tried to connect them, but I do not understand the right syntax. Moreover there could be something wrong in the ChooseDirectory method also.
I created the GUI with Qt Designer and import it with the "import TeraGui" command.
It looks like you need to create a subclass for your dialog, just as you did for the main window.
I can't actually test it without your ui modules, but something like this should work:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import TeraGui
class MainWindow(QMainWindow, TeraGui.Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.actionSelect.triggered.connect(self.Select)
def Select(self):
dialog = Dialog(self)
dialog.exec_()
self.ShowPath.setText(dialog.path)
class Dialog(QDialog, TeraGui.Ui_SelectFiles):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setupUi(self)
self.ChooseDirButton.clicked.connect(self.ChooseDirectory)
self.path = ''
def ChooseDirectory(self):
self.path = str(QFileDialog.getExistingDirectory(
self, "Select Directory"))
app = QApplication(sys.argv)
form = MainWindow()
form.show()
app.exec_()

How do I switch layouts in a window using PyQt?? (Without closing/opening windows)

I am currently attempting to create a program using python and PyQt4 (not Qt Designer).
I created a login class (QDialog) and a Homepage class (QMainWindow). However, because my program will consist of loads of pages (the navigation through the program will be large) i wanted to know how to switch layouts in QMainWindow rather than constantly creating new windows and closing old ones. For example, i would have the MainWindow ('HomePage') layout set as the default screen once logged in and would then have a subclass within MainWindow which allows me to navigate to user settings (or any other page). Instead of creating a new window and closing MainWindow, is there a way for me to swap the MainWindow layout to the User Setting layout?? (apologies if this doesnt make sense, im new to PyQt).
An example code is shown below (V.Basic code)
----------------------------------------------------------------------------------
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MainWindow(QMainWindow):
#Constructor
def __init__(self):
super(MainWindow, self).__init__() #call super class constructor
button1 = QPushButton("User Settings", self)
button1.clicked.connect(UserSelection)
button1.resize(50,50)
button1.move(350,50)
self.show()
class UserSelection(?):
...
def main():
app = QApplication(sys.argv) #Create new application
Main = MainWindow()
sys.exit(app.exec_()) #Monitor application for events
if __name__ == "__main__":
main()
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.central_widget = QtGui.QStackedWidget()
self.setCentralWidget(self.central_widget)
login_widget = LoginWidget(self)
login_widget.button.clicked.connect(self.login)
self.central_widget.addWidget(login_widget)
def login(self):
logged_in_widget = LoggedWidget(self)
self.central_widget.addWidget(logged_in_widget)
self.central_widget.setCurrentWidget(logged_in_widget)
class LoginWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(LoginWidget, self).__init__(parent)
layout = QtGui.QHBoxLayout()
self.button = QtGui.QPushButton('Login')
layout.addWidget(self.button)
self.setLayout(layout)
# you might want to do self.button.click.connect(self.parent().login) here
class LoggedWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(LoggedWidget, self).__init__(parent)
layout = QtGui.QHBoxLayout()
self.label = QtGui.QLabel('logged in!')
layout.addWidget(self.label)
self.setLayout(layout)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MainWindow()
window.show()
app.exec_()

Load other windows when button clicked. PyQt

I am trying to call another window from a button click in python 2.7 using PyQt4. The code below opens the AddBooking dialog but immediately closes it. Im new to Gui programming, can somebody please tell me what is wrong with my code?
from PyQt4 import QtGui
from HomeScreen import Ui_HomeScreen
from AddBooking import Ui_AddBooking
import sys
class HomeScreen(QtGui.QWidget, Ui_HomeScreen):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.show()
self.Add_Booking_Button.clicked.connect(self.handleButton)
def handleButton(self):
AddBooking2()
class AddBooking2(QtGui.QWidget, Ui_AddBooking):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.show()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = HomeScreen()
window.show()
sys.exit(app.exec_())
Don't use multi-inheritance and neither call show function inside class initializer. The problem is that the object you are creating with AddBooking2() is a temporal and it's destroyed automatically when the function ends. So you need use some variable to reference that object something like:
addbooking = AddBooking2()
addbooking.show()
Also, since you are working with QtDesigner and pyuic4 tools you can make connections a little bit easier. Said that, your code can be modified:
from PyQt4 import QtGui
from PyQt4.QtCore import pyqtSlot
from HomeScreen import Ui_HomeScreen
from AddBooking import Ui_AddBooking
import sys
class HomeScreen(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_HomeScreen()
self.ui.setupUi(self)
#pyqtSlot("")
def on_Add_Booking_Button_clicked(self): # The connection is carried by the Ui_* classes generated by pyuic4
addbooking = AddBooking2()
addbooking.show()
class AddBooking2(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_AddBooking()
self.ui.setupUi(self)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = HomeScreen()
window.show()
sys.exit(app.exec_())
The dialog closes immediately because you are not keeping a reference to it, and so it will get garbage-collected as soon as it goes out of scope.
The simplest way to fix it would be to do something like this:
def handleButton(self):
self.dialog = AddBooking2()
self.dialog.show()
and you can also remove the self.show() lines from AddBooking2.__init__ and HomeScreen.__init__, which are redundant. Other than that, your code looks fine.

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)

Categories