Is it possible to have 2 PyQT UI in 1 .py file?
Example code:
Class a(object):
*insert code for PyQT First UI
Class b(QMainWindow):
*insert code for PyQT Second UI
Class a runs first, but how do i switch from Class a to Class b and vice versa?
One file can contain as many ui classes as you want. Just by declaring the class does not run the ui. You can display the ui in several different ways.
To display a second QWidget from your class a, you can call it from a method like this:
def show_b(self):
self.dialog = b()
self.dialog.show()
This works if class b is a QWidget. If it is a QDialog, it can be displayed as follows:
def show_b(self):
dialog = b()
dialog.show() # this line makes the dialog non-modal, it is optional
dialog.exec_() # displays the dialog
If you want to have two windows and be able to switch to either one of them, you just have to declare them in your main file:
def main_Window_A(QMainWindow):
# code for window A
def main_window_B(QMainWindow):
# code for window B
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window_A = main_Window_A()
window_A.show()
window_B = main_Window_B()
window_B.show()
sys.exit(app.exec())
Related
First File first.py
import pyqt5py
ret=pyqt5py.confirm()
print(ret)
Second File Having PYQT5 name: pyqt5py.py
import sys
from PyQt5 import QtWidgets, uic
class Ui(QtWidgets.QDialog):
def __init__(self,button1='Ok',button2='Cancel',text='Are You Sure?'):
super(Ui, self).__init__() # Call the inherited classes __init__ method
uic.loadUi('dialog.ui', self) # Load the .ui file
# Show the GUI
self.pushButton1.clicked.connect(lambda: self.click(1))
self.pushButton2.clicked.connect(lambda: self.click(2))
self.label.setText(text)
self.pushButton1.setText(button1)
self.pushButton2.setText(button2)
self.show()
def click(self,args):
print(self)
return self.sender().text()
app = QtWidgets.QApplication(sys.argv) # Create an instance of QtWidgets.QApplication
def confirm():
def pressed():
return 'clicked'
window = Ui(button1='Ok',button2='Cancel',text='Are You Sure?') # Create an instance of our class
print(window)
window.pushButton1.clicked.connect(pressed)
app.exec_() # Start the application
but i dont know what changes should i do make my first.py to work,i have correctly made the pyqt5 file but i dont know how to add def to call it for confirm
#######################
I Updated My Second File
As suggested by bfris you should rewrite the last lines of pyqt5py.py as follows:
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Ui(button1='Ok',button2='Cancel',text='Are You Sure?')
app.exec_()
That way you can run this file directly for debbugging purposes, but also import it elsewhere.
To use your widget in first.py you need to create an instance of it there.
first.py:
from pyqt5py.py import UI
app = QtWidgets.QApplication(sys.argv)
window = Ui(button1='Ok',button2='Cancel',text='Are You Sure?')
app.exec_()
Usually I use a QDialog within a Qt environment where it is opened from a QMainWindow and also returning which button was clicked to the QMainWindow.
However as I understand you would like to run another program and in between open your UI? I am not experienced doing that but it seems to me that its exec method does exactly that though you should read this discussion about a bug related to it.
Alternatively in first.py you connect the pushbutton's clicked signal to a slot, a function there.
I am coding a little application in PyQt5 and came across a problem illustrated at hand of the following minimal working example:
My custom class 'A' inherits from the QWidget class, calls two setup methods (one for widgets and one for layouts) and adds the widgets from the setup_widgets method ('Click A' Button) to the Layout called 'frame'. This works fine and creating a QApplication as well as a QMainWindow and adding such a class A widget to it will display it properly.
However in the next step I design a class 'B' which is supposed to inherit from class 'A'. Hence I call the init method of 'A' within the init method of 'B'. To my understanding this will go through A.init() including the A.setup_widgets() as well as A.setup_layout(), which adds the 'Click A' Button as well as a Layout called 'frame' to the object.
After a little of debugging though I noticed that the call of setup_layout that comes from the A.init() does actually call the B.setup_layout since the 'self' argument of the inheritance call seems to be an object of type 'B'. Therefore an Error is raised since for the B object no Layout called 'frame' was ever created.
A workaround would be to add A.setup_widgets(self) as a first line to the B.setup_widgets method, equivalently adding A.setup_layout(self) to B.setup_layout method. This approach is also shown in the source code, but commented with a #. However this results in an attempt to set a QLayout twice and thus in a Warning/Error:
QWidget::setLayout: Attempting to set QLayout "" on B "", which already has a layout.
What is the proper way to deal with this issue of inheritance?
If it helps: I never plan to use class A as an actual object, still would like it to be a solo standing functioning class since I will derive many different subclasses from it.
Thanks and cheers,
Paul
from PyQt5.QtWidgets import *
class A(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setup_widgets()
self.setup_layout()
def setup_widgets(self):
self.button_a = QPushButton('Click A')
def setup_layout(self):
self.frame = QHBoxLayout()
self.frame.addWidget(self.button_a)
self.setLayout(self.frame)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
win = QMainWindow()
wid = A()
win.setCentralWidget(wid)
win.show()
sys.exit(app.exec())
-------------------------------------------------------------------------
from PyQt5.QtWidgets import *
from class_a import A
class B(A):
def __init__(self):
A.__init__(self)
self.setup_widgets()
self.setup_layout()
def setup_widgets(self):
#A.setup_widgets(self)
self.button_b = QPushButton('Click B')
def setup_layout(self):
#A.setup_layout(self)
self.frame.addWidget(self.button_b)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
win = QMainWindow()
wid = B()
win.setCentralWidget(wid)
win.show()
sys.exit(app.exec())
You don't need call setup_widgets and setup_layout from your B. __init__ since they are already called by A.
I'm trying to set up an app in Linux using PyQt4 designer and I'm struggling to connect signals and slots to it. Right now all I want it to do is connect a button clicked signal to a custom slot, saveEnergyScheme which simply prints 'energy list' to the terminal.
I've translated the .ui code for my app to a python class with pyuic4 -w sumcorr.ui > sumcorr_ui.py. This created a class in the sumcorr_ui.py module called SumCorr_ui:
class SumCorr_ui(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QMainWindow.__init__(self, parent, f)
self.setupUi(self)
I then made my app as a custom widget and tried to add a simple signal-slot connection to a button to show it works:
from PyQt4 import QtGui, QtCore
from sumcorr_ui import SumCorr_ui
class SumCorr(SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = QtGui.QMainWindow()
ui = SumCorr()
ui.setupUi(mySumCorr)
mySumCorr.show()
sys.exit(app.exec_())
I expect to get the line 'energy list' when I click the button named save_energies_button, but nothing happens. Could this be because I haven't built the UI as a widget, but as a main window? Why doesn't it print out??
Try to add ui.show() and you'll see that your code is creating two different windows, one should have the signal connected and one doesn't. That's because you are showing only the mySumCorr window, but you call only setupUi on it, which does not connect the signal.
When you create the SumCorr instance, you are creating a window and setting it up, then, by no reason, you do ui.setupUi(mySumCorr), which setups the mySumCorr instance without connecting the signal, and you show this last window.
I believe your code should be like this:
class SumCorr(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.setupUi(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = SumCorr()
mySumCorr.show()
sys.exit(app.exec_())
Note that it doesn't make any sense to have a SumCorr_ui class, that's because Qt is a UI library so you are just introducing a worthless level of abstraction. The designer file already gives you an abstraction over the ui layout.
I have a main dialog and on that dialog there is a button. When the button is clicked, I want to open an another dialog.
Main Dialog code (Function which is called when the button is clicked in the main dialog):
def add_host(self):
x=add_host.Ui_Dialog1()
x.main()
default function:
if __name__ == "__main__":
import sys
global app
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
Secondary dialog (add_host.py) code snapshot:
def main(self):
app1 = QtGui.QApplication(sys.argv)
Dialog1 = QtGui.QDialog()
ui1 = Ui_Dialog1()
ui1.setupUi1(Dialog1)
Dialog1.show()
sys.exit(app.exec_())
So when I run the code, it opens the secondary dialog but when I close it, it just freezes, and I get this error message:
File "testbot.py", line 175, in add_host
x.main()
File "/home/ppp/ppp/add_host.py", line 74, in main
sys.exit(app.exec_())
NameError: global name 'app' is not defined
Which does make sense, but I have no idea how to resolve it. I try several combinations without success, including adding and deleting app.exec_().
You cannot create multiple QApplications inside of the same script and thread. You are only supposed to have one...
This should be more like:
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
No global app. Although you should be doing your setupUI from within the class of your dialog.
Then when you want to show another dialog from with your app...say main(), you just create it and call show()
Here is a really basic example:
class Dialog(QDialog)
def __init__(self, parent):
super(Dialog, self).__init__(parent)
self.otherDialog = QDialog(parent=self)
self.otherDialog.show()
if __name__ == "__main__":
app = QApplication([])
dialog = Dialog()
dialog.show()
app.exec_()
You create a single QApplication and start its event loop by calling exec_(). From that point on, your main application is free to create more QWidgets. You never create another QApplication again at this point.
Also, I dont understand this part of your code:
def add_host(self):
x=add_host.Ui_Dialog1()
x.main()
The fact that you are calling a main() method on your UI object makes me think you are modifying the UI file and adding functionality to it, which you should not be doing. That ui file is subject to be overwritten every time you make changes in QT Designer and save out a new one. You should only be importing it and using its setupUI() method to apply it to your own custom classes.
A note about organization of your modules
When you are designing a PyQT application, you will always have a single entry point that will be called to start your app. This is the single and only location that should be creating your QApp and starting the event loop, and is usually done with in a if __name__ == "__main__" block to ensure its only done when its the main script. It should not be done within methods of your objects. For all your other modules where you define other Dialog, Widgets, etc, these should simply be classes that you import. As long as you have a running QApp, you are free to create and show these widgets.
Your code sample is a bit confusing - I don't understand why you have two mains, etc - anyway, maybe it's just a typo in add_host.py (app1.exec_() instead of app.exec_())
def main(self):
app1 = QtGui.QApplication(sys.argv)
...
sys.exit(app1.exec_())
I need to know how to be able to make a dialog pop-up when a user clicks a button.
I'm relatively new to both Python and PyQt/QtDesigner. I've only been using in them for about a month, but I think I have a good grasp.
Here's what I have: A main dialog (which is the main part of the application), which I designed in QtDesigner. I converted the .ui to .py using pyuic4easy.
Here's what I want to do: design a new dialog box in the QtDesigner and somehow make it pop up when a user clicks a button on the first (main) dialog.
Here's the code for my main dialog:
import sys
from PyQt4.QtCore import *
from loginScreen import *
class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.pushButton, QtCore.SIGNAL('clicked()'), self.popup)
...
... Some functions ...
def popup(self):
#Pop-up the new dialog
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp= MyForm()
myapp.show()
sys.exit(app.exec_())
So as you can see, I've connected the first button to a method named 'popup', which needs to be filled in with code to make my second window pop up. How do I go about doing this? Remember that I already have designed my second dialog in QtDesigner, and I don't need to create a new one.
Thanks for all the help!
So as you can see, I've connected the first button to a method named
'popup', which needs to be filled in with code to make my second
window pop up. How do I go about doing this?
Pretty much the same way you do it for your main window (MyForm).
As usual, you write a wrapper class for your QtDesigner code for the second dialog (like you did with MyForm). Let's call it MyPopupDialog. Then in your popup method, you create an instance and then show your instance with either exec_() or show() depending whether you want a modal or modeless dialog. (If you are not familiar with Modal/Modeless concept, you might refer to the documentation.)
So the overall thing might look like this (with a couple of modifications):
# Necessary imports
class MyPopupDialog(QtGui.QDialog):
def __init__(self, parent=None):
# Regular init stuff...
# and other things you might want
class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
# Here, you should call the inherited class' init, which is QDialog
QtGui.QDialog.__init__(self, parent)
# Usual setup stuff
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# Use new style signal/slots
self.ui.pushButton.clicked.connect(self.popup)
# Other things...
def popup(self):
self.dialog = MyPopupDialog()
# For Modal dialogs
self.dialog.exec_()
# Or for modeless dialogs
# self.dialog.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp= MyForm()
myapp.show()
sys.exit(app.exec_())