I want to change the thickness of the text.
In css there is a property for this
-webkit-text-stroke-width
Is there an analog in PyQt5
Changing the font to a thinner one is not an option since I use a unique font that does not have bold italic versions and so on.
import sys
from PyQt5.QtWidgets import (QRadioButton, QHBoxLayout, QButtonGroup,
QApplication, QGraphicsScene,QGraphicsView, QGraphicsLinearLayout, QGraphicsWidget, QWidget, QLabel)
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import QSize, QPoint,Qt
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter
class Window(QWidget):
def __init__(self):
super().__init__()
self.resize(800, 800)
label = QLabel(self)
label.setText('<div></div>')
font_id = QFontDatabase.addApplicationFont(url)
if font_id == -1:
print('not fond')
font = QFont("my-font",18)
label.setStyleSheet('''font-size: 80pt; font-family: my-font;''')
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
You can try the font-weight property, values 100-900 have varying thickness. There's an equivalent method with QFont.setWeight().
class Template(QWidget):
def __init__(self):
super().__init__()
grid = QGridLayout(self)
grid.addWidget(QLabel('Hello World'), 0, 0, Qt.AlignHCenter)
for i in range(1, 10):
lbl = QLabel(f'({i * 100}) Hello World')
lbl.setStyleSheet(f'font-weight: {i * 100}')
grid.addWidget(lbl, i, 0)
self.setStyleSheet('''
QLabel {
font-size: 24pt;
font-family: Helvetica Neue;
}''')
It looks like this:
Although this will not work for all fonts. You could alternatively subclass QLabel and reimplement paintEvent to draw an outline of the text in the window color.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class ThinLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
path = QPainterPath()
path.addText(event.rect().bottomLeft(), self.font(), self.text())
qp.setPen(QPen(self.palette().color(QPalette.Window), 2))
qp.setBrush(self.palette().text())
qp.drawPath(path)
class Template(QWidget):
def __init__(self):
super().__init__()
grid = QGridLayout(self)
grid.addWidget(QLabel('Hello World'), 0, 0)
grid.addWidget(ThinLabel('Hello World'), 1, 0)
self.setStyleSheet('''
QLabel {
font-size: 80pt;
font-family: Helvetica Neue;
}''')
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = Template()
gui.show()
sys.exit(app.exec_())
Related
My code has two files. One is the "main" file that uses a fixed size QFrame instead of the standard window frame. The second is also a subclassed QWidget for adding to the QScrollArea in the main widget.
I want the QFrame of the subwidget to be fixed and the label to actually use the wordwrap property instead of just making it longer to fit and screwing up the whole QScrollArea scrolling area. I have tried using QSizePolicy for the container_widget and QFrame of the subwidget. A minimal reproducible example is as follows.
main_window.py
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from subwidget import SubWidget
class Window(qtw.QWidget):
def __init__(self):
super().__init__()
# Configure Window
self.setWindowFlags(qtc.Qt.FramelessWindowHint)
self.setAttribute(qtc.Qt.WA_TranslucentBackground)
self.setFixedSize(350, 450)
# Init Methods
self.setupUI()
self.refresh_entries()
self.show()
def setupUI(self):
# Main Layout/Frame
self.main_layout = qtw.QHBoxLayout()
self.main_frame = qtw.QFrame()
self.main_frame_layout = qtw.QVBoxLayout()
# Set Layouts
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.main_frame)
self.main_frame.setLayout(self.main_frame_layout)
# Configure QFrame
self.main_frame.setContentsMargins(10, 10, 10, 10)
self.main_frame.setObjectName("main_frame")
self.main_frame.setStyleSheet("""
border: None;
border-radius: 10px;
background: #1E1E1E;
""")
# Secondary Layout/Widget
self.main_scroll_area = qtw.QScrollArea()
self.container_widget = qtw.QWidget()
self.container_layout = qtw.QVBoxLayout()
self.main_scroll_area.setObjectName("main_scroll_area")
self.main_scroll_area.setWidgetResizable(True)
self.main_scroll_area.setVerticalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.main_scroll_area.setHorizontalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.main_scroll_area.setWidget(self.container_widget)
self.container_widget.setLayout(self.container_layout)
self.container_widget.setObjectName("container_widget")
# Widget -> Layout
self.main_frame_layout.addWidget(self.main_scroll_area, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
def refresh_entries(self):
self.clear_entries()
for i in range(5):
self.container_layout.addWidget(SubWidget(i ** i ** i, i))
def clear_entries(self):
for i in reversed(range(self.container_layout.count())):
try:
widget = self.container_layout.itemAt(i).widget()
widget.setParent(None)
except Exception:
pass
if __name__ == "__main__":
app = qtw.QApplication(sys.argv)
win = Window()
sys.exit(app.exec())
and subwidget.py
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
class SubWidget(qtw.QWidget):
def __init__(self, name, index):
super().__init__()
# Variables
self.name = str(name)
self.index = index
# Init Methods
self.setupUI()
self.show()
def setupUI(self):
# Main Layout/Frame
self.main_layout = qtw.QHBoxLayout()
self.main_frame = qtw.QFrame()
self.main_frame_layout = qtw.QVBoxLayout()
# Set Layouts
self.setLayout(self.main_layout)
self.main_layout.addWidget(self.main_frame)
self.main_frame.setLayout(self.main_frame_layout)
# Configure QFrame
self.main_frame.setContentsMargins(5, 5, 5, 5)
self.main_frame.setStyleSheet("""
border: None;
border-radius: 5px;
background: #000000;
""")
# Secondary Layout/Widget
self.name_lbl = qtw.QLabel()
# Configure Seondary Widgets
self.name_lbl.setText(self.name)
self.name_lbl.setStyleSheet("""
color: #FFFFFF;
""")
self.name_lbl.setWordWrap(True) # https://stackoverflow.com/questions/49838817/how-to-resize-qlabels-to-fit-contents-in-qscrollarea
# Widget -> Layout
self.main_frame_layout.addWidget(self.name_lbl, 0, qtc.Qt.AlignmentFlag.AlignHCenter | qtc.Qt.AlignmentFlag.AlignCenter)
This is a visual of the resulting window/frame.
A Wrapable Anywhere QLabel
My way to achieve this to subclass QLabel and and implement the paintEvent, where you can set the text alignment to TextWrapAnywhere when you drawItemText.
Here is a sample code.
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QStyleOption, QVBoxLayout, QWidget, QStyle
class SuperQLabel(QLabel):
def __init__(self, *args, **kwargs):
super(SuperQLabel, self).__init__(*args, **kwargs)
self.textalignment = Qt.AlignLeft | Qt.TextWrapAnywhere
self.isTextLabel = True
self.align = None
def paintEvent(self, event):
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
self.style().drawItemText(painter, self.rect(),
self.textalignment, self.palette(), True, self.text())
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setFixedSize(100, 200)
self.label = QLabel()
self.label.setWordWrap(True)
self.label.setText("1111111111111111111111111111")
self.slabel = SuperQLabel()
self.slabel.setText("111111111111111111111111111")
self.centralwidget = QWidget()
self.setCentralWidget(self.centralwidget)
self.mainlayout = QVBoxLayout()
self.mainlayout.addWidget(self.label)
self.mainlayout.addWidget(self.slabel)
self.centralwidget.setLayout(self.mainlayout)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The result.
Note: this work is tested with pyqt5, pyside2, pyside6 and should work in qt5 as well (in c++).
I'm using
self.setStyleSheet("background-color: white")
to change the background color of a QScrollArea in PyQt5, but that also affects the scroll bar. What is the proper way of just changing the area background color?
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QLabel, QVBoxLayout, QScrollArea)
class TaskListWidget(QScrollArea):
def __init__(self):
super().__init__()
self.content = QWidget()
self.layout = QVBoxLayout(self.content)
for _ in range(20):
self.layout.addWidget(QLabel("task"))
self.setWidget(self.content)
self.setStyleSheet("background-color: white")
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.tasklist = TaskListWidget()
self.windowLayout = QVBoxLayout()
self.windowLayout.addWidget(self.tasklist)
self.setLayout(self.windowLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
One possible solution is to set the background-color of the QScrollBar to None.
self.setStyleSheet(
"""
QWidget{ background-color: white }
QScrollBar{ background-color: none }
"""
)
I am trying to create a PyQt5 - QLabel with both image and text. I would like to have a text at the bottom of the image. Below is a part of the code
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
l4=QLabel()
l4.setText('delete')
l4.setAlignment(Qt.AlignBottom)
pixmap = QPixmap("/home/moh/Documents/My_GUI/Icons/Delete.png")
l4.setPixmap(pixmap)
l4.setAlignment(Qt.AlignTop)
self.layout = QGridLayout()
self.layout.addWidget(l4, 0, 0)
self.setLayout(self.layout)
self.show()
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
You have to use 2 QLabel in a QVBoxLayout:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
pixmap_label = QLabel(
pixmap=QPixmap("/home/moh/Documents/My_GUI/Icons/Delete.png")
)
text_label = QLabel(text="delete")
lay = QVBoxLayout(self)
lay.addWidget(pixmap_label, alignment=Qt.AlignCenter)
lay.addWidget(text_label, alignment=Qt.AlignCenter)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
If you want to use a circle Qlabel image, use this code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPainterPath, QPainter
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
class Label(QLabel):
def __init__(self, *args, antialiasing=True, **kwargs):
super(Label, self).__init__(*args, **kwargs)
self.Antialiasing = antialiasing
self.setMaximumSize(90, 90)
self.setMinimumSize(90, 90)
self.radius = 45
self.target = QPixmap(self.size())
self.target.fill(Qt.transparent)
p = QPixmap("Image.jpg").scaled(
90, 90, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
painter = QPainter(self.target)
if self.Antialiasing:
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setRenderHint(QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
path = QPainterPath()
path.addRoundedRect(
0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(self.target)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
pixmap_label = Label()
text_label = QLabel(text="delete")
lay = QVBoxLayout(self)
lay.addWidget(pixmap_label, alignment=Qt.AlignCenter)
lay.addWidget(text_label, alignment=Qt.AlignCenter)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
I want my window and it's QGraphicsScene to be transparent which is controlled by QSlider.
I tried looking for some answers here and there, but it's mainly setting background color to 0 :
self.setStyleSheet("background-color:rgba(0, 0, 0, 0);")
or like that :
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
Which does it job, but I would like to make slider which will control level of transparency and I don't see how can I do it with commands above.
Can somebody please give me some advise how to do it ? Thank you
I will attach my test code here below(I want to be able to control transparency of everything , but do not touch slider and button):
from PySide2.QtGui import QBrush, QColor
from PySide2.QtCore import QSize, Qt
from PySide2.QtWidgets import QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QFrame, QSizePolicy, QApplication, QSlider, QPushButton
class MainWindow(QDialog):
def __init__(self):
QDialog.__init__(self)
self.mainLayout = QVBoxLayout()
self.graphicsWidget = MainGraphicsWidget()
self.window = 'transp_test'
self.title = 'transparent UI'
self.size = (1000, 650)
self.create()
def create(self, **kwargs):
self.setWindowTitle(self.title)
self.resize(QSize(*self.size))
self.setLayout(self.mainLayout)
self.mainLayout.addWidget(self.graphicsWidget)
class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
self._scene = QGraphicsScene(backgroundBrush = Qt.gray)
self.setScene(self._scene)
self.transpSlider = QSlider()
self.transpSlider.setRange(0,100)
self.mainButton = QPushButton('I want it to be "Test" button')
self._scene.addWidget(self.mainButton)
self._scene.addWidget(self.transpSlider)
self.transpSlider.move(300, 100)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setBackgroundBrush(QBrush(QColor(30, 30, 30)))
self.setFrameShape(QFrame.NoFrame)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(600, 300, 600, 600)
window.show()
sys.exit(app.exec_())
Here is one way.
class MainWindow(QDialog):
def __init__(self):
QDialog.__init__(self)
# these two lines are needed to get a transparent background in windows
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
# rest of class definition unchanged
class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
# set transparent background color for the widget itself
self.setStyleSheet("background-color: #00000000")
self._scene = QGraphicsScene()
self.setScene(self._scene)
# create of slider and connect to slot for changing opacity.
self.transpSlider = QSlider()
self.transpSlider.setStyleSheet('background-color: #00000000')
self.transpSlider.setRange(0,255)
self.transpSlider.valueChanged.connect(self.set_opacity)
self.transpSlider.setValue(255)
# rest of __init__ unchanged
def set_opacity(self, value):
brush = self.backgroundBrush()
color = brush.color()
color.setAlpha(value)
brush.setColor(color)
self.setBackgroundBrush(color)
Note that I've changed the range of the slider to 0-255 to make changing the opacity from fully opaque to fully transparent easier.
Try it:
#from PySide2.QtGui import QBrush, QColor
#from PySide2.QtCore import QSize, Qt
#from PySide2.QtWidgets import QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QFrame, QSizePolicy, QApplication, QSlider, QPushButton
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QBrush, QColor
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene,
QFrame, QSizePolicy, QApplication, QSlider, QPushButton)
class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
self._scene = QGraphicsScene()
self.setScene(self._scene)
self.transpSlider = QtWidgets.QSlider(
QtCore.Qt.Horizontal,
minimum=10,
maximum=100,
value=100,
valueChanged=self.onValueChanged,
)
self.mainButton = QPushButton('I want it to be "Test" button \n QUIT')
self.mainButton.resize(150, 150)
self.mainButton.clicked.connect(parent.close)
self._scene.addWidget(self.mainButton)
self._scene.addWidget(self.transpSlider)
self.transpSlider.move(300, 100)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
c = QColor(220, 30, 30)
c.setAlphaF(1)
self.setBackgroundBrush(QBrush(c))
self.setFrameShape(QFrame.NoFrame)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
#QtCore.pyqtSlot(int)
def onValueChanged(self, value):
c = QColor(220, 30, 30)
c.setAlphaF(value * 0.01)
self.setBackgroundBrush(QBrush(c))
window.setWindowOpacity(value * 0.03)
self.setStyleSheet("MainGraphicsWidget {{background-color: rgba(0, 215, 55, {});}}".format(value))
class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.setAttribute(Qt.WA_NoSystemBackground, False)
self.setStyleSheet("MainWindow {background-color: rgba(0, 215, 55, 70);}")
self.graphicsWidget = MainGraphicsWidget(self)
self.window = 'transp_test'
self.title = 'transparent UI'
self.size = (1000, 650)
self.setWindowTitle(self.title)
self.resize(QSize(*self.size))
self.mainLayout = QVBoxLayout()
self.setLayout(self.mainLayout)
self.mainLayout.addWidget(self.graphicsWidget)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(600, 100, 600, 600)
window.show()
sys.exit(app.exec_())
I have a QMainWindow with a toolbar, and I'm having troubles with fitting the QPixmap to the window, such that it won't tackle with the toolbar.
I want to display the picture:
And from the code:
import sys
from PyQt5.QtCore import QRect
from PyQt5.QtWidgets import QAction, QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter
class Menu(QMainWindow):
def __init__(self):
super().__init__()
newAct = QAction('New', self)
self.toolbar = self.addToolBar('Remove')
self.toolbar.addAction(newAct)
self.image = QPixmap("background.png")
self.setGeometry(100, 30, 500, 300)
self.resize(self.image.width(), self.image.height())
self.show()
def paintEvent(self, event):
painter = QPainter(self)
rect = QRect(0, 0, self.image.width(), self.image.height())
painter.drawPixmap(rect, self.image)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainMenu = Menu()
sys.exit(app.exec_())
I get:
And as you can see, The picture is on the toolbar as well, and I don't want that.
Another try:
import sys
from PyQt5.QtCore import QRect
from PyQt5.QtWidgets import QAction, QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter
class Menu(QMainWindow):
def __init__(self):
super().__init__()
newAct = QAction('New', self)
self.toolbar = self.addToolBar('Remove')
self.toolbar.addAction(newAct)
self.image = QPixmap("background.png")
self.setGeometry(100, 30, 500, 300)
self.resize(self.image.width(), self.image.height() + self.toolbar.height())
self.show()
def paintEvent(self, event):
painter = QPainter(self)
rect = QRect(0, self.toolbar.height(), self.image.width(), self.image.height() + self.toolbar.height())
painter.drawPixmap(rect, self.image)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainMenu = Menu()
sys.exit(app.exec_())
But I get:
And as you can see, I don't see one of the lines (the blue one).
How can I fix it, so the picture will fit the window excluding the toolbar?
In addition to that, it means I'll have to change all my mouse clicks to move the y-axis. Is there perhaps a way I can set everything such that (x,y)=(0,0) would be at the uppermost left, below the toolbar?
I'm using Python 3.6.5 |Anaconda custom (64-bit) on windows | PyQt version: 5.9.2
Although I can not reproduce the problem, the following solution must work, in it I draw the image in a widget and I set them as centralwidget.
import sys
from PyQt5.QtCore import QRect
from PyQt5.QtWidgets import QAction, QMainWindow, QApplication, QWidget
from PyQt5.QtGui import QPixmap, QPainter
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.image = QPixmap("background.png")
self.setFixedSize(self.image.size())
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(self.rect(), self.image)
class Menu(QMainWindow):
def __init__(self):
super().__init__()
newAct = QAction('New', self)
self.toolbar = self.addToolBar('Remove')
self.toolbar.addAction(newAct)
self.setCentralWidget(Widget())
self.setFixedSize(self.sizeHint())
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainMenu = Menu()
sys.exit(app.exec_())