Can't open multiple windows in PyQt5 - python

so I've made several GUIs using the PyQt designer and I aim for each of them to link with eachother and for them to be able to open eachother. I have gotten the start up page to open up the home page, however when I click the respective buttons on the home page to open the other pages, it crashes my program. Any help would in fixing this would be greatly appreciated.
My code is below:
import sys
from PyQt5 import QtGui, QtCore, QtWidgets
from StartupPage import Ui_StartupWindow
from HomePage import Ui_HomeWindow
from FoodPage import Ui_FoodWindow
from ExercisePage import Ui_ExerciseWindow
from ProfilePage import Ui_ProfileWindow
class Startup(QtWidgets.QMainWindow, Ui_StartupWindow):
def __init__(self, parent=None):
super(Startup, self).__init__(parent)
self.setupUi(self)
self.NewEntryButton.clicked.connect(self.NewButtonHandle)
self.ContinueButton.clicked.connect(self.ContinueButtonHandle)
self.HomeP=Home()
def NewButtonHandle(self):
self.HomeP.show()
def ContinueButtonHandle(self):
self.HomeP.show()
class Home(QtWidgets.QMainWindow, Ui_HomeWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.FoodP=Food()
self.ExerciseP=Exercise()
self.ProfileP=Profile()
self.exerciseButton.clicked.connect(self.ExerciseButtonHandle)
self.foodButton.clicked.connect(self.FoodButtonHandle)
self.profileButton.clicked.connect(self.ProfileButtonHandle)
def ExerciseButtonHandle():
self.ExerciseP.show()
def FoodButtonHandle():
self.FoodP.show()
def ProfileButtonHandle():
self.ProfileP.show()
class Food(QtWidgets.QMainWindow, Ui_FoodWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
class Exercise(QtWidgets.QMainWindow, Ui_ExerciseWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
class Profile(QtWidgets.QMainWindow, Ui_ProfileWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Startup()
window.show()
sys.exit(app.exec_())

try to move import sys to:
if __name__ == '__main__':
import sys """<--------------------------here"""
app = QtWidgets.QApplication(sys.argv)
window = Startup()
window.show()
sys.exit(app.exec_())
try to check that other you import modules such as this.

It could be useful to know what error message is displayed when the program crashes.
Having said that, I was fiddling with something similar recently and the below seems to work fine. Note it is mostly the same as what you were doing.
Also, I had wanted to prevent interaction with the main (home) window when any of it's child windows (window1, window2, window3) were open, to force the user to focus on one task at a time rather than opening multiple windows - hence the setEnabled() calls. The
self.Window1.setEnabled(True)
line is required in home.toWindow1() because the Window1 is a member of home, and as such gets disabled along with all other members of home as a result of the first setEnabled call.
Also, while I did put my
import sys
in the main method as suggested by Volodymyr, that's just for the sake of neatness. As references to sys will resolve just as well (scoping rules, LEGB) if the import is the first line of code or the first line in the main method, I don't see how having it in either location could cause any issues (unless it was imported at the start of the file and then later the variable sys was assigned a different value).
I also don't see that altering the import, as suggested by Bahnzo, from
from HomePage import Ui_HomeWindow
to
import HomePage
and then later referring to Ui_HomeWindow as HomePage.Ui_HomeWindow would make any difference, for the same reason - the only case it would is if Ui_homePage had some value explicitly assigned to it after the import occurred and before it was used in the class definition - and you can see that doesn't happen in the OP's code.
#!/bin/python3
from PyQt5.QtWidgets import QApplication, QMainWindow
from startwindow import Ui_startWindow
from homewindow import Ui_homeWindow
from window1 import Ui_Window1
from window2 import Ui_Window2
from window3 import Ui_Window3
class start(QMainWindow, Ui_startWindow):
def __init__(self):
super(start, self).__init__(None)
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
self.home = home()
def toHome(self):
self.home.show()
self.hide()
class home(QMainWindow, Ui_homeWindow):
def __init__(self):
super(home, self).__init__(None)
self.setupUi(self)
self.window1Button.clicked.connect(self.toWindow1)
self.window2Button.clicked.connect(self.toWindow2)
self.window3Button.clicked.connect(self.toWindow3)
self.Window1 = window1(self)
self.Window2 = window2(self)
self.Window3 = window3(self)
def toWindow1(self):
self.Window1.show()
self.setEnabled(False)
self.Window1.setEnabled(True)
def toWindow2(self):
self.Window2.show()
self.setEnabled(False)
self.Window2.setEnabled(True)
def toWindow3(self):
self.Window3.show()
self.setEnabled(False)
self.Window3.setEnabled(True)
def reEnable(self):
self.setEnabled(True)
class window1(QMainWindow, Ui_Window1):
def __init__(self, home):
super(window1, self).__init__(home)
self.home = home
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
def toHome(self):
self.home.setEnabled(True)
self.hide()
class window2(QMainWindow, Ui_Window2):
def __init__(self, home):
super(window2, self).__init__(home)
self.home = home
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
def toHome(self):
self.home.setEnabled(True)
self.hide()
class window3(QMainWindow, Ui_Window3):
def __init__(self, home):
super(window3, self).__init__(home)
self.home = home
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
def toHome(self):
self.home.setEnabled(True)
self.hide()

Try this:
import Homepage #import the whole thing
then:
class Home(QtWidgets.QMainWindow, Homepage.Ui_HomeWindow):
#import the UI there

Related

use QDesktopServices.openUrl() to open window created by QWebEnginePage::createWindow()

when a JavaScript program requests to open a document in a new window, QWebEnginePage::createWindow() would be called to create a new window, while I want to (1) open the new window using QDesktopServices.openUrl(url) instead, and (2) keep the view in my QWebEngineView unchanged. My solution cannot satisfy (2), so any simpler solutions ?
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWebEngineCore import *
import sys,os
class WebEnginePage(QWebEnginePage):
def __init__(self, parent, mdicts=[]):
super().__init__(parent)
self.backwardUrl=''
def acceptNavigationRequest(self, url, navigationType, isMainFrame): # Navigation requests can be delegated to the Qt application instead of having the HTML handler engine process them by overloading this function. This is necessary when an HTML document is used as part of the user interface, and not to display external data, for example, when displaying a list of results.# The QWebEngineUrlRequestInterceptor class offers further options for intercepting and manipulating requests.
# print('acceptNavigationRequest-----------------', navigationType, isMainFrame)
if self.backwardUrl and isMainFrame:
print('blocked------------',self.backwardUrl)
self.setUrl(self.backwardUrl)
QDesktopServices.openUrl(self.backwardUrl)
self.backwardUrl=''
return False
return True
def createWindow(self, windowType):
print('createWindow')
self.backwardUrl=self.url()
return self
class WebEngineView(QWebEngineView):
def __init__(self, parent=None):
super().__init__(parent)
# self.mousePressEvent=lambda event:print('mousePressEvent',event.pos())
# self.mouseMoveEvent=lambda event:print('mouseMoveEvent',event.pos())
self.webPage = WebEnginePage(self)#self.page() # QWebEnginePage()
self.setPage(self.webPage)
# self.setUrl(QUrl('https://dict.eudic.net/liju/en/good#TingLiju'))
self.webPage.setUrl(QUrl('https://dict.eudic.net/liju/en/good#TingLiju'))
if __name__ == "__main__":
app = QApplication(sys.argv)
webEngineView = WebEngineView()
webEngineView.show()
sys.exit(app.exec_())
A possible solution is to create a page that only serves to obtain the url, and when you get it, delete it and launch the url with QDesktopServices::openUrl():
class FakePage(QWebEnginePage):
def __init__(self, parent=None):
super().__init__(parent)
self.urlChanged.connect(self.handle_url_changed)
#pyqtSlot(QUrl)
def handle_url_changed(self, url):
QDesktopServices.openUrl(url)
self.deleteLater()
class WebEnginePage(QWebEnginePage):
def createWindow(self, windowType):
return FakePage(self)
class WebEngineView(QWebEngineView):
def __init__(self, parent=None):
super().__init__(parent)
self.webPage = WebEnginePage(self)
self.setPage(self.webPage)
self.webPage.setUrl(QUrl("https://dict.eudic.net/liju/en/good#TingLiju"))

Best way to handle multiple windows Qt4 python

I have got two main-windows which will run all the time and open other windows. Every window has to communicate with each other. All windows are created with qt designer and as I read in another question I should not modify these files, so I tried to make a new class (communicator) to handle all the jobs.
What is the best way to structure a project like this. So how can i communicate best between these windows now, e.g. if I press a button in 'self.mainWindows_images' I want to do something in 'self.mainWindows_classifier'
from classifier import Form as Form_classifier
from cnn_avg import Form as Form_cnn_avg
from images import Form as Form_images
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class Communicator():
def __init__(self, parent=None):
self.mainWindow_images = Form_images()
self.mainWindow_images.show()
self.mainWindow_classifier = Form_classifier()
self.mainWindow_classifier.show()
def main():
app = QApplication(sys.argv)
app.setStyle('cleanlooks')
comm = Communicator()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
One of the window files, generated by Qt Designer, looks like with the additional -w flag:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(1145, 654)
...
class Form(QtGui.QWidget, Ui_Form):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
I want to do something like this and add the setImage-method to the mainWindow_classifier, becaus as I mentioned I should not modify the generated qt python file:
self.mainWindow_classifier.pushButton.clicked.connect(self.setImage)
def setImage(self):
# change QLabel in self.mainWindow_images

PyQt4 signals and slots - QToolButton

In PyQt4 I have a main window which when the settings button is clicked opens the settings dialog
from PyQt4 import QtCore, QtGui
import ui_Design, ui_Settings_Design
class MainDialog(QtGui.QMainWindow, ui_Design.Ui_arbCrunchUI):
def __init__(self, parent=None):
super(MainDialog, self).__init__(parent)
self.setupUi(self)
self.settingsBtn.clicked.connect(lambda: self.showSettings())
def showSettings(self):
dialog = QtGui.QDialog()
dialog.ui = SettingsDialog()
dialog.ui.setupUi(dialog)
dialog.exec_()
The above works and my SettingsDialog is displayed but I cant get the setPageIndex to work
class SettingsDialog(QtGui.QDialog, ui_Settings_Design.Ui_SettingsDialog):
def __init__(self, parent=None):
super(SettingsDialog, self).__init__(parent)
self.setupUi(self)
self.bookSettingsBtn.clicked.connect(self.setPageIndex)
#QtCore.pyqtSlot()
def setPageIndex(self):
print 'selected'
self.settingsStackedWidget.setCurrentIndex(0)
The bookSettingsBtn is a QToolButton
self.bookSettingsBtn = QtGui.QToolButton(self.navigationFrame)
And the settingsStackedWidget is a QStackedWidget
self.settingsStackedWidget = QtGui.QStackedWidget(SettingsDialog)
At this point I am pretty confused on signals and slots and nothing I have read clears this up - if anyone can point out what I am doing wrong above and also potentially direct me to a good (beginners) guide / tutorial on signals and slots it would be greatly appreciated
I would also like to know how to make setPageIndex work as follows:
def setPageIndex(self, selection):
self.settingsStackedWidget.setCurrentIndex(selection)
I'm not sure why you're doing the following, but that's the issue:
def showSettings(self):
dialog = QtGui.QDialog()
dialog.ui = SettingsDialog()
dialog.ui.setupUi(dialog)
dialog.exec_()
SettingsDialog itself is a proper QDialog. You don't need to instantiate another QDialog.
Right now, you're creating an empty QDialog and then populate it with the same ui as SettingsDialog (i.e. setupUi(dialog)), then you show this dialog. But... The signal connection is for SettingsDialog, and the dialog you're showing doesn't have that.
Basically, you don't need that extra QDialog at all. The following should be enough:
def showSettings(self):
dialog = SettingsDialog()
dialog.exec_()
Ok. So here is an example how you pass an argument to a slot
from functools import partial
# here you have a button bookSettingsBtn:
self.bookSettingsBtn = QtGui.QPushButton("settings")
self.bookSettingsBtn.clicked.connect(partial(self.setPageIndex, self.bookSettingsBtn.text()))
#pyqtSlot(str) # this means the function expects 1 string parameter (str, str) 2 string parameters etc.
def setPageIndex(self, selection):
print "you pressed button " + selection
In your case the argument would be an int. Of course you have to get the value from somewhere
and then put it in the partial part as the argument (here I just used the text of the button),
but you can use int, bool etc. Just watch the slot signature.
Here is a tutorial that helped me:
http://zetcode.com/gui/pyqt4/
I hope this helps.
Hey here I have a fully running example (just copy paste it in a python file and run it):
Maybe this helps you. It's a small example but here you see how it works.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from functools import partial
class MyForm(QMainWindow):
def __init__(self, parent=None):
super(MyForm, self).__init__(parent)
button1 = QPushButton('Button 1')
button2 = QPushButton('Button 2')
button1.clicked.connect(partial(self.on_button, button1.text()))
button2.clicked.connect(partial(self.on_button, button1.text()))
layout = QHBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
main_frame = QWidget()
main_frame.setLayout(layout)
self.setCentralWidget(main_frame)
#pyqtSlot(str)
def on_button(self, n):
print "Text of button is: " + str(n)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
form = MyForm()
form.show()
app.exec_()
So I dont really understand why but changing the way the settingsDialog is called from the MainWindow has fixed my problem. I guess the parent window needed to be specified??:
class MainDialog(QtGui.QMainWindow, ui_Design.Ui_arbCrunchUI):
....
def showSettings(self):
self.settingsDialog = QtGui.QDialog(self)
self.settingsDialog.ui = SettingsDialog(self)
self.settingsDialog.ui.show()
class SettingsDialog(QtGui.QDialog, ui_Settings_Design.Ui_SettingsDialog):
def __init__(self, parent=None):
super(SettingsDialog, self).__init__(parent)
self.setupUi(self)
self.bookSettingsBtn.clicked.connect(partial(self.setPageIndex, 1))
#QtCore.pyqtSlot(int)
def setPageIndex(self, selection):
self.settingsStackedWidget.setCurrentIndex(selection)

Working with PyQt and Qt designer ui files

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)

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.

Categories