PyQt5: How to hide widgets if no more space is available when resizing the window? - pyqt5

My PyQt application includes a QHBoxLayout which contains two QLabels, one with static text and another with dynamic content.
The minimal code is as follows:
from PyQt5.QtWidgets import QMainWindow, QHBoxLayout, QLabel, QApplication, QWidget, QSizePolicy
from PyQt5.QtCore import Qt
class Window(QMainWindow):
def __init__(self):
super().__init__()
mainLabel = QLabel()
mainLabel.setContentsMargins(10, 5, 10, 5)
mainLabel.setText('Main Label')
mainLabel.setAlignment(Qt.AlignLeft)
mainLabel.setStyleSheet("font: 13pt; font-weight: bold; color: darkblue")
mainLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
label = QLabel()
label.setContentsMargins(10, 5, 10, 5)
label.setText("<span style='color: blue'>Lorem ipsum dolor sit amet,</span> <span style='color: red'> consectetur adipiscing elit,</span>")
label.setAlignment(Qt.AlignRight)
label.setStyleSheet("font: 10pt")
hbox = QHBoxLayout()
hbox.addWidget(mainLabel)
hbox.addWidget(label)
mainWidget = QWidget()
mainWidget.setFixedHeight(50)
mainWidget.setLayout(hbox)
mainWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
self.setCentralWidget(mainWidget)
self.setFixedHeight(50)
self.show()
self.resize(500, 50)
App = QApplication([])
window = Window()
App.exec()
The problem is that when I want to shrink the window, the static label (left one) is gradually covered by the dynamic label. So, in some cases, only a portion of the left label is available.
Is it possible to hide the left label when there is no more space available in the QHBoxLayout for both labels and show it again when there is enough space?

Related

How to apply CSS color filter on Folium map tiles

I want to create a dark mode based on Google Maps tiles in Folium. However, as Google is not provided dark mode tiles, a simple workaround seems to be applying a color filter to tiles. A similar plugin for Leaflet is introduced here.
How can I reach a similar result in Folium? Is it possible by executing javascript through the runJavaScript() method (similar to what was done here)?
A minimal Foilium map embedded in PyQt5 is also provided.
import io
import folium
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.m = folium.Map(
zoom_start = 18,
location = (41.8828, 12.4761),
control_scale=True,
tiles = None
)
folium.raster_layers.TileLayer(
tiles='http://mt1.google.com/vt/lyrs=m&h1=p1Z&x={x}&y={y}&z={z}',
name='Standard Roadmap',
attr = 'Google Map',
).add_to(self.m)
folium.LayerControl().add_to(self.m)
self.data = io.BytesIO()
self.m.save(self.data, close_file=False)
widget=QWidget()
vbox = QVBoxLayout()
self.webView = QWebEngineView()
self.webView.setHtml(self.data.getvalue().decode())
self.webView.setContextMenuPolicy(Qt.NoContextMenu)
vbox.addWidget(self.webView)
widget.setLayout(vbox)
self.setCentralWidget(widget)
self.setWindowTitle("App")
self.setMinimumSize(1000, 600)
self.showMaximized()
App = QApplication([])
window = Window()
App.exec()

Indicating that a QOpenGLWidget widget is to have a translucent background does not appear to work

There is no effect when I set the WA_TranslucentBackground attribute on a widget (derived from QOpenGLWidget). I have to set the attribute on the main window instead, which doesn't seem right: the documentation clearly states that the attribute applies to the widget itself:
Indicates that the widget should have a translucent background, i.e.,
any non-opaque regions of the widgets will be translucent because the
widget will have an alpha channel
What is the correct way to make the widget itself have a translucent background? Here is the code:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidget
from PyQt5.QtCore import Qt, QPointF, QLineF
from PyQt5.QtGui import QColor, QPen, QPainter, QPaintEvent
class LineWidget(QOpenGLWidget):
def __init__(self, parent, start : QPointF, end : QPointF, colour : str = 'black'):
super(LineWidget, self).__init__(parent)
self.colour = colour
self.line = QLineF(start, end)
# self.setAttribute(Qt.WA_TranslucentBackground)
def paintEvent(self, a0: QPaintEvent) -> None:
painter = QPainter(self)
painter.begin(self)
painter.setPen(QPen(QColor(self.colour), 5))
painter.drawLine(self.line)
painter.end()
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.lineWidget = LineWidget(self, QPointF(0, 0), QPointF(400, 400), 'red')
self.setCentralWidget(self.lineWidget)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

I would like to rotate a widget using QGraphicsScene in PyQt (QLineEdit and QPushButton)

I would like to rotate a widget in pyqt5, I have developed this code but it doesn't work. The angle doesn't update and it returns a False. Do anyone know how to update this angle to make the widget rotate? If someone can help, thank you.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
robotx=200
roboty=100
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Awesome Rotating Widget")
self.setGeometry(0, 0, 640, 480)
self.R=Robot()
self.angle=0
self.AngleLineEdit=QLineEdit(self)
self.AngleLineEdit.setGeometry(50,50,160,35)
self.AngleLineEdit.setStyleSheet("background-color: rgba(50,50,50,20); color:black; font-weight: bold; font-size: 8pt; font-family: Helvetica; border-radius:5px;")
self.AcceptButton=QPushButton(self)
self.AcceptButton.setText("Accept")
self.AcceptButton.setGeometry(50,100,160,35)
self.AcceptButton.setStyleSheet("QPushButton{color:black; font-weight: bold; font-size: 8pt; font-family: Helvetica; background-color:rgb(255,255,255,20); border-radius:5px}""QPushButton:hover{background-color : rgb(255,255,255,100);}")
container = RotatableContainer(self,self.R, 0)
container.move(robotx,roboty)
container.resize(150,150)
container.setStyleSheet("background-color:transparent;")
self.AcceptButton.clicked.connect(lambda: self.RotateWidget())
self.AcceptButton.clicked.connect(container.rotate)
self.show()
def RotateWidget(self):
self.angle=int(self.AngleLineEdit.text())
print(self.angle)
class RotatableContainer(QGraphicsView):
def __init__(self, parent, widget, angle):
super().__init__(parent)
scene = QGraphicsScene(self)
self.setScene(scene)
self.proxy = QGraphicsProxyWidget()
self.proxy.setWidget(widget)
self.proxy.setTransformOriginPoint(self.proxy.boundingRect().center())
self.proxy.setRotation(angle)
scene.addItem(self.proxy)
def rotate(self, angle):
print(angle)
self.proxy.setRotation(angle)
class Robot(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(0,0,100,100)
def paintEvent(self, event):
p=QPainter(self)
r=QRect(0,0,99,99)
c=QColor(0,0,0)
p.setBrush(QBrush(c))
p.drawRect(r)
app = QApplication([])
window = MainWindow()
app.exec_()
I have seen an example of how to rotate a widget using a qslider but I don't know how to adapt it using a QLineEdit and a QPushButton.
The first argument of clicked is always its check state, which by default is False for non checkable/checked buttons.
Since you've connected the signal to the rotate function, the argument is that of the button signal, and since False also means 0, you're practically doing self.proxy.setRotation(0).
Set the container as an instance attribute and call its rotate function from there:
class MainWindow(QMainWindow):
def __init__(self):
# ...
self.container = RotatableContainer(self,self.R, 0)
self.container.move(robotx,roboty)
self.container.resize(150,150)
self.container.setStyleSheet("background-color:transparent;")
self.AcceptButton.clicked.connect(self.RotateWidget)
self.show()
def RotateWidget(self):
angle = self.AngleLineEdit.text()
if angle.isdigit():
self.angle = angle
self.container.rotate(self.angle)
Note: you should always use layout managers, and only classes and constants should have capitalized names (see the Style Guide for Python Code).

PyQt5 rotation pixmap

In Pyqt5 I want to rotate a pixmap but every time i tried it changes the size.
My code is:
import math
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel
from PyQt5.QtCore import QObject, QPointF, Qt, QRectF,QRect
from PyQt5.QtGui import QPixmap, QTransform, QPainter
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__()
self.arch1 = QPixmap("arch1.png")
pm = QPixmap(556,556)
rectF = QRectF(0,0,556,556)
painter = QPainter(pm)
painter.drawPixmap(rectF, self.arch1, rectF)
painter.end()
self.label = QLabel("AAAAAAAAAA")
self.label.setPixmap(pm)
butA = QPushButton("A")
butA.clicked.connect(lambda: self.rotate_item())
layout = QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(butA)
self.setLayout(layout)
self.show()
def rotate_item(self):
rectF = QRectF(0,0,556,556)
self.arch1 = self.arch1.transformed(QTransform().rotate(36))
pix = QPixmap(556,556)
painter = QPainter(pix)
painter.drawPixmap(rectF, self.arch1,QRectF(self.arch1.rect()))
painter.end()
self.label.setPixmap(pix)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
if __name__=="__main__":
main()
I want only rotate not resize. What do you suggest me to do?
I have four other files and i want to rotate differently. i post some photos to understand what i want to do.
any other way to do this?
Circle one
Circle two
Complete circle
The problem is that the rotated pixmap has a bigger bounding rectangle.
Consider the following example:
The light blue square shows the actual bounding rectangle of the rotated image, which is bigger.
Using drawPixmap(rectF, self.arch1, QRectF(self.arch1.rect())) will cause to painter to draw the pixmap in the rectangle rectF, using the new bounding rectangle as source, so it becomes "smaller".
Instead of rotating the image, you should rotate the painter. Since transformations by default use the origin point of the painter (0, 0), we need first to translate to the center of the rectangle, rotate the painter, and then retranslate back to the origin.
Note that in the following example I'm also always drawing starting from the source image, without modifying it: continuously applying a transformation will cause drawing artifacts due to aliasing, and after some rotation the quality would be very compromised.
The rotation variable is to keep track of the current rotation.
class Window(QWidget):
def __init__(self, *args, **kwargs):
# ...
self.rotation = 0
def rotate_item(self):
self.rotation = (self.rotation + 36) % 360
rectF = QRectF(0,0,556,556)
pix = QPixmap(556,556)
painter = QPainter(pix)
painter.translate(rectF.center())
painter.rotate(self.rotation)
painter.translate(-rectF.center())
painter.drawPixmap(0, 0, self.arch1)
painter.end()
self.label.setPixmap(pix)

How to stretch QLabel in PyQt5

How to change the following code to get the QLabel stretch to width of the window ?
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 200, 100)
self.label = QLabel('Hello World!', self)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet('font-size: 12pt; background-color: red')
self.show()
app = QApplication([])
win = Window()
app.exec()
As the documentation about QMainWindow says, you must set a central widget for it:
Creating a main window without a central widget is not supported. You must have a central widget even if it is just a placeholder.
The problem is that you need a layout manager in order to properly adapt widget sizes inside a parent, and just manually setting widget geometries is generally discouraged.
You created the label as a direct child, so it will have no knowledge about its parents size changes.
Just set the label as central widget.
self.setCentralWidget(self.label)
Otherwise, you can use a container widget, set a layout and add the label to it, but you still must set the central widget.
central = QWidget()
layout = QVBoxLayout(central)
layout.addWidget(self.label)
self.setCentralWidget(central)
The alternative is to directly use a QWidget instead of QMainWindow as you did in your answer.
you can use sizePolicy
self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
Thank you very much for your answers. The problem is now solved by the following code changes
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 200, 100)
self.label = QLabel('Hello World!', self)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet('font-size: 12pt; background-color: red')
self.box_layout = QHBoxLayout()
self.box_layout.addWidget(self.label)
self.setLayout(self.box_layout)
self.show()
app = QApplication([])
win = Window()
app.exec()
Edit: laytout -> box_layout