QPropertyAnimation not working with Window Opacity - python

I'm setting up a new desktop widget to make my life easier at work and using QPropertyAnimation to make it pretty. Fading the app in and out doesn't seem to want to work and in typical coder fashion, it's brought my progress to a standstill.
I'm implementing QPropertyAnimation in a personalised class to make my life easier, but since it's not intially worked I've taken it back to the class code and it's still being pretty stubborn. So far I've tried.
class widget(QWidget):
def init(self):
self.setSize(QSize(300, 300))
self.setWindowOpacity(1)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
def paintEvent(self, event):
s = self.size()
qp = QPainter()
qp.begin(self)
qp.setRenderHint(QPainter.Antialiasing, True)
qp.setBrush(QColor().fromRgb(2,106,194))
qp.setPen(QColor().fromRgb(2,106,194))
qp.drawRoundRect(QRect(0,0, 300, 300), 16, 8)
qp.end()
def show(self):
self.superShow()
a = QPropertyAnimation(self, "windowOpacity")
a.setDuration(500)
a.setStartValue(1)
a.setEndValue(0)
a.start()
def hide(self):
a = QPropertyAnimation(self, "windowOpacity")
a.setDuration(500)
a.setStartValue(0)
a.setEndValue(1)
a.finished.connect(self.superHide)
a.start()
def superShow(self):
super(widget, self).show()
def superHide(self):
super(widget, self).hide()
No error messages at all it just hides and shows after the animation duration is over. No idea where to look or what to do to get it working. I've only been coding for like 3 months or so.

Your code has many errors, for example:
I don't see where you call init().
Animations are local variables that will be removed when the show and hide methods are finished, which is almost instantaneous.
etc.
Instead of changing the opacity directly I will use QGraphicsOpacityEffect, instead of using the show and close method, I will use the showEvent, hideEvent and closeEvent methods.
import sys
from PySide2.QtCore import QEasingCurve, QEventLoop, QPropertyAnimation, QRect, QSize, Qt
from PySide2.QtGui import QColor, QPainter
from PySide2.QtWidgets import QAction, QApplication, QGraphicsOpacityEffect, QWidget
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(QSize(300, 300))
# self.setWindowOpacity(1)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setContextMenuPolicy(Qt.ActionsContextMenu)
quit_action = QAction(self.tr("E&xit"), self)
quit_action.setShortcut(self.tr("Ctrl+Q"))
quit_action.triggered.connect(self.close)
self.addAction(quit_action)
effect = QGraphicsOpacityEffect(self, opacity=1.0)
self.setGraphicsEffect(effect)
self._animation = QPropertyAnimation(
self,
propertyName=b"opacity",
targetObject=effect,
duration=500,
startValue=0.0,
endValue=1.0,
)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing, True)
qp.setBrush(QColor().fromRgb(2, 106, 194))
qp.setPen(QColor().fromRgb(2, 106, 194))
qp.drawRoundedRect(QRect(0, 0, 300, 300), 16, 8)
def fade_in(self):
self._animation.setDirection(QPropertyAnimation.Forward)
self._animation.start()
def fade_out(self):
loop = QEventLoop()
self._animation.finished.connect(loop.quit)
self._animation.setDirection(QPropertyAnimation.Backward)
self._animation.start()
loop.exec_()
def showEvent(self, event):
super().showEvent(event)
self.fade_in()
def closeEvent(self, event):
# fade out
self.fade_out()
super().closeEvent(event)
def hideEvent(self, event):
# fade out
self.fade_out()
super().hideEvent(event)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Related

How to edit only background-color for PyQT5 widgets

I have a problem with styles in PyQT5.
I would like to modify something in the "Fusion" style : when the page loses focus, the blue of some widgets becomes white, i would like to keep them blue.
But when i try to edit only the background color for a QprogressBar, the text is no more centered and there are some other changes.
(app.setStyleSheet("QProgressBar::chunk { background-color : blue}"))
I also tried app.my_progress_bar.setStyleSheed("background-color : blue") which seems to keep text centered but i don't know how to do it for "chunk" item.
Here is a little script if you want to test a solution :
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QPushButton, QProgressBar, QVBoxLayout, QApplication
class Thread(QThread):
_signal = pyqtSignal(int)
def __init__(self):
super(Thread, self).__init__()
def __del__(self):
self.wait()
def run(self):
for i in range(100):
time.sleep(0.1)
self._signal.emit(i)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.setWindowTitle('QProgressBar')
self.btn = QPushButton('Click me')
self.btn.clicked.connect(self.btnFunc)
self.pbar = QProgressBar(self)
self.pbar.setValue(0)
self.resize(300, 100)
self.vbox = QVBoxLayout()
self.vbox.addWidget(self.pbar)
self.vbox.addWidget(self.btn)
self.setLayout(self.vbox)
self.show()
def btnFunc(self):
self.thread = Thread()
self.thread._signal.connect(self.signal_accept)
self.thread.start()
self.btn.setEnabled(False)
def signal_accept(self, msg):
self.pbar.setValue(int(msg))
if self.pbar.value() == 99:
self.pbar.setValue(0)
self.btn.setEnabled(True)
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle("Fusion") ##### When the main windows loses focus, the progressbar becomes white instead of blue
ex = Example()
ex.show()
sys.exit(app.exec_())
When the window have the focus :
When the window does not have the focus :
There is no need to use style sheets as long as the color roles of the widget are known.
Specifically, QProgressBar normally uses the Highlight role, which has a different color for the Inactive color group, so you just need to override it.
palette = self.pbar.palette()
palette.setBrush(
palette.Inactive, palette.Highlight, palette.highlight())
self.pbar.setPalette(palette)
Note that the palette is only a reference, it's completely up to the style to decide which group/role use for a widget (or even completely ignore it). If you use another style than Fusion, the above might not work as expected.
use stylesheet for QProgressBar to achieve centered text and QProgressBar::chunk to keep background color even if it loses focus
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QPushButton, QProgressBar, QVBoxLayout, QApplication
class Thread(QThread):
_signal = pyqtSignal(int)
def __init__(self):
super(Thread, self).__init__()
def __del__(self):
self.wait()
def run(self):
for i in range(100):
time.sleep(0.1)
self._signal.emit(i)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.setWindowTitle('QProgressBar')
self.btn = QPushButton('Click me')
self.btn.clicked.connect(self.btnFunc)
self.pbar = QProgressBar(self)
self.pbar.setValue(0)
# setting background color
self.pbar.setStyleSheet(
"QProgressBar"
"{"
"text-align:center;"
"}"
"QProgressBar::chunk"
"{"
"background-color : blue;"
"text-align:center;"
"color : #E0E0E0;"
"border : 1px"
"}"
)
self.resize(300, 100)
self.vbox = QVBoxLayout()
self.vbox.addWidget(self.pbar)
self.vbox.addWidget(self.btn)
self.setLayout(self.vbox)
self.show()
def btnFunc(self):
self.thread = Thread()
self.thread._signal.connect(self.signal_accept)
self.thread.start()
self.btn.setEnabled(False)
def signal_accept(self, msg):
self.pbar.setValue(int(msg))
if self.pbar.value() == 99:
self.pbar.setValue(0)
self.btn.setEnabled(True)
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle("Fusion") ##### When the main windows loses focus, the progressbar becomes white instead of blue
ex = Example()
ex.show()
sys.exit(app.exec_())

Move QLabel in absolute position with mouse move

I want to move the QLabel with the mouse movement (not like Drag&drop, 'object' disappears while moving). Clicked - moved - released. I did it to some extent, but I ran into a problem. QLabel shrinks as I move it or even disappears (like shrinks to 0 width). How to fix it or what more correct approach to do it?
(self.label_pos is needed to keep the mouse position relative inside self.label)
Or its just monitor's refresh rate issue? But in photoshop's gradient editor, that little color stop isn't shrikns. It's choppy because of refresh rate, but always the same size.
This is what I want to see, recorded using a screen capture program. The same thing I see in Photoshop
This is what I see, recorded on my phone. The quality is poor, but the difference is clearly visible anyway.
This Photoshop is also captured on my phone, here the “object” remains the same size, as in the example made using screen capture
Here is code from eyllanesc's answer, 'object' still shrinks :(
self.label = QLabel(self)
self.label.move(100, 100)
self.label.mousePressEvent = self.mouse_on
self.label.mouseReleaseEvent = self.mouse_off
def mouse_on(self, event):
self.bool = True
self.label_pos = event.pos()
def mouse_off(self, event):
self.bool = False
def mouseMoveEvent(self, event):
if self.bool:
self.label.move(event.x()-self.label_pos.x(), event.y()-self.label_pos.y())
Instead of using a QLabel I recommend using QGraphicsRectItem with a QGraphicsView since it is specialized in this type of tasks:
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.setScene(QtWidgets.QGraphicsScene(self))
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
brush = QtWidgets.QApplication.palette().brush(QtGui.QPalette.Window)
self.setBackgroundBrush(brush)
rect_item = self.scene().addRect(
QtCore.QRectF(QtCore.QPointF(), QtCore.QSizeF(40, 80))
)
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
rect_item.setBrush(QtGui.QBrush(QtGui.QColor("red")))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.setFixedSize(640, 480)
w.show()
sys.exit(app.exec_())
If you want to just scroll horizontally then overwrite the itemChange method of QGraphicsItem:
from PyQt5 import QtCore, QtGui, QtWidgets
class HorizontalItem(QtWidgets.QGraphicsRectItem):
def __init__(self, rect, parent=None):
super(HorizontalItem, self).__init__(rect, parent)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True)
def itemChange(self, change, value):
if (
change == QtWidgets.QGraphicsItem.ItemPositionChange
and self.scene()
):
return QtCore.QPointF(value.x(), self.pos().y())
return super(HorizontalItem, self).itemChange(change, value)
class Widget(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.setScene(QtWidgets.QGraphicsScene(self))
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
brush = QtWidgets.QApplication.palette().brush(QtGui.QPalette.Window)
self.setBackgroundBrush(brush)
rect_item = HorizontalItem(
QtCore.QRectF(QtCore.QPointF(), QtCore.QSizeF(40, 80))
)
rect_item.setBrush(QtGui.QBrush(QtGui.QColor("red")))
self.scene().addItem(rect_item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.setFixedSize(640, 480)
w.show()
sys.exit(app.exec_())
In the following code there is an example similar to what you want:
from PyQt5 import QtCore, QtGui, QtWidgets
class HorizontalItem(QtWidgets.QGraphicsRectItem):
def __init__(self, rect, parent=None):
super(HorizontalItem, self).__init__(rect, parent)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True)
def itemChange(self, change, value):
if (
change == QtWidgets.QGraphicsItem.ItemPositionChange
and self.scene()
):
return QtCore.QPointF(value.x(), self.pos().y())
return super(HorizontalItem, self).itemChange(change, value)
class Widget(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.setScene(QtWidgets.QGraphicsScene(self))
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
brush = QtWidgets.QApplication.palette().brush(QtGui.QPalette.Window)
self.setBackgroundBrush(brush)
self.setFixedSize(640, 480)
size = self.mapToScene(self.viewport().rect()).boundingRect().size()
r = QtCore.QRectF(QtCore.QPointF(), size)
self.setSceneRect(r)
rect = QtCore.QRectF(
QtCore.QPointF(), QtCore.QSizeF(0.8 * r.width(), 80)
)
rect.moveCenter(r.center())
rect_item = self.scene().addRect(rect)
rect_item.setBrush(QtGui.QBrush(QtGui.QColor("salmon")))
item = HorizontalItem(
QtCore.QRectF(
rect.bottomLeft() + QtCore.QPointF(0, 20), QtCore.QSizeF(20, 40)
)
)
item.setBrush(QtGui.QBrush(QtGui.QColor("red")))
self.scene().addItem(item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Cannot save the state of Qt drawing

Maybe it is insufficient knowledge of Qt or of Python, of maybe even both, but I have a problem with Qt5 in Python.
I have a script that draws a line from a point where the mouse pointer is depressed to the point where it is released. That works fine.
Then when I want to draw a second line, I want to keep the first line on the QDialog as well, but because the way paintEvent works that is not possible straight away.
There for I've created a helper class (at first it was in the MyDialog class itself) to store all the points in a list and then use this class to redraw all the lines when paintEvent redraws the QDialog.
However, this is not working because for some reason all the points stored in the helper class get overridden by the last point. So if I draw ten lines, the helper class has 10 times the last (10th) point in its list.
Below you can see the code, can somebody shine a light on this? Thank!
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtGui import QPainter, QPicture
from demoDrawLine import *
class ContextTest:
test = []
class MyForm(QDialog):
picture = []
def __init__(self):
super().__init__()
self.drawing = []
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.pos1 = [0,0]
self.pos2 = [0,0]
self.show()
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter()
qp.begin(self)
qp.drawLine(self.pos1[0], self.pos1[1], self.pos2[0], self.pos2[1])
qp.end()
def mousePressEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
self.pos1[0], self.pos1[1] = event.pos().x(), event.pos().y()
def mouseReleaseEvent(self, event):
self.pos2[0], self.pos2[1] = event.pos().x(), event.pos().y()
ContextTest.test.append((self.pos1, self.pos2))
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
Here some results I copied from the debugger:
1st line drawn: ContextTest.test : [([150, 335], [452, 618])]
2nd line drawn: ContextTest.test : [([311, 695], [340, 666]), ([311, 695], [340, 666])]
3rd line drawn: ContextTest.test : [([1444, 249], [1043, 712]), ([1444, 249], [1043, 712]), ([1444, 249], [1043, 712])]
etc...
You are saving the points in test but you are not using it to paint, as you realized paintEvent has no notion of the past so you will have to save those points but better than saving points would be to keep instructions that know how to paint, for example it could add other figures without needing to write a lot of code in it.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Instruction:
def paint(self, painter):
raise NotImplementedError()
class LineInstruction(Instruction):
def __init__(self, line):
self._line = line
def paint(self, painter):
painter.drawLine(self._line)
class ContextTest:
instructions = []
class MyForm(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.drawing = []
self.show()
def paintEvent(self, event):
super().paintEvent(event)
qp = QtGui.QPainter(self)
for instruction in ContextTest.instructions:
instruction.paint(qp)
def mousePressEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
self.start = event.pos()
def mouseReleaseEvent(self, event):
l = QtCore.QLine(self.start, event.pos())
instruction = LineInstruction(l)
ContextTest.instructions.append(instruction)
self.update()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())

Mouse position in mouseMoveEvent and mousePressEvent are different: QGraphicsObject

Mouse position in mouseMoveEvent and mousePressEvent are different in the following example. This is happening due to the added scaling. Without scaling the positions are same.
Do I have to update the boundingRect according to the changed scaling? How?
#!/usr/bin/env python
from PyQt5.QtCore import (QRectF)
from PyQt5.QtGui import (QPainter, QPixmap)
from PyQt5.QtWidgets import (QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene)
class TicTacToe(QGraphicsObject):
def __init__(self, helper):
super(TicTacToe, self).__init__()
self.mypixmap = QPixmap("exit1.png")
def paint(self, painter, option, widget):
painter.setOpacity(1)
painter.drawPixmap(0,0, 512, 512, self.mypixmap)
painter.drawLine(2,2,20,20)
def boundingRect(self):
return QRectF(0,0,512, 512)
def keyPressEvent(self, event):
print "aaaaaaaaaa"
def mouseMoveEvent(self, event):
print "ccccccccccc ", event.pos()
def mousePressEvent(self, event):
print "bbbbbbbbbbbb", event.pos()
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.scene = QGraphicsScene(self)
self.tic_tac_toe = TicTacToe(self)
self.myScale = 2
self.tic_tac_toe.setScale(self.myScale)
self.setScene(self.scene)
self.scene.addItem(self.tic_tac_toe)
self.setMouseTracking(True)
def keyPressEvent(self, event):
self.tic_tac_toe.keyPressEvent(event)
def mouseMoveEvent(self, event):
print "mouse"
self.tic_tac_toe.mouseMoveEvent(event)
class Example(QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.y = MyGraphicsView()
self.setCentralWidget(self.y)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Example()
w.show()
sys.exit(app.exec_())
The problem is caused because you are sending the QGraphicsView events to a QGraphicsObject. In the case of QGraphicsView the event is of the QMouseEvent type but in the case of QGraphicsObject it is of the QGraphicsSceneMouseEvent type. In conclusion, you should not pass the QGraphicsView events to the QGraphicsObject since they refer to different events with different information.
The mousePressEvent event is enabled by default but in the case of the mouseMoveEvent event it can not be handled by QGraphicsObject, instead you must use hoverMoveEvent but these will only work inside the boundingRect of the QGraphicsObject.
#!/usr/bin/env python
from PyQt5.QtCore import (QRectF)
from PyQt5.QtGui import (QPainter, QPixmap)
from PyQt5.QtWidgets import (QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene)
class TicTacToe(QGraphicsObject):
def __init__(self, helper):
super(TicTacToe, self).__init__()
self.mypixmap = QPixmap("exit1.png")
self.setAcceptHoverEvents(True)
def paint(self, painter, option, widget):
painter.setOpacity(1)
painter.drawPixmap(0,0, 512, 512, self.mypixmap)
painter.drawLine(2,2,20,20)
def boundingRect(self):
return QRectF(0,0,512, 512)
def hoverMoveEvent(self, event):
print("ccccccccccc ", event.pos())
def mousePressEvent(self, event):
print("bbbbbbbbbbbb", event.pos())
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.scene = QGraphicsScene(self)
self.tic_tac_toe = TicTacToe(self)
self.myScale = 2
self.tic_tac_toe.setScale(self.myScale)
self.setScene(self.scene)
self.scene.addItem(self.tic_tac_toe)
class Example(QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.y = MyGraphicsView()
self.setCentralWidget(self.y)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Example()
w.show()
sys.exit(app.exec_())
On the other hand, these points do not coincide with the position in the scene since those coordinates are relative to the item.
For you to understand better we could use the following analogy, let's say you are recording a scene with a camera, the camera's screen is like the QGraphicsView, the scene is the QGraphicsScene and the actors are the QGraphicsItems and QGraphicsObjects. Each of these elements has a different coordinate system.
In the case of QGraphicsView your QMouseEvent returns coordinates in units of pixels, if you want to convert it to coordinates of the scene you must use mapToScene().
In the case of the QGraphicsItem/QGraphicsObject have different coordinates to those of the scene, those are not affected by the transformations such as scale, rotation, etc. That is what is printing in the previous example. If you want to convert it to units of the scene you must use mapToScene().
In the following example I show all the impressions in units of the scene.
#!/usr/bin/env python
from PyQt5.QtCore import (QRectF)
from PyQt5.QtGui import (QPainter, QPixmap)
from PyQt5.QtWidgets import (QMainWindow, QApplication, QGraphicsObject, QGraphicsView, QGraphicsScene)
class TicTacToe(QGraphicsObject):
def __init__(self, helper):
super(TicTacToe, self).__init__()
self.mypixmap = QPixmap("exit1.png")
self.setAcceptHoverEvents(True)
def paint(self, painter, option, widget):
painter.setOpacity(1)
painter.drawPixmap(0,0, 512, 512, self.mypixmap)
painter.drawLine(2,2,20,20)
def boundingRect(self):
return QRectF(0,0,512, 512)
def hoverMoveEvent(self, event):
#print("hoverMoveEvent ", event.pos())
print("hoverMoveEvent", self.mapToScene(event.pos()))
def mousePressEvent(self, event):
#print("mousePressEvent", event.pos())
print("mousePressEvent", self.mapToScene(event.pos()))
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.scene = QGraphicsScene(self)
self.setMouseTracking(True)
self.tic_tac_toe = TicTacToe(self)
self.myScale = 2
self.tic_tac_toe.setScale(self.myScale)
self.setScene(self.scene)
self.scene.addItem(self.tic_tac_toe)
def mouseMoveEvent(self, event):
print("mouseMoveEvent", self.mapToScene(event.pos()))
class Example(QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.y = MyGraphicsView()
self.setCentralWidget(self.y)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Example()
w.show()
sys.exit(app.exec_())
If you want more information check the following links:
http://doc.qt.io/qt-5/graphicsview.html
http://blog.qt.io/blog/2017/01/19/should-you-be-using-qgraphicsview/

PyQt Irregularly Shaped Windows (e.g. A circular without a border/decorations)

How do I create an irregularly shaped window in PyQt?
I found this C++ solution, however I am unsure of how to do that in Python.
Here you go:
from PyQt4 import QtGui, QtWebKit
from PyQt4.QtCore import Qt, QSize
class RoundWindow(QtWebKit.QWebView):
def __init__(self):
super(RoundWindow, self).__init__()
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
def sizeHint(self):
return QSize(300,300)
def paintEvent(self, event):
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing);
qp.setPen(Qt.NoPen);
qp.setBrush(QtGui.QColor(255, 0, 0, 127));
qp.drawEllipse(0, 0, 300, 300);
qp.end()
a = QtGui.QApplication([])
rw = RoundWindow()
rw.show()
a.exec_()
Screenshot
I've never written C++ in my life, but reading that code example was not that hard. You'll find that most Qt documentation online is in C++, so it's useful to at least be able to read.
Here is a PyQT5 example, which creates frameless, movable QWidget, with transparent png mask to generate irregularly shaped Window:
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import Qt, QPoint
class IrregularWindow(QtWidgets.QWidget):
def __init__(self):
super(IrregularWindow, self).__init__()
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
def sizeHint(self):
return QSize(107, 41) # Set this to the exact image resolution
def paintEvent(self, event):
qp = QtGui.QPainter()
qp.begin(self)
pixmap = QtGui.QPixmap()
pixmap.load('image_with_transparency.png')
qp.drawPixmap(QPoint(0, 0), pixmap)
qp.end()
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
def mouseMoveEvent(self, event):
delta = QPoint(event.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
a = QtWidgets.QApplication([])
rw = IrregularWindow()
rw.show()
a.exec_()

Categories