Skip to content

[PyQt5] 實現圓角邊框視窗的界面

Last Updated on 2021-08-23 by Clay

不知道大家是否看膩了一成不變的直角邊框界面?至少,我確定我對於直角邊框的界面感到沒那麼有趣了,看看 Android 的 App 圖示、iOS 的種種邊框,是不是都有著好看的圓角邊框呢?

在 PyQt5 這個框架中,我們當然也可以製作出同樣好看的圓角邊框,以下來看個簡單的範例程式碼。


使用 setStyleSheet() 調整圓角

首先我得澄清,我不確定有沒有更好的實現方法,所以這個方法僅僅只是提供參考。

# coding: utf-8
import sys
from PyQt5.Qt import Qt
from PyQt5.QtWidgets import *


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

        # Window size
        self.WIDTH = 300
        self.HEIGHT = 300
        self.resize(self.WIDTH, self.HEIGHT)

        # Widget
        self.centralwidget = QWidget(self)
        self.centralwidget.resize(self.WIDTH, self.HEIGHT)

        # Initial
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowOpacity(0.6)

        radius = 30
        self.centralwidget.setStyleSheet(
            """
            background:rgb(255, 255, 255);
            border-top-left-radius:{0}px;
            border-bottom-left-radius:{0}px;
            border-top-right-radius:{0}px;
            border-bottom-right-radius:{0}px;
            """.format(radius)
        )


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())



Output:

原理非常單純:我不清楚如何漂亮地改動真正的 MainWindow 元件,於是我建立了一個覆蓋在 MainWindow 上的 Widget 元件,然後將 MainWindow 隱藏,就只剩下單純的 Widget 了。

接著再使用 setStyleSheet() 來寫下要將元件改動樣式的 QSS 語法,也就是更改 radius 參數,就能調整 Widget 的形狀。

為什麼不能直接改 MainWindow 元件呢?我們來直接跑一次改 MainWindow 的狀況。

# coding: utf-8
import sys
from PyQt5.Qt import Qt
from PyQt5.QtWidgets import *


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

        # Window size
        self.WIDTH = 300
        self.HEIGHT = 300
        self.resize(self.WIDTH, self.HEIGHT)

        # Initial
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setWindowOpacity(0.6)

        radius = 30
        self.setStyleSheet(
            """
            background:rgb(255, 255, 255);
            
            border-top:1px solid black;
            border-bottom:1px solid black;
            border-left:1px solid black;
            border-right:1px solid black;
             
            border-top-left-radius:{0}px;
            border-bottom-left-radius:{0}px;
            border-top-right-radius:{0}px;
            border-bottom-right-radius:{0}px;
            """.format(radius)
        )


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())



Output:

並不是沒有改動到(為了更好地呈現效果,我將圓角設定為黑色),但我們可以發現,這樣邊框仍然存在,反而看起來有些醜。不得已,只好使用 Widget 元件來當作界面。

順帶一提,如果想要使用徹底就是個圓形的界面,也可以將 radius 參數調整為 150。(這是因為我尺寸是 300 x 300 的緣故,比如說你的尺寸如果是 600 x 600,想要是圓形就必須要調整 radius 參數為 300

圓形的界面就誕生了 XDDD


拖曳界面

想必寫習慣 PyQt5 的大家應該都有注意到,為了美觀,我把標題欄位隱藏掉了。那麼,這下子我們不就沒辦法拖曳界面和關閉程式了嗎?

這裡分享一下我過去寫過的兩篇文章:

第一篇文章紀錄了該如何在隱藏標題欄位後拖曳界面。

第二篇文章則是介紹了如何設置右鍵打開選單 —— 這樣就可以設定離開鍵了。

完整程式碼如下:

# coding: utf-8
import sys
from PyQt5.Qt import Qt
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QCursor


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

        # Window size
        self.WIDTH = 300
        self.HEIGHT = 300
        self.resize(self.WIDTH, self.HEIGHT)

        # Widget
        self.centralwidget = QWidget(self)
        self.centralwidget.resize(self.WIDTH, self.HEIGHT)

        # Menu
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.right_menu)

        # Initial
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowOpacity(0.6)

        radius = 150
        self.centralwidget.setStyleSheet(
            """
            background:rgb(255, 255, 255);
            border-top-left-radius:{0}px;
            border-bottom-left-radius:{0}px;
            border-top-right-radius:{0}px;
            border-bottom-right-radius:{0}px;
            """.format(radius)
        )

    def right_menu(self, pos):
        menu = QMenu()

        # Add menu options
        exit_option = menu.addAction('Exit')

        # Menu option events
        exit_option.triggered.connect(lambda: exit())

        # Position
        menu.exec_(self.mapToGlobal(pos))

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.moveFlag = True
            self.movePosition = event.globalPos() - self.pos()
            self.setCursor(QCursor(Qt.OpenHandCursor))
            event.accept()

    def mouseMoveEvent(self, event):
        if Qt.LeftButton and self.moveFlag:
            self.move(event.globalPos() - self.movePosition)
            event.accept()

    def mouseReleaseEvent(self, QMouseEvent):
        self.moveFlag = False
        self.setCursor(Qt.CrossCursor)


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())



Output:


References

Leave a Reply