Load other windows when button clicked. PyQt - python

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.

Related

Can't open multiple windows in PyQt5

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

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)

Python PyQt4 open from QDialog new QWidget window

By pressing a QPushButton in my QDialog window I want to open a new QWidget window.
My code:
from PyQt4 import QtGui
import sys
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle("Main Window")
class FirstWindow(QtGui.QDialog):
def __init__(self, parent=None):
super(FirstWindow, self).__init__(parent)
self.createWindow()
def createWindow(self):
btn = QtGui.QPushButton('Open New Window', self)
btn.move(10, 10)
self.openNewWindow = MainWindow(self)
btn.clicked.connect(self.openMainWin)
self.setGeometry(250,250, 150,50)
self.setWindowTitle("First Window")
self.show()
def openMainWin(self):
self.openNewWindow.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
firstwin = FirstWindow()
sys.exit(app.exec_())
When I run the code nothing happens by pressing the button.
But when I change the class from
class MainWindow(QtGui.QWidget) to
class MainWindow(QtGui.QDialog) or class MainWindow(QtGui.QMainWindow)
it works!
What am I doing wrong?! Please assist me.
When you instantiate MainWindow you pass in a parent. Qwidget only makes a new window if you don't specify a parent.
This is of course deliberate. If QWidgets with parents were shown in new windows, then you could never build a GUI. Imagine having every widget in it's own window!
QMainWindow and QDialog are specifically designed to both have a parent, and create a new window. You should use them.

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_()

Open a GUI file from another file PyQT

I've created many GUI interfaces in PyQT using QT Designer, but now I'm trying to open an interface from another one, and I don't know how to do it..
Start.py is the file which run the GUI Interface Authentification_1 and Acceuil_start.py is the file which run the GUI interface Acceuil_2.py, now I want from Start.py to lunch Acceuil_start.py.
Do you have any idea about that ? Thank you.
Here's my code :
Start.py :
import sys
from PyQt4 import QtCore, QtGui
from Authentification_1 import Ui_Fenetre_auth
from Acceuil_2 import Ui_MainWindow #??? Acceuil_2.py is the file which I want to open
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Fenetre_auth()
self.ui.setupUi(self)
def authentifier(val): #Slot method
self.Acceuil = Acceuil() #???
self.Acceuil.show() #???
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
sys.exit(app.exec_())
Acceuil_start.py
import sys
from PyQt4 import QtCore, QtGui
from Authentification_1 import Ui_Fenetre_auth
from Acceuil_2 import Ui_MainWindow
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
sys.exit(app.exec_())
First, you should to name your GUI classes so they have a different name, and not the generic one, so you could distinct them.
Why you would need to do that? Well - simply, because it makes sense - if every class is representing different type of dialog, so it is the different type - and it should be named differently. Some of the names are/may be: QMessageBox, AboutBox, AddUserDialog, and so on.
In Acceuil_start.py (you should rename class in other module, too).
import sys
from PyQt4 import QtCore, QtGui
from Authentification_1 import Ui_Fenetre_auth
from Acceuil_2 import Ui_MainWindow
class Acceuil(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = Acceuil()
myapp.show()
sys.exit(app.exec_())
in the parent class, when you want to create the window, you are close (but it should work in any case):
def authentifier(val): #Slot method
self.Acceuil = Acceuil(self) # You should always pass the parent to the child control
self.Acceuil.show() #???
About parent issue: If your widget/window is creating another widget, setting creator object to be parent is always a good idea (apart from some singular cases), and you should read this to see why is that so:
QObjects organize themselves in object trees. When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is. It turns out that this approach fits the needs of GUI objects very well. For example, a QShortcut (keyboard shortcut) is a child of the relevant window, so when the user closes that window, the shorcut is deleted too.
Edit - Minimal Working Sample
To see what I am trying to tell you, I've built a simple example. You have two classes - MainWindow and
ChildWindow. Every class can work without other class by creating separate QApplication objects. But, if you import ChildWindow in MainWindow, you will create ChildWindow in slot connected to singleshot timer which will trigger in 5 seconds.
MainWindow.py:
import sys
from PyQt4 import QtCore, QtGui
from ChildWindow import ChildWindow
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
QtCore.QTimer.singleShot(5000, self.showChildWindow)
def showChildWindow(self):
self.child_win = ChildWindow(self)
self.child_win.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MainWindow()
myapp.show()
sys.exit(app.exec_())
ChildWindow.py:
import sys
from PyQt4 import QtCore, QtGui
class ChildWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle("Child Window!")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = ChildWindow()
myapp.show()
sys.exit(app.exec_())
To reference the other dialog from Start.py, you must prefix it by the module name, which in this case is Acceuil_start. As such, it is OK if there are duplicated function names in each module. So, you would have:
def authentifier(val): #Slot method
dlg = Acceuil_start.StartQT4()
dlg.exec_()
However, if you want these to run from the same process, keep in mind that you can't have two app objects. You would probably want to structure Acceuil_start.py to act like a dialog, rather than a main window. If these are two distinct main windows, you might find it easier to just invoke another Python interpreter with the Acceuil_start.py as a parameter.

Categories