pyQT4 py3 Can't display image in QFrame background - python

I am trying since a little while to simply display an image in background of a QFrame and simply can't. I can see loads of example on the net but none of them seems to work with my code, and I can't understand why :
import sys, random
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QPalette, QBrush, QPixmap
class MainWin(QtGui.QMainWindow):
def __init__(self):
super(MainWin, self).__init__()
self.initUI()
def initUI(self):
#central widget
self.theboard = Board(self)
self.setCentralWidget(self.theboard)
self.resize(360, 760)
self.setWindowTitle('Name')
self.show()
class Board(QtGui.QFrame):
def __init__(self, parent):
super(Board, self).__init__(parent)
self.initBoard()
def initBoard(self):
print("ddd")
frame = Board
palette = QPalette(self)
palette.setBrush(QPalette.Background,QBrush(QPixmap("ImageTest.jpg")))
frame.setPalette(palette)
def main():
app = QtGui.QApplication([])
mw = MainWin()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
will return:
TypeError: QWidget.setPalette(QPalette): first argument of unbound method must have type 'QWidget'
If I don't pass my QFrame in a variable and do as such :
palette = QPalette(self)
palette.setBrush(QPalette.Background,QBrush(QPixmap("ImageTest.jpg")))
self.setPalette(palette)
No more errors but my background is still blank. Same thing if I just try to fill a color instead of the image.

Unless it's a top-level widget, you need to set the autoFillBackground property to get this to work:
def initBoard(self):
self.setAutoFillBackground(True)
palette = QPalette(self)
palette.setBrush(QPalette.Background, QBrush(QPixmap("ImageTest.jpg")))
self.setPalette(palette)
Alternatively, and more simply, use a style-sheet to set the background image:
def initBoard(self):
self.setStyleSheet('background-image: url("ImageTest.jpg")')

Related

PyQt6: How can I fetch position of mouse pointer from QGraphicsScene and use the variables in the other class?

I'm new to pyqt6 and even to python. As the title indicates, I got stuck with handling mouse position variables. I was expecting to show coodinates of mouse pointer in the QLabel correspond to the mouse movement. I was able to fetch coordinates from mouseMoveEvent in the QGraphicsScene class to getPosition in the Window class. But, that coodinates couldn't be passed to the other function in Window class.
Here is my code so far.
import sys
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QVBoxLayout, QWidget, QLabel
class GraphicsScene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
def mouseMoveEvent(self, event):
self.posX = event.scenePos().x()
Window.getPosition(Window, event.scenePos().x())
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setMouseTracking(True)
scene = GraphicsScene(self)
self.setScene(scene)
class Window(QWidget):
def __init__(self):
super().__init__()
self.Layout = QVBoxLayout()
self.gw = GraphicsView() # an image is meant to be set here.
self.Layout.addWidget(self.gw)
self.label = QLabel("Coordinate: x") # wanna show coorinates here correspond to the mouse movement.
self.Layout.addWidget(self.label)
self.setLayout(self.Layout)
def getPosition(self, posX):
self.label.setText("Coordinate: x" + str(self.posX))
self.repaint()
print(posX)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec())
and got an ERROR like this:
AttributeError: type object 'Window' has no attribute 'label'
It seemas the self in the getPosition function is set to GraphicsScene class after being called (unexpectedly for me). And I have no idea this approach works or not after reading several web documents and asking help for chatGPT. Possibly, I took wrong approach to layout of Widgets.
Any suggestion would be helpful because I'm stuck whole this week with dipression.
Thanks.
Using class Window as parameter to setPosition was wrong, one needs to use an instance of this class. I did this by climbing up the parent() methods and there may be prettier ways to achieve the same. However, it works for now and I did not want to throw in too many changes.
I marked notable changes with comments.
#!/usr/bin/env python3
import sys
from PyQt6 import QtWidgets
class GraphicsScene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
def mouseMoveEvent(self, event):
self.posX = event.scenePos().x()
self.parent().parent().setPosition(event.scenePos().x()) # <-- crawl up the ancestry
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setMouseTracking(True)
scene = GraphicsScene(self)
self.setScene(scene)
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.Layout = QtWidgets.QVBoxLayout()
self.gw = GraphicsView(self) # <-- pass self here
self.Layout.addWidget(self.gw)
self.label = QtWidgets.QLabel("Coordinate: x") # wanna show coorinates here correspond to the mouse movement.
self.Layout.addWidget(self.label)
self.setLayout(self.Layout)
def setPosition(self, posX): # <-- this is a setter, not a getter
self.label.setText("Coordinate: x" + str(posX)) # <-- use argument posX
self.repaint()
print(posX)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec())

How to create multiple QLabels in a gui on PyQt5?

I've created a gui using PyQt5 in PyCharm and I've managed to get one QLabel with an image in it (Picture1.png) showing up, however, when I try to add a second QLabel with a second image (named Shutter1.png) on the same window, it seems to remove both labels and nothing shows up on the gui. I'm not sure where I'm going wrong and any help would be greatly appreciated, I'm a novice! NB I've doublechecked the filepath for both imagePath and imagePath_1 are correct. See below for attached code:
from PyQt5 import uic, QtWidgets, QtGui, QtCore
import sys
import pkg_resources
import functions.initialisation as inits
import functions.Sig2Open as S2O
import functions.Sig2Close as S2C
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
self.gui = uic.loadUi('Shuttergui.ui', self)
# Creates the path of the image
self.imagePath = "C:/........../Picture1.png"
self.label = QtWidgets.QLabel(self.gui)
self.image = QtGui.QImage(self.imagePath)
self.pixmapImage = QtGui.QPixmap.fromImage(self.image)
self.label.setPixmap(self.pixmapImage)
self.label.resize(self.width(), self.height())
self.label.move(60, 170)
self.imagePath = "C:/....../Shutter1.png"
# Create label that holds the image in imagePath
self.label_1 = QtWidgets.QLabel(self.gui)
self.image_1 = QtGui.QImage(self.imagePath)
self.pixmapImage_1 = QtGui.QPixmap.fromImage(self.image_1)
self.label_1.setPixmap(self.pixmapImage_1)
self.label_1.resize(self.width(), self.height())
self.label_1.move(60, 170)
self.gui.showMaximized()
# redirect closeevent func to main self rather than inside gui
self.gui.closeEvent = self.closeEvent
# Initialise shutter functions
inits.ardopenup(self)
inits.ardshutup(self)
self.gui.show()
def closeEvent(self, event):
import time
time.sleep(0.1)
print("main thread quitting")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(pkg_resources.resource_stream(__name__, '/css/darktheme/style.css').read().decode())
window = Ui()
sys.exit(app.exec_())

Background picture in QMainwindow PyQt5

I'm trying to get a background image to my mainwindow but i can't get it to work properly.
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel
from PyQt5.QtGui import QIcon
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSvg import *
from PyQt5.QtWidgets import *
from abc import abstractmethod
class App(QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent=parent)
self.title = 'Title'
self.left = 500
self.top = 500
self.width = 440
self.height = 280
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# ...
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
#view = TableScene(ex)
ex.show()
sys.exit(app.exec_())
I've tried different kinds of methods but none of them works as it should.
I found the following code as a solution from another topic but it just gives me a black background and the rest of the widgets get laggy.
oImage = QImage("table.png")
sImage = oImage.scaled(QSize(440, 280))
palette = QPalette()
palette.setBrush(QPalette.Window, QBrush(sImage))
self.setPalette(palette)
I don't know if the whole window gets laggy or what really happens but the picture below is a screenshot of a part of the window using the code above, and as you can see it gets all black and the slider shows all the previous position it has been on, sort of laggy anyways.
I've also tried the setStyleSheet but I don't know if it's my syntax that's wrong or if it's a faulty way of doing it. Does anyone know a way of doing it correctly?
EDIT
This is my current window:
This is the picture I'm trying to implement as a background to my current window, the picture called "table.png" :
This is a visualization of what I'm trying to do, and this is made in paint since I don't know how to do it correctly:
And this is what I get if i use the code from the other topic:
One of the possible reasons why a black background appears is that QImage is null. And a QImage is null because the image is invalid or because the image path is incorrect. In this case I think it is the second case since the OP uses a relative path that is prone to errors. The solution is to build the absolute path using the script information such as its location:
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class App(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent=parent)
self.initUI()
def initUI(self):
self.setWindowTitle("Title")
self.setGeometry(500, 500, 440, 280)
oImage = QtGui.QImage(os.path.join(CURRENT_DIR, "table.png"))
sImage = oImage.scaled(QtCore.QSize(440, 280))
palette = QtGui.QPalette()
palette.setBrush(QtGui.QPalette.Window, QtGui.QBrush(sImage))
self.setPalette(palette)
pushbutton = QtWidgets.QPushButton("test", self)
pushbutton.move(100, 100)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
Note: The image provided by the OP has extension .jpg but the one indicated by code is .png, maybe "imgur" has changed the extension.
Note: If the window is resized manually, the following behavior will be observed:
So for this there are 2 possible solutions depending on the developer's criteria:
Set a fixed size: self.setFixedSize(440, 280)
Adapt the image to the size of the window:
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class App(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent=parent)
self.initUI()
def initUI(self):
self.setWindowTitle("Title")
self.setGeometry(500, 500, 440, 280)
pushbutton = QtWidgets.QPushButton("test", self)
pushbutton.move(100, 100)
self.oImage = QtGui.QImage(os.path.join(CURRENT_DIR, "table.png"))
# or QPixmap
# self.oPixmap = QtGui.QPixmap(os.path.join(CURRENT_DIR, "table.png"))
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.drawImage(self.rect(), self.oImage)
# or QPixmap
# painter.drawPixmap(self.rect(), self.oPixmap)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
or
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class App(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(App, self).__init__(parent=parent)
self.initUI()
def initUI(self):
self.setWindowTitle("Title")
self.setGeometry(500, 500, 440, 280)
pushbutton = QtWidgets.QPushButton("test", self)
pushbutton.move(100, 100)
self.setStyleSheet(
"""
QMainWindow{
border-image: url(%s) 0 0 0 0 stretch stretch
}
"""
% os.path.join(CURRENT_DIR, "table.png")
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())

PyQt: How to prevent processing multiple resize events when maximizing a window?

I have a QMainWindow containing a child QWidget containing itself a QLabel.
When the window is maximized (e.g. by clicking the maximize icon on the window), the QLabel.resizeEvent() handler is called multiple times (supposedly to follow the progressive enlargement of the window until it takes the full desktop space).
The code in the event handler calls setPixmap() to scale the label pixmap. This is a relatively long operation which slows the process. Code for the label:
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QLabel, QFrame, QGridLayout
from PyQt5.QtGui import QImageReader, QPixmap
class DisplayArea(QLabel):
def __init__(self):
super().__init__()
self.pix_map = None
self.init_ui()
def init_ui(self):
self.setMinimumSize(1, 1)
self.setStyleSheet("border:1px solid black;")
def set_image(self, image):
self.pix_map = QPixmap.fromImage(image)
self.scale_image(self.size())
def scale_image(self, size):
if self.pix_map is None:
return
scaled = self.pix_map.scaled(size, Qt.KeepAspectRatio)
self.setPixmap(scaled)
def resizeEvent(self, e):
self.scale_image(e.size())
super().resizeEvent(e)
Is there a possibility to process the event only once, when the window has reached its final size?
The problem is that the resizeEvent is called many times in the time that the window is maximized, and that same number of times is what you call scale_image. One possible possible is not to update unless a period of time passes. In the following example only resizes for times greater than 100 ms (the time you must calibrate):
from PyQt5 import QtCore, QtGui, QtWidgets
class DisplayArea(QtWidgets.QLabel):
def __init__(self):
super().__init__()
self.pix_map = QtGui.QPixmap()
self._flag = False
self.init_ui()
def init_ui(self):
self.setMinimumSize(1, 1)
self.setStyleSheet("border:1px solid black;")
def set_image(self, image):
self.pix_map = QtGui.QPixmap.fromImage(image)
self.scale_image()
def scale_image(self):
if self.pix_map.isNull():
return
scaled = self.pix_map.scaled(self.size(), QtCore.Qt.KeepAspectRatio)
self.setPixmap(scaled)
def resizeEvent(self, e):
if not self._flag:
self._flag = True
self.scale_image()
QtCore.QTimer.singleShot(100, lambda: setattr(self, "_flag", False))
super().resizeEvent(e)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow()
da = DisplayArea()
da.set_image(QtGui.QImage("logo.png"))
w.setCentralWidget(da)
w.show()
sys.exit(app.exec_())

Draw QFrame around QPushButton PyQt5

I am unable to get a QFrame to completely surround a QPushButton Like a Border. It only frames the top and left side of the button. I was wondering what I'm doing wrong with the frame.
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class main(QWidget):
def __init__(self):
super().__init__()
layout1 = QVBoxLayout()
btn1 = QPushButton("Test")
frame = QFrame(btn1)
frame.setGeometry(btn1.geometry())
frame.setFrameShape(QFrame.Box)
frame.setFrameShadow(QFrame.Plain)
frame.setLineWidth(4)
layout1.addWidget(btn1)
self.setLayout(layout1)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = main()
window.show()
sys.exit(app.exec_())
The problem is caused because the QFrame does not change the size, instead QPushButton does. In my solution I have resized every time the size is changed in the QPushButton
class FrameButton(QPushButton):
def __init__(self, *args, **kwargs):
QPushButton.__init__(self, *args, **kwargs)
self.frame = QFrame(self)
self.frame.setFrameShape(QFrame.Box)
self.frame.setFrameShadow(QFrame.Plain)
self.frame.setLineWidth(4)
def resizeEvent(self, event):
self.frame.resize(self.size())
QWidget.resizeEvent(self, event)
class main(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout(self)
layout.addWidget(FrameButton("Test"))

Categories

Resources