Basically I want to create a window using QtGui.QWindow() instead of QtWidgets.QMainWindow().
I want to do this because I want to have access to QWindow functions such as:
startSystemMove()
setTitle()
setWindowStates()
startSystemResize()
At first I thought you make the window class inherit QtGui.QWindow, but if you do that, it just creates an empty window.
However, QWindow functions do work. So my guess is that I have to somehow input the QMainWindow (or the widgets inside it) into the QWindow, but I have no idea how.
So that there is an XY problem since the objective is to modify properties of the QWindow associated with the QWidget but instead it asks how to embed a QWidget into a QWindow.
QWidget creates a QWindow after using the show() method and it can be accessed using the windowHandle() method.
import sys
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow
def main():
app = QApplication(sys.argv)
mainwindow = QMainWindow()
mainwindow.show()
window = mainwindow.windowHandle()
window.setTitle("Foo")
def start_resize():
window.startSystemResize(Qt.TopEdge)
def start_move():
window.startSystemMove()
def maximized():
window.setWindowStates(Qt.WindowMaximized)
QTimer.singleShot(5 * 1000, start_resize)
QTimer.singleShot(10 * 1000, start_move)
QTimer.singleShot(15 * 1000, maximized)
sys.exit(app.exec())
if __name__ == "__main__":
main()
Note: Some methods of the QWidget are a wrapper of the QWindow methods such as setWindowTitle() or setWindowState().
Related
I have this Python 3.5.1 program with PyQt5 and a GUI created from a QtCreator ui file where the pyqtSlot decorator causes "TypeError: connect() failed between textChanged(QString) and edited()".
In the sample code to reproduce the problem I have 2 custom classes: MainApp and LineEditHandler. MainApp instantiates the main GUI (from the file "mainwindow.ui") and LineEditHandler handles a QLineEdit object. LineEditHandler reason to exist is to concentrate the custom methods that relate mostly to the QLineEdit object in a class. Its constructor needs the QLineEdit object and the MainApp instance (to access other objects/properties when needed).
In MainApp I connect the textChanged signal of the QLineEdit to LineEditHandler.edited(). If I don't decorate LineEditHandler.edited() with pyqtSlot() everything works fine. If I do use #pyqtSlot() for the method, the code run will fail with "TypeError: connect() failed between textChanged(QString) and edited()". What am I doing something wrong here?
You can get the mainwindow.ui file at: https://drive.google.com/file/d/0B70NMOBg3HZtUktqYVduVEJBN2M/view
And this is the sample code to generate the problem:
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot
Ui_MainWindow, QtBaseClass = uic.loadUiType("mainwindow.ui")
class MainApp(QMainWindow, Ui_MainWindow):
def __init__(self):
# noinspection PyArgumentList
QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
# Instantiate the QLineEdit handler.
self._line_edit_handler = LineEditHandler(self, self.lineEdit)
# Let the QLineEdit handler deal with the QLineEdit textChanged signal.
self.lineEdit.textChanged.connect(self._line_edit_handler.edited)
class LineEditHandler:
def __init__(self, main_window, line_edit_obj):
self._line_edit = line_edit_obj
self._main_window = main_window
# FIXME The pyqtSlot decorator causes "TypeError: connect() failed between
# FIXME textChanged(QString) and edited()"
#pyqtSlot(name="edited")
def edited(self):
# Copy the entry box text to the label box below.
self._main_window.label.setText(self._line_edit.text())
def main():
app = QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Why do you want to use #pyqtSlot?
The reason it fails is that LineEditHandler is not a QObject. What #pyqtSlot does is basically creating a real Qt slot instead of internally using a proxy object (which is the default behavior without #pyqtSlot).
I don't know what was wrong, but I found a workaround: Connect the textChanged signal to a pyqtSlot decorated MainApp method that calls LineEditHandler.edited():
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot
Ui_MainWindow, QtBaseClass = uic.loadUiType("mainwindow.ui")
class MainApp(QMainWindow, Ui_MainWindow):
def __init__(self):
# noinspection PyArgumentList
QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
# Instantiate the QLineEdit handler.
self._line_edit_handler = LineEditHandler(self, self.lineEdit)
self.lineEdit.textChanged.connect(self._line_edited)
#pyqtSlot(name="_line_edited")
def _line_edited(self):
self._line_edit_handler.edited()
class LineEditHandler:
def __init__(self, main_window, line_edit_obj):
self._line_edit = line_edit_obj
self._main_window = main_window
def edited(self):
# Copy the entry box text to the label box below.
self._main_window.label.setText(self._line_edit.text())
def main():
app = QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
what i want to achieve
I am learning how to use pyqt5 with this project of mine.
I tried downloading something called BlurWindow but it kept giving me a parameter error so switched back to trying to use QGraphicBlurEffect but it blurs everything inside my MainWindow
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
import sys
from PyQt5.uic import loadUi
from BlurWindow.blurWindow import blur
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
loadUi(r'D:\Workspace\Qt Designer\blur bg\blurtest.ui',self)
self.setAttribute(Qt.WA_TranslucentBackground)
hWnd = self.winId()
print(hWnd)
blur(hWnd)
self.setStyleSheet("background-color: rgba(0, 0, 0, 0)")
app=QApplication(sys.argv)
mainwindow=MainWindow()
widget=QtWidgets.QStackedWidget()
widget.setWindowOpacity(0.5)
widget.addWidget(mainwindow)
widget.setFixedHeight(600)
widget.setFixedWidth(800)
widget.show()
sys.exit(app.exec_())
BlurWindow uses system features to set the background of a top level window.
Your problem is that you're applying it to the wrong widget, which is a child widget, not a top level one. The top level has no "glass effect" set, so the result is that it won't have any effect applied on it.
The solution is simple: apply the effect to the top level window.
import sys
from PyQt5.QtWidgets import *
from PyQt5.uic import loadUi
from BlurWindow.blurWindow import blur
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
loadUi(r'D:\Workspace\Qt Designer\blur bg\blurtest.ui', self)
self.setStyleSheet("""
MainWindow {
background-color: rgba(0, 0, 0, 0);
}
""")
app = QApplication(sys.argv)
mainwindow = MainWindow()
widget = QtWidgets.QStackedWidget()
widget.addWidget(mainwindow)
widget.setFixedHeight(600)
widget.setFixedWidth(800)
blur(widget.winId()) # <---
widget.show()
sys.exit(app.exec_())
Note that:
QMainWindow is not supposed to be used as a child widget. You should switch to a basic QWidget (or other container widgets like QFrame), meaning that you should create a new "widget" in Designer and copy/paste the content of your previous window to it, otherwise loadUi() will throw an exception;
you should never apply generic style sheet properties to parent widgets, as you would get unexpected results (especially with complex widgets, like scroll areas); you should always use proper selectors (as I did above);
I can't make form1 to make parent object like it needs to be.
And all content in second form align to left-top corner and i have no way to make it work fine. May be someone know what i can do with this. Thank you!
How it looks in Qt Designer:
But how it looks really:
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QMainWindow, QApplication
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# Set up the user interface from Designer.
uic.loadUi("mw.ui", self)
uic.loadUi("form1.ui", self.mn_general)
# Connect up the buttons.
self.pushButton.clicked.connect(self.BtnClck)
self.show()
def BtnClck(self):
print('Hello StackOverflow')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
How QApplication() and QWidget() are connected?
This is an example code that I copied, it creates QApplication object and QWidget object, but there is no link between the two objects. I expected something like app.setWidget(did) to teach PySide/PyQt controller about the widget that was created.
# http://zetcode.com/gui/pysidetutorial/firstprograms/
# 1. PySide.QtGui is the class
import sys
from PySide import QtGui
# 2. setup the application
app = QtGui.QApplication(sys.argv)
# 3. create the widget and setup
wid = QtGui.QWidget()
wid.resize(250, 150)
wid.setWindowTitle('Simple')
# 4. Show the widget
wid.show()
# 5. execute the app
sys.exit(app.exec_())
What's the magic behind this?
QApplication is a singleton so it would be pretty easy, for QWidget to do: QApplication.instance() and interact with the QApplication instance.
In fact trying to instantiate QWidget before the QApplication leads to an error:
>>> QtGui.QWidget()
QWidget: Must construct a QApplication before a QPaintDevice
Which probably means this is what happens.
Edit: I've downloaded the qt sources and in fact, in src/gui/kernel/qwidget.cpp, line 328, there is:
if (!qApp) {
qFatal("QWidget: Must construct a QApplication before a QPaintDevice");
return;
}
Where qApp is a pointer to the QApplication instance(i.e. it is equivalent to calling QApplication.instance()).
So, in the end, the QWidget interacts with the QApplication via a global variable, even though it isn't necessary. They probably use qApp instead of QApplication.instance() to avoid unnecessary overhead that might happen when creating/destroying many QWidgets.
I'm having problems with a "New Window" function in PyQt4/PySide with Python 2.7. I connected a initNewWindow() function, to create a new window, to an action and put it in a menu bar. Once a common function in desktop software. Instead of giving me a new persistent window alongside the other one the new window pops up and closes. The code I'm working on is proprietary so I created an example that does the same thing with the same error below. Is there any way to get this to work? Runs in PySide with Python 2.7. It was written in and tested in Windows.
from PySide.QtCore import QSize
from PySide.QtGui import QAction
from PySide.QtGui import QApplication
from PySide.QtGui import QLabel
from PySide.QtGui import QMainWindow
from PySide.QtGui import QMenuBar
from PySide.QtGui import QMenu
from sys import argv
def main():
application = QApplication(argv)
window = QMainWindow()
window.setWindowTitle('New Window Test')
menu = QMenuBar(window)
view = QMenu('View')
new_window = QAction('New Window', view)
new_window.triggered.connect(initNewWindow)
view.addAction(new_window)
menu.addMenu(view)
label = QLabel()
label.setMinimumSize(QSize(300,300))
window.setMenuBar(menu)
window.setCentralWidget(label)
window.show()
application.exec_()
def initNewWindow():
window = QMainWindow()
window.setWindowTitle('New Window')
window.show()
if __name__ == '__main__':
main()
If a function creates a PyQt object that the application needs to continue using, you will have to ensure that a reference to it is kept somehow. Otherwise, it could be deleted by the Python garbage collector immediately after the function returns.
So either give the object a parent, or keep it as an attribute of some other object. (In principle, the object could also be made a global variable, but that is usually considered bad practice).
Here's a revised version of your example script that demonstrates how to fix your problem:
from PySide import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
menu = self.menuBar().addMenu(self.tr('View'))
action = menu.addAction(self.tr('New Window'))
action.triggered.connect(self.handleNewWindow)
def handleNewWindow(self):
window = QtGui.QMainWindow(self)
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle(self.tr('New Window'))
window.show()
# or, alternatively
# self.window = QtGui.QMainWindow()
# self.window.setWindowTitle(self.tr('New Window'))
# self.window.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(300, 300)
window.show()
sys.exit(app.exec_())
When initNewWindow() returns, the window variable is deleted and the window's reference count drops to zero, causing the newly created C++ object to be deleted. This is why your window closes immediately.
If you want to keep it open, make sure to keep a reference around. The easiest way to do this is to make your new window a child of the calling window, and set its WA_DeleteOnClose widget attribute (see Qt::WidgetAttribute).