pyqt - Frameless widget weird titlebar appears - python

I noticed a weird behavior when running a frameless widget in PyQt.
If I minimize it in taskbar multiple times, a Windows XP title bar appears in the top left corner during a few milliseconds and then disappears.
Here is a simple code to reproduce the problem :
import sys
from PyQt5 import QtCore, QtWidgets
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ui = QtWidgets.QWidget()
ui.setWindowFlags(ui.windowFlags() | QtCore.Qt.FramelessWindowHint)
ui.show()
sys.exit(app.exec_())
The behavior is described in this video
My setup is Windows 7 (x64), Python 3.5 and PyQt5.7
(FYI, the problem was also present in PyQt5.6)
Can anyone explain this behavior and give a solution ?

I reported the issue to Qt and it seems to be a general Windows bug :
Sergio Martins added a comment
I can reproduce this problem with a pure Windows example, (passing WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX to CreateWindowEx()).
Doesn't seem fixable, other than removing the minimize button capability.

If anyone still has problems with it:
make the window translucent
create a widget that u can use as a window
Example:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.width = 400
self.height = 220
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.setFixedSize(self.width, self.height)
self.setAttribute(Qt.WA_TranslucentBackground)
self.window = QtWidgets.QWidget(self)
self.window.setStyleSheet("QWidget{background-color: #ffffff;}")
self.window.setGeometry(0, 0, self.width, self.height)
self.minimize_button = QtWidgets.QPushButton("🗕", self.window)
self.minimize_button.setGeometry(355, 2, 20, 20)
self.minimize_button.clicked.connect(self.minimize_window)
def minimize_window(self):
self.setWindowState(QtCore.Qt.WindowMinimized)
Now the title bar does not appear anymore, due to the window being invisible.

Related

PyQt6 / finplot - Compatability Issue? (problem isolated to small runnable code)

My head is spinning from trying to get finplot to create an embedded graph for days with no luck. I decided to restart small.
The code that I included works as-is. However, if I change the import to PyQt6 from PyQt5, it stops working.
The application that I am trying to integrate this into is all done in PyQt6. finplot works and displays externally in my PyQt6 attempts, but I cannot use fplt.create_plot_widget while passing self.window() with PyQt6, it seems.
Honestly, I keep running into trouble any time i try to use pyqtgraph. I sidetracked to do something clever with mplfinance, but I'm back to where i was 6 months ago with trying to get anything graph and Qt related to show up in a layout nicely with the other widgets :/
Any help is appreciated. Thank you.
import sys
import finplot as fplt
from PyQt5.QtWidgets import *
import yfinance
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PyQt5 - QTabWidget'
self.left = 0
self.top = 0
self.width = 600
self.height = 400
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.menu = self.menuBar()
self.widget = MyGraphWidget(self)
self.setCentralWidget(self.widget)
fplt.show(qt_exec=False)
self.show()
class MyGraphWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.resize(600, 400)
self.label = QLabel("AAPL")
self.df = yfinance.download('AAPL')
self.fplt_widget1, self.fplt_widget2 = fplt.create_plot_widget(self.window(), rows=2)
fplt.candlestick_ochl(self.df[['Open', 'Close', 'High', 'Low']])
self.layout.addWidget(self.label)
self.window().axs = [self.fplt_widget1]
self.layout.addWidget(self.fplt_widget1.ax_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec())
This is not an issue with pyqtgraph. That project currently supports PyQt6/PySide6.
However, looking at finplot project's setup.py here, it looks like it is currently on PyQt5 (evidenced by the configuration line install_requires=['pandas', 'PyQt5', 'pyqtgraph>=0.11.1'],). The migration to PyQt6 would have to start there. There is some visible mention of hints toward PyQt6 in the project's issues here and here.
As of today, it appears that your options are:
Submit an issue to finplot's maintainer to request support for PyQt6.
Fork finplot, do the migration work yourself and submit a PR back.
Keep using finplot with PyQt5.

Pyside GUI function overwrite issue

I am learning to make GUI's in PySide.
How do I re-size the buttons inside a QHBoxLayout()? I tried button_1.setFixedWidth() and button_1.setFixedHeight() these make the buttons non-scalable. button_1.move() also doesn't work.
Also I have created a function angles() which have Qlabel and QLineEdit, when I run the program, the button function is over-writing the angles function to display only buttons at right corner of the GUI.
And how to resize the length of the QLineEdit and for it to not extend the whole window?
import sys
from PySide.QtGui import *
from PySide.QtCore import *
class MainWindow(QMainWindow):
#GUI Layout
def __init__(self,parent = None):
super(MainWindow, self).__init__(parent)
widget = QWidget()
self.setCentralWidget(widget)
self.setWindowTitle("Example")
self.setGeometry(400, 100, 1500, 800)
self.angles()
self.makebuttons()
def angles(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
Rotation = QLabel('Rotation:')
Tilt = QLabel('Tilt:')
RoatationEdit = QLineEdit()
TiltEdit = QLineEdit()
grid = QGridLayout()
grid.setSpacing(2)
grid.addWidget(Rotation,1,0)
grid.addWidget(RoatationEdit, 1, 1)
grid.addWidget(Tilt,2,0)
grid.addWidget(TiltEdit, 2, 1)
central_widget.setLayout(grid)
def makebuttons(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
hbox = QHBoxLayout()
button_1 = QPushButton("Button 1",self)
button_1.move(0,30)
hbox.addStretch(1)
button_2 = QPushButton("Button 2",self)
hbox.addStretch(1)
hbox.addWidget(button_1)
hbox.addWidget(button_2)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
central_widget.setLayout(vbox)
# central_widget.addLayout(vbox)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
If you want to resize use: button_1.setFixedSize({your scale}*button_1.size())
The makebuttons function creates another centralWidget by deleting all of the above, so you will not see what you did with angles.
To change the width of QLineEdit use {your QlineEdit} .setFixedWidth({your width})
I use Qt Designer for all of my Pyside GUI work, even if it's a fairly trivial program. It's much more than just a drag-and-drop WYSISYG tool. For things like push buttons in your example, you would be presented with a list of configurable properties including sizing parameters of the button as well as the ability to configure the layout.
So, my solution is to create your GUI in QT Designer then modify the layout there before using the pyside-uic tool to convert the code to python. Then just import the resulting python module into your code. From there you can still re-configure whatever you want later in your code if, for example, you need to change the appearance of your GUI during the course of your program.

PyQt4 Child Windows do NOT minimize to Windows taskbar

Whenever I create a PyQt4 application with secondary (child) windows they do not minimize to the Windows 7 taskbar. Only the main (parent) window shows up on the taskbar. When a child window is minimized it collapses to the bottom of the screen with only the titlebar (and titlebar buttons) showing. Here is some sample code to demo this behavoir:
import sys
from PyQt4 import QtGui, QtCore
class Parent(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Parent, self).__init__(parent)
w = QtGui.QWidget()
layout = QtGui.QVBoxLayout(w)
self.button = QtGui.QPushButton('Create Child')
self.text = QtGui.QTextEdit()
layout.addWidget(self.button)
layout.addWidget(self.text)
self.setCentralWidget(w)
self.setWindowTitle('Parent')
self.button.clicked.connect(self.createChild)
def createChild(self):
self.dialog = QtGui.QMainWindow(self)
#self.dialog.setParent(None)
self.dialog.setWindowTitle('Child')
self.dialog.show()
app = QtGui.QApplication(sys.argv)
p = Parent()
p.show()
sys.exit(app.exec_())
The only way I get my pyqt apps to behave the way I want is to set the parent of the children windows to None.
self.dialog.setParent(None)
Doing so makes keeping track of the children windows a lot more complicated than I feel it should be. Closing the main window does not close the secondary windows for example. With extra code this can work but it seems odd to have to break the parent relationship. Am I missing something?

Qt QGraphicsDropShadowEffect is not showing

I am creating a custom widget my_widget inheriting from QWidget.
Here, I have a label to which I would like to apply QGraphicsDropShadowEffect however it does not seem to be working since I don't see any shadows.
My code is in Python and it's:
eff = QGraphicsDropShadowEffect()
self.my_widget_label.setGraphicsEffect(eff)
I tried various alterations to this code to no avail.
After doing a through search on Google, I came across many similar questions without answers.
What might be the cause? How can I get the shadow?
Works for me in C++. I did the following in a QDialog containing a QLabel object named titleLabel. I'm using Qt 4.8.4 on a Windows XP computer.
QGraphicsDropShadowEffect* eff = new QGraphicsDropShadowEffect(this);
eff->setBlurRadius(5);
titleLabel->setGraphicsEffect(eff);
See if this works for you:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class testShadow(QWidget):
def __init__(self, parent=None):
super(testShadow, self).__init__(parent)
self.resize(94, 35)
self.verticalLayout = QVBoxLayout(self)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QLabel(self)
self.label.setText("Text Label")
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(5)
self.label.setGraphicsEffect(self.shadow)
self.verticalLayout.addWidget(self.label)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
main = testShadow()
main.show()
sys.exit(app.exec_())
I have only every tried to use this (and used it successfully) in QGraphicsScene situations. This works for me, while trying to set it on a normal QWidget actually crashes the entire application:
from PyQt4 import QtGui
class Graphics(QtGui.QWidget):
def __init__(self):
super(Graphics, self).__init__()
layout = QtGui.QVBoxLayout(self)
layout.setMargin(0)
shad = QtGui.QGraphicsDropShadowEffect(self)
shad.setBlurRadius(5)
self.scene = QtGui.QGraphicsScene(self)
self.view = QtGui.QGraphicsView(self)
self.view.setScene(self.scene)
text = self.scene.addText("Drop Shadow!")
text.setGraphicsEffect(shad)
layout.addWidget(self.view)
if __name__ == "__main__":
app = QtGui.QApplication([])
main = Graphics()
main.show()
main.raise_()
app.exec_()

pyqt Window similar to Win32 style

I'm trying to port a Win32 app to Python using pyqt for the GUI, but I can't seem to get a simple window with a text label and edit field such as the following simple Win32 style (basically WS_EX_CLIENTEDGE):
I played with setFrameStyle (ie using different styles and sunken - and then for a good measure all other sensible combinations) of the two widgets and used setContentsMargins() to zero to get it to fill all the space, but the qt window still looks quite different with regard to the border.
I get pretty close with the following (using QtGui.QFrame.WinPanel):
import sys
from PySide import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
label = QtGui.QLabel("Test")
label.setAlignment(QtCore.Qt.AlignCenter)
label.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Sunken)
edit = QtGui.QTextEdit()
edit.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Sunken)
edit.setText("Some text")
edit.moveCursor(QtGui.QTextCursor.MoveOperation.End)
vbox = QtGui.QVBoxLayout()
vbox.setContentsMargins(1, 1, 1, 1)
vbox.setSpacing(1)
vbox.addWidget(label)
vbox.addWidget(edit)
self.setLayout(vbox)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Window Title')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
QFrame docs has an excellent overview of different frame styles.
To get closer than setFrameStyle allows, you need to paint you own widgets/panels, or use something other than QT.
wxPython
pywin32
You are probably not using the right style. Have a look at the documentation for QStyle.

Categories