main window with menubar ,toolbar and statusbar
class TajirMWindow(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("Tajir/Home")
self.resize(800, 400)
self.centralWidget = QLabel("Hello, World")
self.centralWidget.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.setCentralWidget(self.centralWidget)
self._createActions()
self._connectActions()
self._createMenuBar() #Menus
self._createToolBars()#tools
'''
Menu Bar function
'''
def _createMenuBar():
menuBar = self.menuBar()
fileMenu = menuBar.addMenu("&File")
outilMenu = menuBar.addMenu("&Outils")
menuBar.addSeparator()
achatMenu = menuBar.addMenu("Bying")
stockMenu = menuBar.addMenu("Stocks")
menuBar.addSeparator()
helpMenu = menuBar.addMenu("&Help")
when i run the code no probleme accur but i didn t get the separator
QMenuBar doesn't support separators natively. It doesn't even support adding QWidgetActions, as they appear as empty actions and their widget are never actually shown.
The only solution is to create a "fake" action with an unique identifier, and bypass the drawing of the action using a QProxyStyle: we override sizeFromContents()
so that when the QMenuBar computes the sizes of its actions it returns an appropriate width, and drawControl()
to draw a fake QFrame that is displayed as a VLine (like vertical separators in Designers).
Important: this will not work on MacOS when using the nativeMenuBar.
class MenuProxy(QtWidgets.QProxyStyle):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# create a fake frame that we'll use as a source for the separator
self.fakeFrame = QtWidgets.QFrame(frameShape=QtWidgets.QFrame.VLine)
def sizeFromContents(self, content, opt, size, widget=None):
size = super().sizeFromContents(content, opt, size, widget)
if (content == self.CT_MenuBarItem and
isinstance(widget, QtWidgets.QMenuBar)
and opt.text == '_'):
# use the size hint of the frame to return the correct width
size.setWidth(self.fakeFrame.sizeHint().width())
return size
def drawControl(self, ctl, opt, qp, widget=None):
if (ctl == self.CE_MenuBarItem and
isinstance(widget, QtWidgets.QMenuBar) and
opt.text == '_'):
self.fakeFrame.resize(opt.rect.size())
frameOpt = QtWidgets.QStyleOptionFrame()
self.fakeFrame.initStyleOption(frameOpt)
# the frame will be drawn using its own coordinates (starting
# from 0, 0), so we need to save the current state of the painter
# and then translate to the correct position
qp.save()
qp.translate(opt.rect.topLeft())
# paint the "fake" frame
self.drawControl(self.CE_ShapedFrame, frameOpt, qp, self.fakeFrame)
# restore the painter to the previous position
qp.restore()
return
super().drawControl(ctl, opt, qp, widget)
class YourWindow(QtWidgets.QMainWindow):
def __init__(self):
# ...
sep = QtWidgets.QAction('_', self, enabled=False)
menuBar.addAction(sep)
# ...
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle(MenuProxy())
Note that:
setSeparator(True)
must not be used for the separator action;'_'
underscore is used to identify separators in the style, as QStyle has no direct access to actions (so we can't use action.setData
), and using a special character is required because some Qt styles have the bad habit of setting mnemonics (the underscored letters that are used as shortcuts) by changing the text/label too, so if you use something like "separator", it could become "&separator", or even "s&eparator" if another object has the "s" shortcut already grabbed or you add more separators. Another possibility is to use '&' or '&&&' or any other unique non-alphanumeric character identifier like '_#'
.