Как добавить разделитель в строку меню в pyqt5

#python #pyqt5

#python #pyqt5

Вопрос:

главное окно с панелью меню, панелью инструментов и строкой состояния

 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("amp;File")
        outilMenu = menuBar.addMenu("amp;Outils")
        menuBar.addSeparator()
        achatMenu = menuBar.addMenu("Bying")
        stockMenu = menuBar.addMenu("Stocks")
        menuBar.addSeparator()
        helpMenu = menuBar.addMenu("amp;Help")

 

когда я запускаю код, никаких проблем не возникает, но я не получил разделитель

Комментарии:

1. Вы обеспечили правильное написание «строки меню»? У вас есть две опечатки с ‘menuBap’, чтобы убедиться, что это не проблема 😉

2. ошибка только здесь, в вопросе / мой код правильный MenuBar.addSeparator()

3. QMenuBar не поддерживает разделители.

4. Просто чтобы убедиться, вам нужны вертикальные разделители в самой панели меню, а не горизонтальные разделители в меню панели меню…. Я ошибся, и благодаря musicamente понял это сейчас — удалил мой ответ.

5. @hamzachenni когда вы публикуете / редактируете свой код, пожалуйста, убедитесь, что его синтаксис правильный: например, в _createMenuBar() функции отсутствует self аргумент, а другие функции, подобные _createActions() этому, отсутствуют в вашем коде (и не имеют отношения к примеру, поэтому этих строк там быть не должно).

Ответ №1:

QMenuBar изначально не поддерживает разделители. Он даже не поддерживает добавление QWidgetActions, поскольку они отображаются как пустые действия, а их виджет фактически никогда не отображается.

Единственное решение — создать «поддельное» действие с уникальным идентификатором и обойти рисование действия с помощью QProxyStyle: мы переопределяем, sizeFromContents() чтобы, когда QMenuBar вычисляет размеры своих действий, он возвращал соответствующую ширину, и drawControl() рисовать поддельный QFrame, который отображается в виде VLine (напримервертикальные разделители в конструкторах).

строка меню с разделителями

Важно: это не будет работать на macOS при использовании 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())
 

Обратите внимание, что:

  • поскольку QMenuBar автоматически игнорирует действия разделителя, setSeparator(True) его нельзя использовать для действия разделителя;
  • действие «разделитель» должно быть отключено, иначе навигация с клавиатуры попытается сфокусировать его;
  • это будет работать даже для строк меню, созданных в Designer, если вы добавите меню с именем с уникальным идентификатором (меню должно быть отключено, как описано в предыдущем пункте);
  • символ '_' подчеркивания используется для идентификации разделителей в стиле, поскольку QStyle не имеет прямого доступа к действиям (поэтому мы не можем использовать action.setData ), и требуется использование специального символа, потому что некоторые стили Qt имеют плохую привычку устанавливать мнемонику (подчеркнутые буквы, которые используются в качестве ярлыков) путем изменения текста /метка тоже, поэтому, если вы используете что-то вроде «separator», она может стать «amp; separator» или даже «s amp; eparator», если у другого объекта уже есть ярлык «s» или вы добавляете больше разделителей. Другая возможность — использовать ‘amp;’ или ‘amp;amp;amp;’ или любой другой уникальный не буквенно-цифровой идентификатор символа, например '_#' .