2

I have a simple flow: user clicks a button, a QDialog popup appears and I wish to render a MenuBar and an image below the MenuBar (the rendering happens during the paintEvent).

import sys

from PyQt5 import QtGui
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QDialog, QMenuBar, QAction, QHBoxLayout


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

        self.initUI()

    def initUI(self):
        self.button = QPushButton()
        self.button.setText("Click")
        self.button.setMaximumHeight(100)
        self.button.setMaximumWidth(100)
        self.button.clicked.connect(self.clicked)

        self.layout().addWidget(self.button)

        self.show()

    def clicked(self):
        self.something = SecondExample()
        self.something.exec()

class SecondExample(QDialog):
    def __init__(self):
        super().__init__()
        self.installEventFilter(self)

        layout = QHBoxLayout()

        toolbar = QMenuBar()
        toolbar.addAction(QAction("Edit", toolbar))
        toolbar.addAction(QAction("Polygon", toolbar))
        toolbar.addAction(QAction("Rectangle", toolbar))

        layout.setMenuBar(toolbar)

        self.setLayout(layout)

        self.pixmap = QPixmap(r"C:\Users\kjankosk\Desktop\Panasonic-OLED-TV-FZ950-Lifestyle.jpg")
        self.resize(self.pixmap.width(), self.pixmap.height())


    def paintEvent(self, event):
        super().paintEvent(event)

        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)

        painter.drawPixmap(self.rect(), self.pixmap)



if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

Here is a reproducible example of what I have so far (edit the image path), however part of the image appears behind the menu bar. How can I fix this issue? I think the main problem is with the rect() call as it seems to be using the whole window, but I was hoping that the menu bar would be "outside the window".

Kristijan
  • 195
  • 10

2 Answers2

2

A possible solution is to give an offset like the one indicated by S.Nick but as you saw a disadvantage first is to calculate the offset that is dependent on the style and OS. So another possible solution is to create another widget where the image is displayed and add it to the layout:

# ...
class Widget(QWidget):
    def __init__(self):
        super().__init__()

        self.pixmap = QPixmap(
            r"C:\Users\kjankosk\Desktop\Panasonic-OLED-TV-FZ950-Lifestyle.jpg"
        )

    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
        painter.drawPixmap(self.rect(), self.pixmap)

    def sizeHint(self):
        return self.pixmap.size()


class SecondExample(QDialog):
    def __init__(self):
        super().__init__()

        layout = QHBoxLayout(self)

        toolbar = QMenuBar()
        toolbar.addAction(QAction("Edit", toolbar))
        toolbar.addAction(QAction("Polygon", toolbar))
        toolbar.addAction(QAction("Rectangle", toolbar))

        layout.setMenuBar(toolbar)

        widget = Widget()
        layout.addWidget(widget)
# ...
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • This is what I tried doing but It wouldn't resize it self for some reason, works with the sizeHint. Thanks. – Kristijan Jun 20 '19 at 07:37
  • I just tried with a larger picture, and it still seems like it's squeezing the height by an offset depending on the size of the toolbar. – Kristijan Jun 20 '19 at 12:41
  • @Kristijan What size of image do you have? if you could share the image to analyze where the problem is and thus improve my solution would be great – eyllanesc Jun 20 '19 at 12:53
  • The image I tried with is 892 x 852 px - I can send it to you if needed – Kristijan Jun 20 '19 at 12:57
  • @Kristijan You could also share a screenshot of your window to better understand your problem – eyllanesc Jun 20 '19 at 13:03
  • https://imgur.com/a/XYmX1pg here is a side by side comparison (left is the solution) – Kristijan Jun 20 '19 at 13:06
0

Try it:

import sys
from PyQt5 import QtGui
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (QMainWindow, QApplication, QPushButton, QDialog, 
                             QMenuBar, QAction, QHBoxLayout, QWidget, QGridLayout)

class SecondExample(QDialog):
    def __init__(self):
        super().__init__()
        self.installEventFilter(self)

        toolbar = QMenuBar()
        toolbar.addAction(QAction("Edit", toolbar))
        toolbar.addAction(QAction("Polygon", toolbar))
        toolbar.addAction(QAction("Rectangle", toolbar))

        layout = QHBoxLayout()
        layout.setMenuBar(toolbar)
        self.setLayout(layout)

        self.pixmap = QPixmap("D:/_Qt/__Qt/img/max1.jpg")      # py-qt.png
        self.resize(self.pixmap.width(), self.pixmap.height())

    def paintEvent(self, event):
        super().paintEvent(event)

        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)

#        painter.drawPixmap(self.rect(), self.pixmap)
        rect = self.rect().x(), self.rect().y()+20, self.rect().width(), self.rect().height()-20 # +++
        painter.drawPixmap(*rect, self.pixmap)                                                   # +++


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

        self.initUI()

    def initUI(self):
        self.button = QPushButton(self)
        self.button.setText("Click")
        self.button.setMaximumHeight(100)
        self.button.setMaximumWidth(100)
        self.button.clicked.connect(self.clicked)

        centralWidget = QWidget()
        self.setCentralWidget(centralWidget)
        layout = QGridLayout(centralWidget)
#        self.layout().addWidget(self.button)
        layout.addWidget(self.button)

    def clicked(self):
        self.something = SecondExample()
        self.something.show()            # exec()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

enter image description here

S. Nick
  • 12,879
  • 8
  • 25
  • 33
  • Well yeah, this is the obvious solution but this means that the rect() is now shifted for the fixed amount - there probably is a way to make the menubar not part of the rect(). A potential issue is that I would have to also shift the coordinates of the mouse position let's say if I were to catch it as It would not give the correct positions due to the menu bar being there. – Kristijan Jun 19 '19 at 14:47