How to improve gif quality in PyQt6? - pyqt6

I'm coding in PyQt6 and I'd like to add a loading gif to my application. I've got a good quality 256px gif. However, after adding it to app (I used QLabel and QMovie, and added QMovie to QLabel - and I also changed size of the image to 40px using setScaledSize), the quality is much worse. Without scaling the image quality seems to be a bit better, but honestly I don't want to have 256px gif :D
I tried adding 64px and 40px gifs - but the quality was horrible as well.
My code:
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel
from PyQt6.QtGui import QMovie
from PyQt6.QtCore import QSize
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
layout = QVBoxLayout()
loading = QLabel()
gif = QMovie("loading.gif")
gif.setFormat(b"gif")
gif.setScaledSize(QSize(40,40))
loading.setMovie(gif)
gif.start()
layout.addWidget(loading)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
My gif is from here:
https://icons8.com/preloaders/en/circular
and it's called Position.gif
That's what it looks like in my app.
Any ideas on how to improve it would be great!

Related

Draw transparent image over the screen with Qt

I'm trying to draw an image with a transparent background over the entire screen.
I've done similar with Xlib, but I thought I'd try Qt so my program might work in different environments besides X11.
Before getting committed, I've honestly just searched the internet trying to find a working example but failed.
So I've got an image of coordinates that I want to overlay on the screen.
The image is a PNG with a transparent background.
Here's a picture of what I want to see, my desktop with coordinates:
Here's my PyQt6 code, it draws the image fullscreen but sadly you can't see through it, it has a black background:
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QImage
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtGui import QPainter
class Img(QMainWindow):
def __init__(self, img_path, parent=None):
super().__init__(parent)
self.qimg = QImage(img_path)
self.setStyleSheet('QMainWindow {background:transparent}')
self.setWindowFlags(
Qt.WindowType.WindowStaysOnTopHint |
Qt.WindowType.FramelessWindowHint |
Qt.WindowType.WindowTransparentForInput
)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
def paintEvent(self, qpaint_event):
painter = QPainter(self)
rect = qpaint_event.rect()
painter.drawImage(rect, self.qimg)
self.showFullScreen()
if __name__ == "__main__":
app = QApplication(sys.argv)
img_path = 'coords.png'
window = Img(img_path)
window.show()
sys.exit(app.exec())
Answers don't need to be PyQt6, perhaps PyQt5 or written in Go.
I have tried your code and it works fine, apparently it seems to be a problem of the image, I recommend you to use some kind of external application to erase the transparent parts like this.
Here is a test that works with your code:
If you want to do this automatically I recommend you to use opencv.

QT layout in layout shrinks automatically

I am using Qt Designer to create a main window and I have the following result:
The above opened with PyQt6 using the following code:
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6 import uic
import sys
class UI(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("form.ui", self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = UI()
window.show()
sys.exit(app.exec())
However, in the Qt designer the actual form looks sth like this:
As you can notice the x, y and z text and line edits look weird and dimensionally different from the Qt Designer.
There I have a layout in layout and for some reason the the inner layout shrinks. Is it actually possible to fix the error in Qt Designer without modifying the code?
Thank you for your attention!
Edit 1:
Outer layout Property - Value pairs:
Inner layout Property - Value pairs:

Qt: HBoxLayout - stop MainWindow from resizing to contents

It seems most people are asking how to make their QMainWindow resize to its contents - I have the opposite problem, my MainWindow does resize and I don't know why.
When I set my QLabel to a longer text, my mainwindow suddenly gets bigger, and I can't find out why that happens.
The following example code basically contains:
A QMainWindow
A QWidget as central widget
A QVBoxLayout as a child of that
A LabelBar inside that.
The LabelBar is a QWidget which in turn contains:
A QHBoxLayout
Two QLabels in that.
After a second, a QTimer sets the label to a longer text to demonstrate the issue.
PyQt example code:
from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QLabel, QWidget,
QMainWindow, QVBoxLayout, QSizePolicy)
from PyQt5.QtCore import QTimer
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
cwidget = QWidget(self)
self.setCentralWidget(cwidget)
self.resize(100, 100)
vbox = QVBoxLayout(cwidget)
vbox.addWidget(QWidget())
self.bar = LabelBar(self)
vbox.addWidget(self.bar)
timer = QTimer(self)
timer.timeout.connect(lambda: self.bar.lbl2.setText("a" * 100))
timer.start(1000)
class LabelBar(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
hbox = QHBoxLayout(self)
self.lbl1 = QLabel(text="eggs")
hbox.addWidget(self.lbl1)
self.lbl2 = QLabel(text="spam")
hbox.addWidget(self.lbl2)
if __name__ == '__main__':
app = QApplication([])
main = MainWindow()
main.show()
app.exec_()
Main window grows because it's the goal of using layouts. Layouts make size requirements for their widgets to ensure that all content is displayed correctly. Requirements depend on child widgets. For example, QLabel by default grows horizontally and require space to fit its content. There are many ways to prevent window growing, and the resulting behavior varies:
You can put QLabel in a QScrollArea. When label's text is too long, scrollbars will appear.
You can enable word wrap using self.lbl2.setWordWrap(True). As long as you set text with some spaces, QLabel will display it in several lines, and window will grow vertically a bit instead of growing horizontally.
You can ignore QLabel's size hint using self.lbl2.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed). QLabel's content will not affect its layout or parent widget size. Too large text will be truncated.

Qt:How to create a Window that does not minimize and do not block background GUI

I have a QMainWindow that is a child to another window. When the user clicks anywhere in the parent window, I do not want the child window to be minimized. The child window should lose the focus and user should be able to continue working on the parent window.
This functionality is similar to the find/replace dialogs found in libreoffice/excel/openoffice etc as shown below. We can see that the task-bar shows only the parent application window and the child window is not visible in task-bar.
Are there any signals on QMainWindow that could help me achieve this? Or what would be the best way to do this?
If you open the new window as Dialog and give it a parent, it should stay on top of the parent. Since you're using QMainWindow, you can pass this with the constructor. If you decide to use QDialog, make sure you make it modeless with setModal(False). Otherwise it will block the parent.
A small example:
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
w = QtGui.QWidget()
layout = QtGui.QVBoxLayout(w)
self.button = QtGui.QPushButton('Open Dialog')
self.text = QtGui.QTextEdit()
layout.addWidget(self.button)
layout.addWidget(self.text)
self.setCentralWidget(w)
self.button.clicked.connect(self.openDialog)
def openDialog(self):
self.dialog = QtGui.QMainWindow(self, QtCore.Qt.Dialog)
self.dialog.show()
app = QtGui.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

Qt's opaqueresize property on QSplitter meaning

I didn't find this on the web...
What does this opaqueResize property on QSplitter (see doc) stand for?
Thanks.
I am not really sure what you are asking here. It's all in the docs.
QSplitter resizes its children
dynamically by default. If you would
rather have QSplitter resize the
children only at the end of a resize
operation, call setOpaqueResize(false)
Meaning if you set setOpaqueResize(false) on your splitter, start your application and try to pull the splitter to resize the widgets it holds it will not actually resize widgets until you release the splitter. On the other hand if it is set to true it will try to resize the widgets while you are dragging the splitter handle.
It can be useful to turn this feature off if your custom widgets take long time to draw for example since it would make resizing quite slow.
But to answer your question, property opaqueResize holds whether resizing is opaque or not, i.e. will it resize the widgets while dragging the splitter or not.
Example:
Here is a PyQt example you can try (I had example laying around in Python, but it should work the same in C++):
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self, *args, **kwargs):
super(Example, self).__init__(*args, **kwargs)
top = QtGui.QLabel('test', self)
bottom = QtGui.QPushButton('test', self)
splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
# Try changing from False to True
splitter.setOpaqueResize(False)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox = QtGui.QHBoxLayout(self)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(250, 200, 350, 250)
def main():
app = QtGui.QApplication([])
ex = Example()
ex.show()
app.exec_()
if __name__ == '__main__':
main()
Hope this makes things a bit clearer.

Resources