Himanshu Poddar
Himanshu Poddar

Reputation: 7789

Pyqt5 window full screen does not show border

I create a pyqt window without any title bar and transparent. Also added blue border for my window but when on running the app I can't see any blue border for the window.

from PyQt5.QtWidgets import * 
from PyQt5.QtGui import * 
from PyQt5.QtCore import Qt
import sys
  
class Window(QMainWindow):
    def __init__(self):
        super().__init__()
  
        # this will hide the title bar
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setStyleSheet("border : 3px solid blue;")
        self.setWindowOpacity(0.01)
        # setting  the geometry of window
        self.setGeometry(100, 100, 400, 300)
        self.showFullScreen()
  
  
  
# create pyqt5 app
App = QApplication(sys.argv)
  
# create the instance of our Window
window = Window()
window.show()
# start the app
sys.exit(App.exec())

How can I show the border for my window?

Upvotes: 0

Views: 6497

Answers (2)

musicamante
musicamante

Reputation: 48260

The main problem with the original code is that the whole window gets almost transparent (having an alpha channel value of 0.01); this makes any content of the window as much as transparent, including the border, which becomes practically invisible unless the desktop background (or underlying windows) have enough contrast with the color set.

While the proposed solution works as expected and properly answer the OP question, there's another possibility that doesn't directly involve overriding paintEvent().

The issue of setting the border in the stylesheet and setting the WA_TranslucentBackground attribute is that only explicit opaque parts of the window are visible (child widgets, and any other painting implemented in paintEvent()): the background is automatically ignored, and, normally, the border along with it[1].

A possibility is to add a child widget to the main one and set the border for that widget only using a proper style sheet selector:

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
  
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        borderWidget = QWidget(objectName='borderWidget')
        self.setCentralWidget(borderWidget)

        bgd = self.palette().color(QPalette.Window)
        bgd.setAlphaF(.01)
        self.setStyleSheet('''
            #borderWidget {{
                border: 3px solid blue;
                background: {bgd};
            }}
        '''.format(bgd=bgd.name(bgd.HexArgb)))

        self.showFullScreen()

Note: in the code above (and that below) the background is still visible, but with a very low alpha channel value. If you don't need it, the background value could be ignored, but, for consistency it's better to explicitly declare it: background: transparent;.

That said, consider that QMainWindow has its own private layout, which could add unwanted margins on some systems (and trying to override them might not work at all).
Unless you really need any of the QMainWindow features (menu bar, status bar, tool bars and dock widgets), you should use a basic QWidget instead, which will give you direct control over the layout:

class Window(QWidget):
    def __init__(self):
        super().__init__()
  
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        borderWidget = QWidget(objectName='borderWidget')
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(borderWidget)

        bgd = self.palette().color(QPalette.Window)
        bgd.setAlphaF(.01)
        self.setStyleSheet('''
            #borderWidget {{
                border: 3px solid blue;
                background: {bgd};
            }}
        '''.format(bgd=bgd.name(bgd.HexArgb)))

        self.showFullScreen()

Remember that setting the basic background/border properties of a QWidget stylesheet only works for actual QWidget instances: Qt subclasses implement it on their own way, and if you are going to create the child widget as a custom QWidget subclass the above will NOT work (see this question and this note in the documentation).

[1] This depends on the implementation of the platform and how Qt deals with it through its QPlatformPlugin. For instance, using older versions of xcompmgr I can get the border just by unsetting the WA_NoSystemBackground attribute (which, as the documentation reports, is automatically set when WA_TranslucentBackground is). While properly implementing specific-platform issues would be better, it's almost impossible as their behavior is often inconsistent across different versions, and the combinations between the window and composition managers are almost infinite. The proposed solution should work in all the situations, and with a minimal, possible, overhead.

Upvotes: 1

alec
alec

Reputation: 6112

You can use the TranslucentBackground attribute and paint the border/background in paintEvent.

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
  
        # this will hide the title bar
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        
        # setting  the geometry of window
        self.setGeometry(100, 100, 400, 300)
        self.showFullScreen()

    def paintEvent(self, event):
        qp = QPainter(self)
        qp.setPen(QPen(Qt.blue, 6))
        qp.drawRect(self.rect())
        
        qp.setOpacity(0.01)
        qp.setPen(Qt.NoPen)
        qp.setBrush(self.palette().window())
        qp.drawRect(self.rect())

Upvotes: 2

Related Questions