I'm building a plugin for QGIS using PyQGIS and PyQt5. I want to work with multiple windows. After clicking a button, a new window should open. Ideally, it should overlap window 1. After editing in window 2, it should go back to window 1.
My previous code is like this:
class MainWindow(QDialog):
def __init__(self):
super(MainWindow, self).__init__()
loadUi(r"test1.ui", self)
self.button.clicked.connect(self.gotoScreen2)
def gotoScreen2(self):
screen2=Screen2()
widget.addWidget(screen2)
widget.setCurrentIndex(widget.currentIndex()+1)
class Screen2(QDialog):
def __init__(self):
super(Screen2,self).__init__()
loadUi(r"test2.ui", self)
self.pushButton.clicked.connect(self.gotoScreen1)
def gotoScreen1(self):
mainwindow = MainWindow()
widget.addWidget(mainwindow)
widget.setCurrentIndex(widget.currentIndex()+1)
#main
app = QApplication(sys.argv)
widget = QtWidgets.QStackedWidget()
mainwindow = MainWindow()
widget.addWidget(mainwindow)
widget.show()
Building on this, I would like the plugin window to dock on the right in the program. I know that it is possible with the QDockWidget class and addDockWidget (QtCore.Qt.RightDockWidgetArea,...).
But how do I get these class built into my script?
This is my solution (there are now three UIs (windows) that communicate directly with each other.) It works wonderfully in QGIS.
class MainWindow(QDialog):
def __init__(self):
super(MainWindow, self).__init__()
self.gui = loadUi(r"test1.ui", self)
self.button.clicked.connect(self.gotoScreen2)
self.btn_adding.clicked.connect(self.adding)
def gotoScreen2(self):
screen2=Screen2()
widget.setWidget(screen2)
class Screen2(QDialog):
def __init__(self):
super(Screen2,self).__init__()
loadUi(r"test2.ui", self)
self.pushButton.clicked.connect(self.gotoScreen1)
self.pushButton_2.clicked.connect(self.gotoScreen3)
def gotoScreen1(self):
mainwindow = MainWindow()
widget.setWidget(mainwindow)
def gotoScreen3(self):
screen3=Screen3()
widget.setWidget(screen3)
class Screen3(QDialog):
def __init__(self):
super(Screen3,self).__init__()
loadUi(r"test3.ui", self)
self.pushButton.clicked.connect(self.gotoScreen2)
def gotoScreen2(self):
screen2=Screen2()
widget.setWidget(screen2)
widget = QtWidgets.QDockWidget("test")
mainwindow = MainWindow()
widget.setWidget(mainwindow)
#dock on the right side of the screen
iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, widget)
widget.show()
Related
I started out with PyQt5 recently. I wanted to create a custom widget and then insert it into the main window of an application.
The custom Widget:
class ScoreCard(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ScoreCard, self).__init__(parent=parent)
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint)
self.pressing = False
self.init_ui()
self.show()
def init_ui(self):
# Layout in here
And this is the main Application:
from PyQt5.QtWidgets import *
from scorecard import ScoreCard
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUi()
self.show()
def initUi(self):
self.setGeometry(300,300,800,700)
window_layout = QVBoxLayout()
recent_playcard = ScoreCard()
window_layout.addWidget(recent_playcard)
self.setLayout(window_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
execute = MainWindow()
sys.exit(app.exec_())
Why is it that whenever I run the main Application, the custom widget appears in another window? I even tried removing the frame and setting the parent to none, but none of that changed this behavior. How do I fix this?
Looks like I mixed up QMainWindow and QDialog I should be using a central widget for the main application instead of setting a layout..
I'm trying to show a new dialog window in my main window when i click on a pushbutton. I'm facing some issues here:
1: when i create a new dialog object inside my mainWindow class, i'll have to use lambda as a slot or else it wont work. the code below works as expected:
class main(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
new = QDialog()
self.ui.pushButton.clicked.connect(lambda: new.show())
self.show()
app = QApplication(sys.argv)
ex = main()
sys.exit(app.exec_())
while going like self.ui.pushButton.clicked.connect(new.show) does not work.
But if the object is created outside the main class it will run without Lambda:
class main(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
app = QApplication(sys.argv)
ex = main()
new = QDialog()
ex.ui.pushButton.clicked.connect(new.show)
sys.exit(app.exec_())
I really don't understand what is happening here. AFAIK using a slot without Lambda should work as long as no arguments are passed to it.
2:
If i wanted to connect the pushbutton to a slot (in which i create a dialog object and run the show() method on it), the dialog window would appear and then immediately disappear, in this case i'll need to do dialoginstance.exec_() instead of dialoginstance.show()
class main(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(lambda: self.showdiag())
self.show()
def showdiag(self):
new = QDialog()
new.exec_() # new.show() wont work!
app = QApplication(sys.argv)
ex = main()
sys.exit(app.exec_())
I have generated my UI with Qt Designer:
like this
I have used the .ui file with the following python code:
Ui_MainWindow, QtBaseClass = uic.loadUiType("vault.ui")
Ui_Credentials, QtBaseClass = uic.loadUiType("credentials.ui")
class Credentials(QMainWindow):
def __init__(self):
super(Credentials, self).__init__()
self.ui = Ui_Credentials()
self.ui.setupUi(self)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.load.clicked.connect(self.loadVault)
self.ui.next.clicked.connect(self.next)
self.controller = CLI(....)
self.loadVault()
def loadVault(self):
self.ui.vault.clear()
vaults = self.controller.listVaults()
for vault in vaults:
item = QListWidgetItem(vault)
self.ui.vault.addItem(item)
def next(self):
print(self.ui.vault.currentItem().text())
window = Credentials()
window.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
I have tried to change the window when the button next is pressed by created a new class and using a different ui file.
I found this stackoverflow post where this is a similar problem but the code is this post doesn't use a .ui and I did not manage to have a working code with .ui file. I have succeeded to have a new window when I don't use my ui file.
Someone know how can I deal with this ? Is it not adviced to use .ui file?
The solution that I propose is similar to my previous answer, the objective is to change the graphical part so we will use the function setupUI () that generates that part.
When we press the next button, you must change it back with that function.
Ui_MainWindow, _ = uic.loadUiType("vault.ui")
Ui_Credentials, _ = uic.loadUiType("credentials.ui")
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.startMainWindow()
def startMainWindow(self):
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.next.clicked.connect(self.startCredentials)
def startCredentials(self):
self.ui = Ui_Credentials()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
I am trying to write a python script to an application like matplotlib.
I need a function call to show the Qt main window. How do I do this?
class MainWindow(QtGui.QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.numbers = 4
...
app = QtGui.QApplication(sys.argv)
dmw = DesignerMainWindow()
dmw.show()
sys.exit(app.exec_()) #this works, but pops the window right away
I want to be able to call the window when I wish instead. (Something like this)
def newWin():
app = QtGui.QApplication(sys.argv)
dwm = MainWindow()
sys.exit(app.exec_())
return dwn
a = newWin() # application is created now
a.numbers = 10 # do something
a.show() # should pop me the window now
EDIT : Pasting solution thanks to jadkik94
class App(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self,args)
self.window = MainWindow()
def doSomething(self, ii):
self.window.numbers = ii
def show(self):
self.window.show()
sys.exit(self.exec_())
a = App(sys.argv)
a.doSomething(12) #updates numbers alternately a.window.numbers = 12
a.show() #pops the window!
When used inside a function, the window does not show. The problem is simple: the window is garbage collected because it is defined inside the scope of the function, and then not used anymore, so Python sees it as "garbage" and deletes the object.
The best way I found of avoiding that is having an application class that will hold references to all the windows you want to show. So you can either have a regular class do that for you, or subclass the QtGui.QApplication if you can make use of it otherwise too. I would go for the second option.
Another option, if you really don't want to be using a class, is to set it to a global variable, and that will usually prevent it from being garbage-collected by Python.
Is this what you want:
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Icon')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
a = main()
a.show()
I'm kinda new to PySide.I have a main window object which shows one widget at a time. I've been trying to change the central widget of the QMainWindow class in order to replace the visible Widget in the window when pressing a button. The problem is that the button pressed is in the Widget class, not in the main window class.
say...
class App(QtGui.QMainWindow):
def __init__(self):
super(App, self).__init__()
self.initUI()
def initUI(self):
self.statusBar().showMessage('Listo.') #Status Bar
self.login_screen = LoginScreen()
self.logged_in_screen = LoggedInScreen()
self.setCentralWidget(self.login_screen)
self.setGeometry(300, 300, 450, 600) #Window Size
self.setWindowTitle('PyTransactio - Client') #Window Title
self.setWindowIcon(QtGui.QIcon('icon.png')) #App Icon
self.show()
The pressed button is in the login_screen instance. The method called when the button is clicked is inside the LoginScreen class:
def login(self):
""" Send login data to the server in order to log in """
#Process
self.setParent(None)
Setting the parent widget to None removes the widget (login_screen) from the main window. What should I do in order to get another widget (e.g. logged_in_screen) as the central widget of the main window when the loginButton (inside the login_screen widget) is pressed?
Maybe the login method should be inside the main window class? If so, how can I connect the buttons pressed in login_screen with the main window's method?
You may use a QStackedWidget as central widget and add both the log-in screen and "logged-in" screen to it.
An example usage:
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_()
If you do not want to use this widget, then I think you'll have to call QMainWindow.setCentralWidget every time you change the central widget.
As to where the login method should be, it depends. Probably you could define a simple interface for your mainwindow to add/remove/show specific central widgets, and call it from the login method of LoginScreen. In this way the LoginScreen class does not have to know about implementation details such as if the central widget is actually a QStackedWidget or this thing is done in an other way.
You can use QMainWindow.setCentralWidget to do this (repeatedly):
#! /usr/bin/env python3
from PySide import QtGui
from PySide import QtCore
import sys
app = QtGui.QApplication(sys.argv)
mw = QtGui.QMainWindow()
w2 = QtGui.QWidget()
pb = QtGui.QPushButton('push me', w2)
l1 = QtGui.QLabel('orig')
l2 = QtGui.QLabel('changed')
mw.setCentralWidget(l1)
pb.clicked.connect(lambda: mw.setCentralWidget(l2))
mw.show()
w2.show()
sys.exit(app.exec_())