PyQt5: QWebEngineView Distortion on Resize [duplicate] - python

This question already has an answer here:
PyQt WebEngineView interferes with MainMenu
(1 answer)
Closed 4 years ago.
I have a python application that simply displays given html, with the following code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView
class IFace(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 1000, 500)
self.view = WebView(self)
self.setLayout(QGridLayout(self))
self.layout().addWidget(self.view, 0, 0)
self.layout().setContentsMargins(0, 0, 0, 0)
class WebView(QWebEngineView):
def __init__(self, parent):
super().__init__(parent)
self.setHtml("""<html><head></head><body><center>
<h1>Hi!</h1>
<h1>Hi!</h1>
<h1>Hi!</h1>
</body></html>""")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = IFace()
w.show()
sys.exit(app.exec_())
The html is displayed correctly at first, but resizing the window vertically will cause the displayed webpage to 'stretch' downwards, distorting the text:
Before resizing:
After resizing:
Note how the the text is taller, but not wider. The text also moves downwards as the window is shrunk vertically.
When I place another widget to the left of the QWebEngineView, such as a QLabel, the distortion affects the QLabel as well. If I do not include the QWebEngineView, the QLabel is not distorted.
Why does this happen, and how can I fix it?
Thanks.
UPDATE:
It appears to have something to do with the instantiation of a QWebEngineView that has the window as a parent, as the effect persists when the QWebEngineView is only created not placed, and the effect does not remain when the QWebEngineView is instantiated by QWebEngineView() without the widget as a parent.

This problem occurred due to outdated drivers. I found the solution (also on stackoverflow) here, though it was to a slightly different problem (widgets being hidden beneath the title bar, not distortion of the QWebEngineView).
I updated my Intel(R) HD Graphics driver (forwards, unlike the listed answer in the link) and the issue went away.

Related

Overriding paintEvent for QSpinBox and drawing on top (PyQt5)

I am trying to subclass and draw on top of a QSpinBox by overriding its paintEvent. For example I try to draw an orange rect covering the entire spin box, but it only ends up going on top of some elements, and remains behind others, and moreover I discovered that passing/returning the paintEvent still draws the widget, so I am not sure I understand what is happening here. This is all on Windows btw.
So my precise question is, how do I draw a rect on top of a QSpinBox, such that it paitns on top of everythign else and is part of the subclassed widget's code (not externally painted)?
My second question is how to override the painting such that when the widget is shown it is not drawn at all?
My code:
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QSpinBox, QWidget
from PyQt6.QtGui import QPaintEvent, QBrush, QColor, QPainter
class CustomSpinBox(QSpinBox):
def paintEvent(self, e: QPaintEvent) -> None:
super().paintEvent(e)
painter = QPainter(self)
painter.setBrush(QBrush(QColor('orange'), Qt.BrushStyle.SolidPattern))
painter.drawRect(0, 0, self.width(), self.height())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
window.setGeometry(500, 200, 400, 300)
spin_box = CustomSpinBox(window)
spin_box.move(100, 100)
spin_box.setFixedSize(120, 40)
window.show()
app.exec()
This paints over the spin box arrows, but below the actual value field. I am not sure how and where this layering order is defined, I assume it is something to do with how SubControls of ComplexControls are handled, but I could not really understand how this works exactly based on the information I found.

How PySide6 paintEvent function for a PushButton works?

A long time ago, I wanted to make a logo appear on top of the text in a QPushButton stacked on top of each other, but I couldn't find anyway
I read some stylesheets (couldn't find a single doc to read it all about all styles I can apply to a button)
tried the setLayoutDirection (RightToLeft and LeftToRight were there, but no UpToDown direction)
In my (I wish) last attempt I tried to inherit a QAbstractButton (I didn't find QAbstractPushButton, so I guess QAbstractButton is the answer) and change its paintEvent/paintEngine to draw an image or maybe add a vbox inside it as a layout to draw to components, but I can't find anything in python (specially PySide) which has an example in any possible way close to that. The best thing I found was the analogue clock example which was not very helpful because it was trying to work a QWidget and not a QAbstractButton and I want to keep the feel of a Native looking button.
I like my final product to be something like this.
source of the implemention of that
Python Enaml toolkit supported this feature out of the box (in one of its widgets), and I know it is QT based, so I really wish to know how it is possible?
p.s.: Also, is there a market for qt widgets? e.g.: a plugin system. Because rewriting an android like switch doesn't seem like the correct thing that I should do! even a good tutorial or doc would be appreicated (excluding official doc)
It is easier than you think, you can use QToolButton() like this:
import sys
from PySide6.QtCore import Qt, QSize
from PySide6.QtWidgets import QApplication, QVBoxLayout,QStyle, QWidget,
QToolButton
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
button = QToolButton()
# here you choose the position of the icon and its text
button.setToolButtonStyle(
Qt.ToolButtonStyle.ToolButtonTextUnderIcon)
# here I just use built-in icon by PySide6 for this example
name = 'SP_DialogSaveButton'
pixmapi = getattr(QStyle, name)
icon = self.style().standardIcon(pixmapi)
# here we set text and icon of size 32x32 to the button
button.setIcon(icon)
button.setText("Sample text")
button.setIconSize(QSize(32, 32))
# finally we add our button to the layout
lay = QVBoxLayout(self)
lay.addWidget(button, alignment=Qt.AlignCenter)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

Fonts in PyQt5 not showing up correctly [duplicate]

I am learning how to use PyQt5 and I came across this issue where "my first label" does not complete display on my screen.
Display after running the code:
Code:
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) #enable highdpi scaling
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) #use highdpi icons
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win = QMainWindow()
win.setGeometry(200, 200, 400, 400)
win.setWindowTitle("Tech with Aeijan")
label = QtWidgets.QLabel(win)
label.setText("my first label!")
label.move(50,50)
win.show()
sys.exit(app.exec_())
window()
QLabel adapts its contents based on the (possible) parent layout manager, but you didn't use any, so it doesn't know how to correctly display itself or adapt its size to do that.
The simplest solution is to call label.adjustSize(), which will cause the label to resize itself so that it will be able to display its contents.
That wouldn't be a very good idea, though: you are trying to use a fixed position for a widget (which is normally considered a bad thing to do, for plenty of reasons); the result will be that if the label text is too big and the user resizes the window, the text won't be completely visible as it should be, nor the label would know how to resize or eventually wrap its contents to do ensure that all its text is shown.
The better approach is to use a layout manager, but that is a solution reserved for simpler widgets (like a QWidget or a QDialog); a QMainWindow doesn't work like that, and it requires a central widget to be set to ensure that its contents are correctly displayed and managed.
In your case, you could simply use self.setCentralWidget(label), but that would prevent you to add any other widget to your window.
A "container" widget should be used instead, and that widget would be set as the central one for the main window; then you can set a layout for that widget and add the label to it:
def window():
app = QApplication(sys.argv)
win = QMainWindow()
central = QWidget()
win.setCentralWidget(central)
layout = QVBoxLayout()
central.setLayout(layout)
# alternatively, the above is the same as this:
# layout = QVBoxLayout(central)
label = QtWidgets.QLabel(win)
label.setText("my first label!")
layout.addWidget(label)
# ...

How to make sure the entire label is visible in the window [duplicate]

This question already has an answer here:
PyQt5 label cut off
(1 answer)
Closed 2 years ago.
I have recently started learning pyQt5 and am running into an issue where the entire label does not show up on the window. Is there a quick fix for this? This is the code I have so far and the image of the window is attached as well -> Before button click:
After button click:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
class MyWindow(QMainWindow):
# Create an innstance of QMainWindow
def __init__(self):
super(MyWindow, self).__init__() # parent constructor
self.setGeometry(400, 200, 1000, 750) # sets size of window
self.setWindowTitle("The birds work for the bourgeoisie") # sets title of window
self.initUI()
def initUI(self):
# stuff we want in window
# Step 1: Define an application
# Labels
self.label = QtWidgets.QLabel(self) # where label is located
self.label.setText("birb wants freedom")
self.label.move(400,200)
# Buttons
self.b1 = QtWidgets.QPushButton(self)
self.b1.setText("Free birb")
self.b1.move(410,230)
# Map button to an event
self.b1.clicked.connect(self.clicked)
# Step 2: Create event for button click
def clicked(self):
self.label.setText("FREEDOM AT LAST!")
def window():
app = QApplication(sys.argv) # passing cmmd line args to QtApp
win = MyWindow() # widget shown in the application
win.show() # brings up window
sys.exit(app.exec_()) # winndow shows up nicely and exits properly
window()
The label object has an adjust size method. From https://www.geeksforgeeks.org/pyqt5-how-to-auto-resize-label-adjustsize-qlabel/:
PyQt5 – How to auto resize Label | adjustSize QLabel
Last Updated : 26 Mar, 2020
During the designing of the GUI (Graphical User Interface) application there is a need to display plain text as information where label is used, but sometimes information text could be large or much smaller and it is difficult to use resize() method so have to auto adjust the size of the label according to the text, in order to do so adjustSize() method can be used.
adjustSize() method will change the size of label according to the length of the text, if the length is less it will decrease the length and height of the widget and vice versa.
Syntax : label.adjustSize()
Argument : It takes no argument.

Why does the label not fully display?

I am learning how to use PyQt5 and I came across this issue where "my first label" does not complete display on my screen.
Display after running the code:
Code:
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) #enable highdpi scaling
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) #use highdpi icons
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win = QMainWindow()
win.setGeometry(200, 200, 400, 400)
win.setWindowTitle("Tech with Aeijan")
label = QtWidgets.QLabel(win)
label.setText("my first label!")
label.move(50,50)
win.show()
sys.exit(app.exec_())
window()
QLabel adapts its contents based on the (possible) parent layout manager, but you didn't use any, so it doesn't know how to correctly display itself or adapt its size to do that.
The simplest solution is to call label.adjustSize(), which will cause the label to resize itself so that it will be able to display its contents.
That wouldn't be a very good idea, though: you are trying to use a fixed position for a widget (which is normally considered a bad thing to do, for plenty of reasons); the result will be that if the label text is too big and the user resizes the window, the text won't be completely visible as it should be, nor the label would know how to resize or eventually wrap its contents to do ensure that all its text is shown.
The better approach is to use a layout manager, but that is a solution reserved for simpler widgets (like a QWidget or a QDialog); a QMainWindow doesn't work like that, and it requires a central widget to be set to ensure that its contents are correctly displayed and managed.
In your case, you could simply use self.setCentralWidget(label), but that would prevent you to add any other widget to your window.
A "container" widget should be used instead, and that widget would be set as the central one for the main window; then you can set a layout for that widget and add the label to it:
def window():
app = QApplication(sys.argv)
win = QMainWindow()
central = QWidget()
win.setCentralWidget(central)
layout = QVBoxLayout()
central.setLayout(layout)
# alternatively, the above is the same as this:
# layout = QVBoxLayout(central)
label = QtWidgets.QLabel(win)
label.setText("my first label!")
layout.addWidget(label)
# ...

Categories