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..
Related
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()
Hi, I'm trying to make simple GUI application using PyQt5, Python 3.4 and Windows 7.
Below code works properly.
# coding: utf-8
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
class MainWnd(QMainWindow):
def __init__(self):
super().__init__()
self.popup_dlg = None
self.init_ui()
def init_ui(self):
self.setGeometry(100, 100, 300, 200)
self.show()
self.popup_dlg = ChildWnd()
class ChildWnd(QDialog):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.resize(200, 100)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWnd()
sys.exit(app.exec_())
Two windows are created. One is main window and the other is child window(popup window). But what I want is to make child window's default location is centered of main window.
So I've modified the code like this.
# coding: utf-8
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
class MainWnd(QMainWindow):
def __init__(self):
super().__init__()
self.popup_dlg = None
self.init_ui()
def init_ui(self):
self.setGeometry(100, 100, 300, 200)
self.show()
self.popup_dlg = ChildWnd(self) # make instance with parent window argument.
class ChildWnd(QDialog):
def __init__(self, parent_wnd):
super().__init__()
self.setParent(parent_wnd) # set child window's parent
self.init_ui()
def init_ui(self):
self.resize(200, 100)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWnd()
sys.exit(app.exec_())
But this code makes problem. Child window doesn't show up. Only main window(=parent window) shows. In Qt's QDialog's manual, I found this.
but if it has a parent, its default location is centered on top of the
parent's top-level widget (if it is not top-level itself).
This is why I added the setParent().
What should I do?
Please help me!!
As specified in the documentation calling setParent will just change the ownership of the QDialog widget. If you want the QDialog widget to be centered within it's parent, you need to pass the parent widget instance to the super constructor of your QDialog:
class ChildWnd(QDialog):
def __init__(self, parent_wnd):
super().__init__(parent_wnd)
self.init_ui()
def init_ui(self):
self.resize(200, 100)
self.show()
I have created two different pyqt windows, and within one of them, by pressing a button, it should bring up another smaller window. While my code does pretty much exactly what I just dais it should do, there is a problem with the way the smaller popup window is displayed.
This is my code for displaying the windows and the button functionality:
from PyQt4 import QtGui
from EnterprisePassport import Ui_StudentEnterprisePassport
from Session_tracker import Ui_Session_tracker
class StudentEnterprisePassport(Ui_StudentEnterprisePassport):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.sessionTracker_btn.clicked.connect(self.handleButton)
self.window2 = None
def handleButton(self):
if self.window2 is None:
self.window2 = Session_tracker(self)
self.window2.show()
class Session_tracker(Ui_Session_tracker):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = StudentEnterprisePassport()
window.show()
sys.exit(app.exec_())
I can still use the functions within the window, but I can't move it, or close it, and there is no title bar. Have I done something wrong within my code for the popup window to appear like this?
Edit:
Original Session tracker window: Original window
Popup session tracker window: Popup window
In order to show the other widget in it's own window, it has to be a QMainWindow or a QDialog.
One option, if you don't want to convert your existing Session_tracker to a QDialog, is to just wrap it in a QDialog
def handleButton(self):
if self.window2 is None:
self.window2 = QtGui.QDialog(self)
lay = QtGui.QVBoxLayout()
self.window2.setLayout(lay)
self.session_tracker = Session_tracker(self.window2)
lay.addWidget(self.session_tracker)
self.window2.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_())
I would like to use a QMenu as a permanent widget in the gui. (I like its appearance and layout, and the fact that as soon as I hover over it, the requisite menu pops up, no clicking needed. It would be a pain in the neck to try and emulate it with a custom widget.) I have tried adding it to a parent widget's layout, but after the first time it is used, it disappears. How would I go about keeping it there?
I can't find any option in QMenu that would disable auto-hide, so simplest way would be a subclass that overrides hideEvent. hideEvent is fired just before hide() completes. That means you can't intercept/ignore hide() but you can re-show it:
class PermanentMenu(QtGui.QMenu):
def hideEvent(self, event):
self.show()
Just make your top-level menu from PermanentMenu and it should be fine.
A simple example using it:
import sys
from PyQt4 import QtGui
class PermanentMenu(QtGui.QMenu):
def hideEvent(self, event):
self.show()
class Window(QtGui.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.menu = PermanentMenu()
self.menu.addAction('one')
self.menu.addAction('two')
self.submenu = self.menu.addMenu('submenu')
self.submenu.addAction('sub one')
self.submenu.addAction('sub two')
self.submenu2 = self.menu.addMenu('submenu 2')
self.submenu2.addAction('sub 2 one')
self.submenu2.addAction('sub 2 two')
layout = QtGui.QHBoxLayout()
layout.addWidget(self.menu)
self.setLayout(layout)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())