PyQt resize QMovie with proper anti-aliasing - python

I created a QLabel and set it's movie to a QMovie object with an animated gif. Then in the resizeEvent of my app I resize and move the label, so that it is centered/fit to the layout. This works fine but the movie has a lot of fine lines which get totally garbled in the resize operation, it seems there is no anti-aliasing. So either I am using the wrong resize method, or I need to set anti-aliasing somewhere right? There is nothing in the QMovie or QLabel documentation to suggest how to do this. I did read that the QMovie is inherited from a QImageReader, though that too has no property for anti-aliasing that I could find.
EDIT
I did somewhat get this to work, but it's still not quite right. I found that QMovie has a setScaledSize method which actually scales the underlying QImageViewer. Then I just have the label adjust to it's contents, namely the movie. Using the following code I am able to resize the movie with proper anti-aliasing, however it is quite "jumpy" and "flickery" during resize so obviously I'm not doing this quite "right". Also it somehow loses it's aspect ratio sometimes. Still looking for the correct way to do this... Maybe a QLabel is the wrong way to go?
Here's a working example
import sys
from PyQt4 import QtGui
class MovieTest(QtGui.QDialog):
def __init__(self):
super(MovieTest, self).__init__()
layout = QtGui.QVBoxLayout()
self.setLayout(layout)
self.loading_lbl = QtGui.QLabel()
self.loading_lbl.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicyIgnored)
self.loading_lbl.setScaledContents(True)
layout.addWidget(self.loading_lbl)
loading_movie = QtGui.QMovie("loading-radial_loop.gif") # some gif in here
self.loading_lbl.setMovie(loading_movie)
loading_movie.start()
self.setGeometry(50,50,100,100)
self.setMinimumSize(10,10)
def resizeEvent(self, event):
rect = self.geometry()
size = min(rect.width(), rect.height())
movie = self.loading_lbl.movie()
movie.setScaledSize(QtCore.QSize(size, size))
self.loading_lbl.adjustSize()
def main():
app = QtGui.QApplication(sys.argv)
ex = MovieTest()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Ok I have this figured out now, with just a few tweaks to the code in my edited post. The secret is in keeping the label the full size of it's parent rect (in this case the size of the whole layout) and then scaling the movie within the label. Essentially you are internally scaling the movie, instead of having it automatically fill the contents of the label. From what I can tell this changes around the order of operations a bit and allows the movie to scale itself on render, instead of rendering the frame and then scaling it to the label size.
Working code:
import sys
from PyQt4 import QtGui, QtCore
class MovieTest(QtGui.QDialog):
def __init__(self):
super(MovieTest, self).__init__()
layout = QtGui.QVBoxLayout()
self.setLayout(layout)
self.loading_lbl = QtGui.QLabel()
self.loading_lbl.setStyleSheet('border: 1px solid red') # just for illustration
self.loading_lbl.setAlignment(QtCore.Qt.AlignCenter)
layout.addWidget(self.loading_lbl)
loading_movie = QtGui.QMovie("loading-radial_loop.gif")
self.loading_lbl.setMovie(loading_movie)
loading_movie.start()
self.setGeometry(50,50,100,100)
self.setMinimumSize(10,10)
def resizeEvent(self, event):
rect = self.geometry()
size = QtCore.QSize(min(rect.width(), rect.height()), min(rect.width(), rect.height()))
movie = self.loading_lbl.movie()
movie.setScaledSize(size)
def main():
app = QtGui.QApplication(sys.argv)
ex = MovieTest()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Related

Widgets are not displayed

I'm currently doing a tutorial on how to create GUI apps from a book called "Modern PyQt" by Joshua Willman and I'm stuck right out of the gate:
I've copy pasted a basic code snippet from the book and tried to tweak it bit by bit instead of reading a bunch of text without any practical trial and error. I can display a window and adjust it's size and properties, but when I try to attach other widgets to the main window, they just don't show up.
Here's what I've got so far:
# First practical example from the book: Pomodoro time manager
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
class Pomodoro(QWidget):
def __init__(self): # Create default constructor
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Initialize the window and display its contents to the screen."""
self.setGeometry(int((SCREEN_WIDTH-WINDOW_WIDTH)/2),int((SCREEN_HEIGHT-WINDOW_HEIGHT)/2),WINDOW_WIDTH,WINDOW_HEIGHT) # x,y,w,h
self.setWindowTitle('Bortism')
# self.setWindowIcon(QIcon("Borticon.png"))
self.button1 = QPushButton()
self.button1.setText('Button')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
WINDOW_WIDTH, WINDOW_HEIGHT = 1000,600
SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT = app.desktop().screenGeometry().getRect()
window = Pomodoro()
sys.exit(app.exec_())
For a widget to be shown as part of another then the requirement is that the first is the child of the second. This can be done by passing the parent or by using a layout (which is also passed to it by the parent). So in your case you must change to:
self.button1 = QPushButton(self)

Can't set transparency of QWindow after shown once while opaque

I have a window I'm trying to make transparent after being shown once while opaque. However, doesn't go transparent even if I hide and show again. This is what I get:
But I want it like this: (transparent against background)
If I run WA_TranslucentBackground first, before .show() it creates a nice transparent button as expected.
Here is an example code which shows a floating button when you run it
import sys
from PySide2 import QtCore, QtWidgets, QtGui
class TransparentWindow(QtWidgets.QMainWindow):
def __init__(self):
super(TransparentWindow, self).__init__()
self.setCentralWidget(QtWidgets.QWidget(self))
self.mainLayout = QtWidgets.QVBoxLayout()
self.centralWidget().setLayout(self.mainLayout)
self.mainLayout.addWidget(QtWidgets.QPushButton("Hello World", parent=self))
self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint)
self.show() # If I move this under '.setAttribute()' it works
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
demo = TransparentWindow()
sys.exit(app.exec_())
I've tried hiding and reshowing, 'setAutoFillBackground()' and 'WA_NoSystemBackground' attribute, but I cant seem to get it to work. Anybody have any idea how to set the transparency after it has been shown as opaque?
Using versions QtCore: 5.9.6, Pyside2: 5.9.0a1.dev1528389443

How to resize a QColorDialog

Is it possible to resize a QColorDialog? I have been unable to get the window to resize appropriately. After the dialog is shown, it reverts to the default size.
An example:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
push_Button = QPushButton()
layout.addWidget(push_Button)
push_Button.clicked.connect(self.button)
self.setLayout(layout)
def button(self):
color = QColorDialog(self)
color.resize(100,100)
print(color.size()) #Prints 100, 100
color.show()
print(color.size()) #Prints 551, 431
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
The QColorDialog has a fixed size, because it contains several custom widgets which aren't designed to be resizable. It is possble to override these constraints and allow for manual resizing like this:
color = QColorDialog(self)
color.setSizeGripEnabled(True)
color.layout().setSizeConstraint(QLayout.SetNoConstraint)
color.show()
However, as you will see, the layout quickly becomes messed up with even a little bit of resizing. I also found that beyond a certain point, the dialog will actually crash due to floating point exceptions. So I think you will either have to accept it as it is, or perhaps write your own color dialog.

How to change the background color in PyQt4

I am really new to PyQt4(just learned what it is two days ago) and I know that this question probably has a really easy answer but I can't find it anywhere. I am trying to change the background color of the window to black. I have this code so far.
import sys
from PyQt4 import QtGui
class Display(QtGui.QMainWindow):
def __init__(self):
super(Display, self).__init__()
self.ShowFullScreen()
self.show()
if name == '__main__':
app = QtGui.QApplication(sys.argv)
GUI = Display()
sys.exit(app.exec())
When I run this I get a white window. Is there a method I could run to change it to black?
You can set styleSheet for window.
self.showFullScreen()
self.setStyleSheet("background-color: black;")
Reference
Stylesheet Reference

PyQt: LineEdit widget's placement inside of FormLayout

A QtGui.QLineEdit line_edit widget is placed inside of QtGui.QFormLayout Form layout using .addRow() method.
my_formLayout.addRow(my_label, my_lineEdit)
To make a line_edit widget to stick to a dialog window's edges (so it re-sizes with the dialog) tried using sizePolicy:
sizePolicy = my_lineEdit.sizePolicy()
sizePolicy.setHorizontalStretch(1)
my_lineEdit.setSizePolicy( sizePolicy )
There are no errors. But the line_edit widget still doesn't stick to the edges of the dialog... What could be wrong?
You shouldn't need to do anything.
This simple example resizes as necessary:
from PyQt4 import QtGui
class Dialog(QtGui.QDialog):
def __init__(self):
super(Dialog, self).__init__()
form = QtGui.QFormLayout(self)
label = QtGui.QLabel('Label', self)
edit = QtGui.QLineEdit(self)
form.addRow(label, edit)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Dialog()
window.setGeometry(500, 300, 300, 50)
window.show()
sys.exit(app.exec_())
UPDATE:
Okay, it seems the behaviour of QFormaLayout is platform-dependent. To quote from the docs:
Style based on the Mac OS X Aqua guidelines. Labels are right-aligned, the fields don't grow beyond their size hint, and the form is horizontally centered.
However, there is a setFieldGrowthPolicy method, which could be used to over-ride the default behaviour on Mac OSX. So try:
my_formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.ExpandingFieldsGrow)
or:
my_formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
Try this: sizePolicy.setHorizontalPolicy(QSizePolicy.Expanding)

Categories