How to Add a Background Image to the Qmainwindow

How to add a background image to a QWidget without using QMainWindow?

Out of curiosity, I tried on my side with my own MCVE.

C++ source testQWidgetBackgroundImage.cc:

// Qt header:
#include <QtWidgets>

// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QWidget qWinMain;
qWinMain.setWindowTitle("Test Background Image");
qWinMain.resize(640, 480);
qWinMain.setObjectName("Widget");
qWinMain.setStyleSheet("#Widget { background-image: url(cat.jpg); }");
qWinMain.show();
// runtime loop
return app.exec();
}

Build script CMakeLists.txt:

project(QWidgetBackgroundImage)

cmake_minimum_required(VERSION 3.10.0)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Qt5Widgets CONFIG REQUIRED)

include_directories("${CMAKE_SOURCE_DIR}")

add_executable(testQWidgetBackgroundImage testQWidgetBackgroundImage.cc)

target_link_libraries(testQWidgetBackgroundImage Qt5::Widgets)

Output:

snapshot of testQWidgetBackgroundImage.exe

So, I was able to show a plain QWidget with a background image set by a style sheet, at least, in Windows 10 with VS 2017 and Qt 5.13.

This is in accordance with what is documented in Qt Style Sheets Reference – background:

Shorthand notation for setting the background. Equivalent to specifying background-color, background-image, background-repeat, and/or background-position.

This property is supported by QAbstractItemView subclasses, QAbstractSpinBox subclasses, QCheckBox, QComboBox, QDialog, QFrame, QGroupBox, QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QRadioButton, QSplitter, QTextEdit, QToolTip, and plain QWidgets.

Note:

I must admit that I don't have any experience concerning the use of Qt resources. Hence, I provided the URL just as url(cat.jpg) which results in the attempt to load from a file in the local current working directory (with success as seen in the snapshot above). The prefixing with : (e.g. url(:/cat.jpg)) would address an entry in the Qt resources instead.

Further readings: The Qt Resource System


After having read the doc. in the above link, I noticed that it's not that complicated to use and modified the above MCVE a bit:

C++ source file testQWidgetBackgroundImage.cc

// Qt header:
#include <QtWidgets>

// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QWidget qWinMain;
qWinMain.setWindowTitle("Test Background Image");
qWinMain.resize(640, 480);
qWinMain.setObjectName("Widget");
qWinMain.setStyleSheet("#Widget { background-image: url(:/cat.jpg); }");
qWinMain.show();
// runtime loop
return app.exec();
}

Effectively, the only change was url(cat.jpg)url(:/cat.jpg).

Qt resource file testQWidgetBackgroundImage.qrc:

<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>cat.jpg</file>
</qresource>
</RCC>

Qt project file testQWidgetBackgroundImage.pro:

SOURCES = testQWidgetBackgroundImage.cc

RESOURCES = testQWidgetBackgroundImage.qrc

QT += widgets

Built and tested in cygwin64:

$ qmake-qt5 testQWidgetBackgroundImage.pro

$ make && ./testQWidgetBackgroundImage
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQWidgetBackgroundImage.o testQWidgetBackgroundImage.cc
/usr/lib/qt5/bin/rcc -name testQWidgetBackgroundImage testQWidgetBackgroundImage.qrc -o qrc_testQWidgetBackgroundImage.cpp
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o qrc_testQWidgetBackgroundImage.o qrc_testQWidgetBackgroundImage.cpp
g++ -o testQWidgetBackgroundImage.exe testQWidgetBackgroundImage.o qrc_testQWidgetBackgroundImage.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4

Output:

snapshot of ./testQWidgetBackgroundImage

Background picture in QMainwindow PyQt5

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_())

enter image description here


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:

enter image description here

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_())

how to add a background image to a main window without affecting the widgets in Pyqt5

Try it:

from PyQt5.QtWidgets import *

class MainWindow(QMainWindow):
def __init__(self):
super().__init__()

self.centralwidget = QWidget()
self.setCentralWidget(self.centralwidget)

self.pushButton1 = QPushButton("Button 1", self.centralwidget)
self.pushButton2 = QPushButton("Button 2", self.centralwidget)

lay = QHBoxLayout(self.centralwidget)
lay.addWidget(self.pushButton1)
lay.addWidget(self.pushButton2)


stylesheet = """
MainWindow {
background-image: url("D:/_Qt/img/cat.jpg");
background-repeat: no-repeat;
background-position: center;
}
"""

if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
app.setStyleSheet(stylesheet) # <---
window = MainWindow()
window.resize(640, 640)
window.show()
sys.exit(app.exec_())

enter image description here


from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
def setupUi(self, MainWindow):

MainWindow.setObjectName("MainWindow")
MainWindow.resize(400, 300)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")

self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralWidget)

self.horizontalLayout_2.setContentsMargins(11, 11, 11, 11)
self.horizontalLayout_2.setSpacing(6)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSpacing(6)
self.horizontalLayout.setObjectName("horizontalLayout")
self.start_button = QtWidgets.QPushButton(self.centralWidget)
self.start_button.setObjectName("start_button")

self.horizontalLayout.addWidget(self.start_button)
self.stop_button = QtWidgets.QPushButton(self.centralWidget)
self.stop_button.setObjectName("stop_button")
self.horizontalLayout.addWidget(self.stop_button)
self.horizontalLayout_2.addLayout(self.horizontalLayout)
MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 26))
self.menuBar.setObjectName("menuBar")
MainWindow.setMenuBar(self.menuBar)
self.mainToolBar = QtWidgets.QToolBar(MainWindow)
self.mainToolBar.setObjectName("mainToolBar")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
self.statusBar = QtWidgets.QStatusBar(MainWindow)
self.statusBar.setObjectName("statusBar")
MainWindow.setStatusBar(self.statusBar)

self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.start_button.setText(_translate("MainWindow", "Start"))
self.stop_button.setText(_translate("MainWindow", "Stop"))


class MyWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()

self.setupUi(self)


stylesheet = """
QMainWindow {
background-image: url("D:/_Qt/img/cat.jpg");
background-repeat: no-repeat;
background-position: center;
}
"""

if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(stylesheet)

w = MyWindow()
# MainWindow = QtWidgets.QMainWindow()
# ui = Ui_MainWindow()
# ui.setupUi(MainWindow)
# MainWindow.show()
w.show()

sys.exit(app.exec_())

How to change the background image of a QMainWindow central widget?

To change the background image of a QWidget you should override the paintEvent method, in your case yours in a QStackedWidget, we create a class that inherits from this:

class StackedWidget(QStackedWidget):
def __init__(self, parent=None):
QStackedWidget.__init__(self, parent=parent)

def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(self.rect(), QPixmap("ninja.png"))
QStackedWidget.paintEvent(self, event)

And then you change:

self.central_widget = QStackedWidget()

to:

self.central_widget = StackedWidget()

Example:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

class StackedWidget(QStackedWidget):
def __init__(self, parent=None):
QStackedWidget.__init__(self, parent=parent)

def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(self.rect(), QPixmap("image.png"))
QStackedWidget.paintEvent(self, event)

class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent)
self.setCentralWidget(StackedWidget())

if __name__ == '__main__':

app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Screenshot:

enter image description here

The case of QStackedWidget is a special case since this is not shown, this serves to show other widgets, to those widgets you must change the background image.

From your code, the first widget they attach is a QMdiArea, this is also a special case since it has a viewport and this should be changed.

class MdiArea(QMdiArea):
def __init__(self, parent=None):
QMdiArea.__init__(self, parent=parent)

def paintEvent(self, event):
QMdiArea.paintEvent(self, event)
painter = QPainter(self.viewport())
painter.drawPixmap(self.rect(), QPixmap("image.png"))

In your code change:

self.mdi = QMdiArea()

to:

self.mdi = MdiArea()

Screenshots:

enter image description here

enter image description here

How to put a widget on a background image in QMainWindow in Pyqt5?

The issue is not related to the background: the LED widgets are there, the problem is that widgets added to a parent that is already shown (and without using a layout manager) does not make them visible, and they must be explicitly shown by calling show() or setVisible(True).

You can see the difference if you remove the self.show() line after setting the palette (but leaving the mainWin.show() at the end): in that case, the leds become automatically visible.

The solution is to either show the child widgets explicitly, or call show()/setVisible(True) on the parent after adding them.

How do I set a background image to mainwindow?

Try to add What you have tried so far,with out that we cant help.
Try the below one

setStyleSheet("MainWindow {background-image:url(:/files/MainPic/Technology-Banner1.jpg)}");

How Could I Set The Main Window Background To A Base64 Image In PyQt5 [duplicate]

There is no direct way to do this, so you need to implement the paint event of the main window, and ensure that its central widget does not paint its background (by setting the background color in the stylesheet or using autoFillBackground()).

The following will render the pixmap at the center:

class Win(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setCentralWidget(QtWidgets.QWidget())
self.bkgnd = QtGui.QPixmap # base64 data ...

def paintEvent(self, event):
qp = QtGui.QPainter(self)
pmRect = self.bkgnd.rect()
pmRect.moveCenter(self.centralWidget().geometry().center())
qp.drawPixmap(pmRect, self.bkgnd)

You can also get tiling:

    def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.fillRect(self.centralWidget().geometry(), QtGui.QBrush(self.bkgnd))

Or stretch the contents of the image:

    def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.drawPixmap(self.centralWidget().geometry(), self.bkgnd)

Or scale by keeping the aspect ratio:

    def paintEvent(self, event):
qp = QtGui.QPainter(self)
rect = self.centralWidget().geometry()
scaled = self.bkgnd.scaled(rect.size(), QtCore.Qt.KeepAspectRatio)
pmRect = scaled.rect()
pmRect.moveCenter(rect.center())
qp.drawPixmap(pmRect, scaled)

In all the situations above, you can also try to use the full rectangle of the main window (self.rect()) instead of that of the central widget, if you want to set a background that also renders under menus, toolbars, etc, but I would not suggest you to do so, as it would probably make those elements difficult to see, and it's also possible that some styles would paint their background in any case.

Qt Creator and main window background image

While editing your main window form find styleSheet property, and put something like this:

background: url(:/path/to-your-resource.png)


Related Topics



Leave a reply



Submit