PySide2 How to make a transparent widget background - python-3.x

I'm writing a widget that should have a transparent background.
Unfortunately, I get a black background instead of transparent.
I've used attributes like:
WA_TranslucentBackground
WA_NoSystemBackground
and also flags:
Qt.FramelessWindowHint
Qt.X11BypassWindowManagerHint
my system using KWin windows manager which is based on x.org
Here's a quick example of my widget:
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
import sys
from psutil import cpu_percent
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__()
self.resize(600, 600)
self.dark = "#3B3A44"
self.light = "#4a4953"
self.color = "#75ECB5"
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.setAttribute(Qt.WA_NoSystemBackground, True)
self.setStyleSheet("background:transparent;")
# self.setAttribute(QtCore.Qt.WA_PaintOnScreen)
self.setWindowFlags(Qt.FramelessWindowHint |
Qt.X11BypassWindowManagerHint |
Qt.Tool)
def paintEvent(self, event: QPaintEvent):
""" Dessine l'horloge """
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
base_rect = self.rect().adjusted(20, 20, -20, -20)
painter.setBrush(QBrush(QColor(self.dark)))
painter.drawEllipse(base_rect)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.move(800, 300)
w.show()
app.exec_()

Check if translucency is enable on your KDE systemsettings.
Also you can install other tools like xcompmgr and execute it before starting your app.

Related

PyQt issue with animating rotation

I experiencing some issue while trying to understand how animate a qgraphicItem in Pyqt.
I'm trying to animate a qgraphicsItem inside a scene, but when the animation starts all the objects rotate. Is there someone who can help me?
here is my code.
from PyQt6.QtGui import *
from PyQt6.QtCore import *
from PyQt6.QtWidgets import *
class GraphicsView(QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setRenderHints(QPainter.RenderHint.Antialiasing
| QPainter.RenderHint.TextAntialiasing | QPainter.RenderHint.SmoothPixmapTransform)
self.setViewportUpdateMode(QGraphicsView.ViewportUpdateMode.FullViewportUpdate)
self.scene = QGraphicsScene(QRectF(-250, -250, 1000, 1000), self)
self.setScene(self.scene)
self.graphicItem = QGraphicsRectItem(0, 0, 100, 100)
self.graphicItem.setZValue(10)
self.graphicItem.setPos(100, 100)
self.scene.addItem(self.graphicItem)
self.scene.addRect(self.sceneRect(), brush=QBrush(Qt.GlobalColor.gray))
self.animateRotation()
def rot(self, angle: QVariant) -> None:
self.rotate(self.graphicItem.rotation() - angle)
self.graphicItem.setRotation(angle)
#pyqtSlot()
def animateRotation(self):
self.animation = QVariantAnimation(self)
self.animation.setStartValue(QVariant(0))
self.animation.setEndValue(QVariant(180))
self.animation.setDuration(10000)
self.animation.start()
self.animation.valueChanged.connect(self.rot)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = GraphicsView()
w.resize(720, 720)
w.show()
sys.exit(app.exec())

scaledToHeight() does not scale to height - PyQt5

I'm trying to render my image, but scaled to the height of the current window and keeping with aspect ratio.
The following does just that, but does not actually scale the image:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Img(QWidget):
def __init__(self, parent=None):
super(Img, self).__init__(parent)
self.setAttribute(Qt.WA_StyledBackground, True)
self.setStyleSheet('background-color: orange')
window = QDesktopWidget().screenGeometry(0)
height = window.height()
layout = QVBoxLayout(self)
pixmap = QPixmap("test.png")
pixmap = pixmap.scaledToHeight(height)
label = QLabel()
label.setPixmap(pixmap)
label.setScaledContents(True)
layout.addWidget(label)
print(height)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
img = Img()
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(img)
layout.setAlignment(Qt.AlignCenter)
content = QWidget()
content.setLayout(layout)
w,h = (1024,670)
self.resize(w,h)
self.setCentralWidget(content)
self.show()
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
app.exec_()
Although it prints out height is 1050, what I see is a huge image and the window expands down past my monitor. Can someone explain the issue and what needs to happen for scaledToHeight()?
Here is an example of what I see:
And here is the actual image:
The image gets cut off because it gets extended past the monitor screen, and is also stretched oddly.

PyQt5 - How to draw a dot on mouse click position?

I am trying to draw a dot on my main window, but the dot is not shown.
I've tried bounding mousePressEvent to paintEvent, but it didn't work as well. Here's current version of my code(which is not working too). Also I tried place a point with drawPoint method and it didn't work too.
import sys
from PyQt5 import QtWidgets, QtGui, QtCore, uic
class GUI(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('gui.ui', self)
self.setFixedSize(self.size())
self.show()
def mousePressEvent(self, e):
print(e.pos())
qp = QtGui.QPainter()
qp.begin(self)
qp.setPen(QtCore.Qt.red)
qp.drawEllipse(e.pos().x(), e.pos().y(), 10, 10)
qp.end()
self.update()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = GUI()
sys.exit(app.exec_())
I know that mousePressEvent is working since I get coords of the click.
I am okay to change methods of dot-placing or type of dots to place, but it should have customizable color and size.
You should only draw within the paintEvent method, and this paint does not save memory so if you want to graph several points you must store them in some container, for example using QPolygon.
paintEvent() is called every time you call update() or repaint(), for example it is called every time it is resized, the window is moved, etc.
import sys
from PyQt5 import QtWidgets, QtGui, QtCore, uic
class GUI(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('gui.ui', self)
self.setFixedSize(self.size())
self.show()
self.points = QtGui.QPolygon()
def mousePressEvent(self, e):
self.points << e.pos()
self.update()
def paintEvent(self, ev):
qp = QtGui.QPainter(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing)
pen = QtGui.QPen(QtCore.Qt.red, 5)
brush = QtGui.QBrush(QtCore.Qt.red)
qp.setPen(pen)
qp.setBrush(brush)
for i in range(self.points.count()):
qp.drawEllipse(self.points.point(i), 5, 5)
# or
# qp.drawPoints(self.points)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = GUI()
sys.exit(app.exec_())

QGraphicsview + scene + QGroupBox movement issue

For past few days I was trying to solve the issue of widget movement. At some point I tried rewriting QComboBox classes with mouse signals but that did not work. As a work around I settled for parenting my widget to a QGraphicsWidget but once I try to add another item it does not display any more and I'm not sure what to do. Here is full test script:
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QApplication,QGraphicsItem, QGraphicsView, QGraphicsScene, QDesktopWidget, QCheckBox, QGroupBox, QPushButton, QGridLayout, QLabel, QLineEdit, QComboBox, QFont, QRadioButton, QButtonGroup, QWidget, QShortcut, QKeySequence, QIcon, QListView, QStandardItemModel, QStandardItem, QAction, QIntValidator, QListWidget, QProgressBar, QSpacerItem
from PyQt4.QtCore import QRect
from functools import partial
import sys
class node_GUI(QtGui.QWidget):
def __init__(self):
super(node_GUI, self).__init__()
class Main(QtGui.QMainWindow):
def __init__(self, *args):
super(Main, self).__init__(*args)#QtGui.QMainWindow.__init__(self)
self.init_defaults()
def init_defaults(self):
self.setGeometry(800,800,500,200)
self.lay_main = QGridLayout()
self.centralwidget = QtGui.QWidget()
self.centralwidget.setLayout(self.lay_main)
self.setCentralWidget(self.centralwidget)
btn_create_node = QPushButton("Create Node View")
btn_create_node.clicked.connect(self.create_node_view)
self.lay_main.addWidget(btn_create_node)
def showWindow(self,window):
window.show()
def printTest(self):
print "Start"
box = QGroupBox("subWidget")
box_btn = QPushButton("Test")
box_btn.clicked.connect(self.printTest)
le_edit = QLineEdit()
lay = QGridLayout()
box.setLayout(lay)
lay.addWidget(box_btn)
lay.addWidget(le_edit)
area = QtGui.QGraphicsWidget()
area.setMinimumSize(QtCore.QSizeF(400,300))
area.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
area.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
proxy = self.scene.addWidget(box)
proxy.setParentItem(area)
print "END"
def create_node_view(self):
print "creting node view"
window = node_GUI()
window.setGeometry(QRect(100, 100, 400, 200))
window.setWindowTitle("node ")
window.setObjectName("node")
show_window = QPushButton("Show Node Editor")
show_window.setObjectName("btn")
show_window.clicked.connect(partial(self.showWindow,window))
self.lay_main.addWidget(show_window)
box = QGroupBox("Widgets")
box_btn = QPushButton("Test")
box_btn.clicked.connect(self.printTest)
le_edit = QLineEdit()
lay = QGridLayout()
box.setLayout(lay)
lay.addWidget(box_btn)
lay.addWidget(le_edit)
area = QtGui.QGraphicsWidget()
area.setMinimumSize(QtCore.QSizeF(300,300))
area.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
area.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
area.setAutoFillBackground(True)
ecs = QtGui.QGraphicsEllipseItem()
ecs.setRect(QtCore.QRectF(79,79,79,79))
ecs.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
ecs.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
view = QGraphicsView()
self.scene = QGraphicsScene()
self.scene.addItem(area)
proxy = self.scene.addWidget(box)
proxy.setParentItem(area)
self.scene.addItem(ecs)
view.setScene(self.scene)
lay_window = QGridLayout()
window.setLayout(lay_window)
lay_window.addWidget(view)
def main():
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
When you click on Create Node View > Show Node Editor > Test button > a new GroupBox should appear but that does not work. Not sure why.
Right so I stopped using QGraphicsWidget() and instead I just use QGraphicsRectItem(ecs for example) once I did that change everything started to work as expected.

How can I make PyQt QSplitter visible?

Can I define the width/height for a QSplitter object? Can I make it visible with a proper arrow?
In my C++ code, I use QSplitter::setHandleWidth()
Adjusting the height would probably require adjusting the height of the container itself.
Here's how you can overwrite the QSplitter class to make the splitters to have some icon to let user know they can resize the widgets, See the image for output.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Handle(QWidget):
def paintEvent(self, e=None):
painter = QPainter(self)
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.Dense6Pattern)
painter.drawRect(self.rect())
class customSplitter(QSplitter):
def addWidget(self, wdg):
super().addWidget(wdg)
self.width = self.handleWidth()
l_handle = Handle()
l_handle.setMaximumSize(self.width*2, self.width*10)
layout = QHBoxLayout(self.handle(self.count()-1))
layout.setSpacing(0)
layout.setContentsMargins(0,0,0,0)
layout.addWidget(l_handle)
class Window(QMainWindow):
def setUI(self, MainWindow):
self.splt_v = customSplitter(Qt.Vertical)
self.splt_v.setHandleWidth(8)
self.splt_v.addWidget(QGroupBox("Box 1"))
self.splt_v.addWidget(QGroupBox("Box 2"))
self.splt_v.addWidget(QGroupBox("Box 3"))
self.wdg = QWidget()
self.v_lt = QVBoxLayout(self.wdg)
self.v_lt.addWidget(self.splt_v)
self.spl_h = customSplitter()
self.spl_h.addWidget(self.wdg)
self.spl_h.addWidget(QGroupBox("Box 4"))
self.spl_h.addWidget(QGroupBox("Box 5"))
self.h_lt = QHBoxLayout()
self.h_lt.addWidget(self.spl_h)
self.w = QWidget()
self.w.setLayout(self.h_lt)
self.w.setGeometry(0,0,1280,720)
self.w.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
MainWindow = QMainWindow()
ui = Window()
ui.setUI(MainWindow)
sys.exit(app.exec_())

Resources