16

How could I customize the Title Bar (including: close, maximize, minimize buttons, title) and the Frame of desktop application written in PyQt so that it looks like the below image?. I need a way to specify the colors I want to use for title bar elements (buttons, text title and background-color of bar and buttons). Nokia Ovi Suite

the code which I need to change its window:

import sys
from PyQt5 import QtCore, uic
from PyQt5.QtWidgets import QApplication, QDialog

class MainWindow(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)

        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)


        self.resize(500, 600)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec_())

Is there any way to do that? I appreciate any suggestion and idea to doing this.

iraj jelodari
  • 3,118
  • 3
  • 35
  • 45

2 Answers2

32
#########################################################
## customize Title bar
## dotpy.ir
## iraj.jelo@gmail.com
#########################################################
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt

class TitleBar(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setWindowFlags(Qt.FramelessWindowHint);
        css = """
        QWidget{
            Background: #AA00AA;
            color:white;
            font:12px bold;
            font-weight:bold;
            border-radius: 1px;
            height: 11px;
        }
        QDialog{
            Background-image:url('img/titlebar bg.png');
            font-size:12px;
            color: black;

        }
        QToolButton{
            Background:#AA00AA;
            font-size:11px;
        }
        QToolButton:hover{
            Background: #FF00FF;
            font-size:11px;
        }
        """
        self.setAutoFillBackground(True)
        self.setBackgroundRole(QtGui.QPalette.Highlight)
        self.setStyleSheet(css) 
        self.minimize=QtGui.QToolButton(self);
        self.minimize.setIcon(QtGui.QIcon('img/min.png'));
        self.maximize=QtGui.QToolButton(self);
        self.maximize.setIcon(QtGui.QIcon('img/max.png'));
        close=QtGui.QToolButton(self);
        close.setIcon(QtGui.QIcon('img/close.png'));
        self.minimize.setMinimumHeight(10);
        close.setMinimumHeight(10);
        self.maximize.setMinimumHeight(10);
        label=QtGui.QLabel(self);
        label.setText("Window Title");
        self.setWindowTitle("Window Title");
        hbox=QtGui.QHBoxLayout(self);
        hbox.addWidget(label);
        hbox.addWidget(self.minimize);
        hbox.addWidget(self.maximize);
        hbox.addWidget(close);
        hbox.insertStretch(1,500);
        hbox.setSpacing(0);
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Fixed);
        self.maxNormal=False;
        close.clicked.connect(self.close);
        self.minimize.clicked.connect(self.showSmall);
        self.maximize.clicked.connect(self.showMaxRestore);

    def showSmall(self):
        box.showMinimized();

    def showMaxRestore(self):
        if(self.maxNormal):
            box.showNormal();
            self.maxNormal= False;
            self.maximize.setIcon(QtGui.QIcon('img/max.png'));
            print '1'
        else:
            box.showMaximized();
            self.maxNormal=  True;
            print '2'
            self.maximize.setIcon(QtGui.QIcon('img/max2.png'));

    def close(self):
        box.close()

    def mousePressEvent(self,event):
        if event.button() == Qt.LeftButton:
            box.moving = True; box.offset = event.pos()

    def mouseMoveEvent(self,event):
        if box.moving: box.move(event.globalPos()-box.offset)


class Frame(QtGui.QFrame):
    def __init__(self, parent=None):
        QtGui.QFrame.__init__(self, parent)
        self.m_mouse_down= False;
        self.setFrameShape(QtGui.QFrame.StyledPanel)
        css = """
        QFrame{
            Background:  #D700D7;
            color:white;
            font:13px ;
            font-weight:bold;
            }
        """
        self.setStyleSheet(css) 
        self.setWindowFlags(Qt.FramelessWindowHint);
        self.setMouseTracking(True);
        self.m_titleBar= TitleBar(self);
        self.m_content= QtGui.QWidget(self);
        vbox=QtGui.QVBoxLayout(self);
        vbox.addWidget(self.m_titleBar);
        vbox.setMargin(0);
        vbox.setSpacing(0);
        layout=QtGui.QVBoxLayout(self);
        layout.addWidget(self.m_content);
        layout.setMargin(5);
        layout.setSpacing(0);
        vbox.addLayout(layout);
        # Allows you to access the content area of the frame
        # where widgets and layouts can be added

    def contentWidget(self):
        return self.m_content

    def titleBar(self):
        return self.m_titleBar

    def mousePressEvent(self,event):
        self.m_old_pos = event.pos();
        self.m_mouse_down = event.button()== Qt.LeftButton;

    def mouseMoveEvent(self,event):
        x=event.x();
        y=event.y();

    def mouseReleaseEvent(self,event):
        m_mouse_down=False;

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv);
    box = Frame()
    box.move(60,60);
    l=QtGui.QVBoxLayout(box.contentWidget());
    l.setMargin(0);
    edit=QtGui.QLabel("""I would've did anything for you to show you how much I adored you
But it's over now, it's too late to save our loveJust promise me you'll think of me
Every time you look up in the sky and see a star 'cuz I'm  your star.""");
    l.addWidget(edit)
    box.show()
    app.exec_()
iraj jelodari
  • 3,118
  • 3
  • 35
  • 45
  • 3
    Aaaah, that good 'ol way for programmer to express their feeling on lost love.. ;) Thanks @iraj! Help me so much (not the poet, but the custom title bar!). It rocks! – swdev Jun 29 '14 at 15:09
  • @irai jelodari Hi, I know this thread is quite old, but maybe you can help me. I use PySide (which is in most parts compatible to PyQt) on Python 3.4.4. When I run the example, I get this error: `TypeError: PySide.QtGui.QWidget isn't a direct base class of TitleBar`. Any ideas? – linusg Mar 30 '16 at 17:27
  • @linusg Hi, I didn't work with PyQt since years ago but PyQt and PySide have a lot of changes from earlier version (I have worked with version 4). So which version do you use? May someone could help you. – iraj jelodari Mar 31 '16 at 18:53
  • @irajjelodari I'm using PySide 1.2.4 and Qt 4, because Qt 5 is not supported by PySide yet. I hope, you can help me! – linusg Mar 31 '16 at 19:00
  • 4
    @linusg I was able to reproduce the error you got. In line 13: `QtGui.QWidget.__init__(self, parent)` is calling the `__init__` method of QWidget, but `TitleBar`'s baseclass is a QtGui.QDialog, hence the error message. There are many possible ways to fix it (e.g. use `super(TitleBar, self).__init__()`). Or make the class types match for both`TitleBar`'s baseclass and its `__init__` method by simply replacing `QtGui.QWidget.__init__(self, parent)` with `QtGui.QDialog.__init__(self, parent)` so the class types match. Hope that helps! (-: – chickity china chinese chicken Apr 13 '16 at 00:46
  • 1
    @downshift Thanks a lot! Using the above and commenting out all `setMargin()` calls I made this working on Python 3.4.4 and PySide! – linusg Apr 13 '16 at 16:17
23

Here's a PyQt5 version of @iraj jelodari's script:

#########################################################
## customize Title bar
## dotpy.ir
## iraj.jelo@gmail.com
#########################################################
import sys
from PyQt5 import QtWidgets, QtGui
from PyQt5 import QtCore
from PyQt5.QtCore import Qt

class TitleBar(QtWidgets.QDialog):
    def __init__(self, parent=None):
        QtWidgets.QDialog.__init__(self, parent)
        self.setWindowFlags(Qt.FramelessWindowHint)
        css = """
        QWidget{
            Background: #AA00AA;
            color:white;
            font:12px bold;
            font-weight:bold;
            border-radius: 1px;
            height: 11px;
        }
        QDialog{
            Background-image:url('img/titlebar bg.png');
            font-size:12px;
            color: black;

        }
        QToolButton{
            Background:#AA00AA;
            font-size:11px;
        }
        QToolButton:hover{
            Background: #FF00FF;
            font-size:11px;
        }
        """
        self.setAutoFillBackground(True)
        self.setBackgroundRole(QtGui.QPalette.Highlight)
        self.setStyleSheet(css)
        self.minimize=QtWidgets.QToolButton(self)
        self.minimize.setIcon(QtGui.QIcon('img/min.png'))
        self.maximize=QtWidgets.QToolButton(self)
        self.maximize.setIcon(QtGui.QIcon('img/max.png'))
        close=QtWidgets.QToolButton(self)
        close.setIcon(QtGui.QIcon('img/close.png'))
        self.minimize.setMinimumHeight(10)
        close.setMinimumHeight(10)
        self.maximize.setMinimumHeight(10)
        label=QtWidgets.QLabel(self)
        label.setText("Window Title")
        self.setWindowTitle("Window Title")
        hbox=QtWidgets.QHBoxLayout(self)
        hbox.addWidget(label)
        hbox.addWidget(self.minimize)
        hbox.addWidget(self.maximize)
        hbox.addWidget(close)
        hbox.insertStretch(1,500)
        hbox.setSpacing(0)
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Fixed)
        self.maxNormal=False
        close.clicked.connect(self.close)
        self.minimize.clicked.connect(self.showSmall)
        self.maximize.clicked.connect(self.showMaxRestore)

    def showSmall(self):
        box.showMinimized()

    def showMaxRestore(self):
        if(self.maxNormal):
            box.showNormal()
            self.maxNormal= False
            self.maximize.setIcon(QtGui.QIcon('img/max.png'))
            print('1')
        else:
            box.showMaximized()
            self.maxNormal=  True
            print('2')
            self.maximize.setIcon(QtGui.QIcon('img/max2.png'))

    def close(self):
        box.close()

    def mousePressEvent(self,event):
        if event.button() == Qt.LeftButton:
            box.moving = True
            box.offset = event.pos()

    def mouseMoveEvent(self,event):
        if box.moving: box.move(event.globalPos()-box.offset)


class Frame(QtWidgets.QFrame):
    def __init__(self, parent=None):
        QtWidgets.QFrame.__init__(self, parent)
        self.m_mouse_down= False
        self.setFrameShape(QtWidgets.QFrame.StyledPanel)
        css = """
        QFrame{
            Background:  #D700D7;
            color:white;
            font:13px ;
            font-weight:bold;
            }
        """
        self.setStyleSheet(css)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setMouseTracking(True)
        self.m_titleBar= TitleBar(self)
        self.m_content= QtWidgets.QWidget(self)
        vbox=QtWidgets.QVBoxLayout(self)
        vbox.addWidget(self.m_titleBar)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        layout=QtWidgets.QVBoxLayout()
        layout.addWidget(self.m_content)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(0)
        vbox.addLayout(layout)
        # Allows you to access the content area of the frame
        # where widgets and layouts can be added

    def contentWidget(self):
        return self.m_content

    def titleBar(self):
        return self.m_titleBar

    def mousePressEvent(self,event):
        self.m_old_pos = event.pos()
        self.m_mouse_down = event.button()== Qt.LeftButton

    def mouseMoveEvent(self,event):
        x=event.x()
        y=event.y()

    def mouseReleaseEvent(self,event):
        m_mouse_down=False

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    box = Frame()
    box.move(60,60)
    l=QtWidgets.QVBoxLayout(box.contentWidget())
    l.setContentsMargins(0, 0, 0, 0)
    edit=QtWidgets.QLabel("""I would've did anything for you to show you how much I adored you
But it's over now, it's too late to save our loveJust promise me you'll think of me
Every time you look up in the sky and see a star 'cuz I'm  your star.""")
    l.addWidget(edit)
    box.show()
    app.exec_()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336