Можно ли использовать QMenu-прокрутку на небольшом фиксированном размере QMenu? - PullRequest
0 голосов
/ 20 октября 2018

Я пытаюсь создать пользовательское меню фиксированного размера, которое может прокручивать элементы подменю вверх и вниз.
Использование QMenu{menu-scrollable: 1; } работает, но только когда список очень большой и превышает длину экрана, ноПодменю начинается с верхней части экрана, а не рядом с меню, как хотелось бы.Мне интересно, есть ли способ включить функцию прокрутки или просто переместить подменю вниз от верхней части экрана.

Приведенный ниже код добавляет подменю в виде фиксированного размера с меню, но не позволяет добраться до элементов, которые не отображаются.Если вы раскомментируете for i in range(100):, вы увидите, что я имею в виду, когда подменю идет в верхнюю часть экрана, но имеет функцию прокрутки.

У кого-нибудь есть идеи?

import sys
from PyQt5.QtCore import QPoint, QEvent
from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, QApplication, QAction, QMenu

class MyMenu(QMenu):
    def event(self, event):
        if event.type() == QEvent.Show:
            self.move(self.parent().mapToGlobal(QPoint(-88, 0)))
        return super(MyMenu, self).event(event)

class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setStyleSheet("QMenu::item {height: 40px;margin: 0px;padding: 2px 25px 2px 20px;border: none;}")
        self.layout = QVBoxLayout()
        self.btn = QPushButton("Button")
        self.btn.setFixedHeight(30)
        self.btn.setFixedWidth(100)
        self.myMenu = MyMenu("Menu", self.btn)
        self.btn.setMenu(self.myMenu)
        self.layout.addWidget(self.btn)
        self.setLayout(self.layout)

        self.menu = QMenu("Menu1", self.btn)
        self.menu.setStyleSheet("QMenu{menu-scrollable: 1; }")
        self.menu.setMaximumHeight(226)
        self.btn.menu().addMenu(self.menu)
        self.menu2 = QMenu("Menu2", self.btn)
        self.menu2.setStyleSheet("QMenu{menu-scrollable: 1; }")
        self.menu2.setMaximumHeight(226)
        self.btn.menu().addMenu(self.menu2)
        self.menu3 = QMenu("Menu3", self.btn)
        self.menu3.setStyleSheet("QMenu{menu-scrollable: 1; }")
        self.menu3.setMaximumHeight(226)
        self.btn.menu().addMenu(self.menu3)
        self.menu4 = QMenu("Menu4", self.btn)
        self.menu4.setStyleSheet("QMenu{menu-scrollable: 1; }")
        self.menu4.setMaximumHeight(226)
        self.btn.menu().addMenu(self.menu4)
        self.menu5 = QMenu("Menu5", self.btn)
        self.menu5.setStyleSheet("QMenu{menu-scrollable: 1; }")
        self.menu5.setMaximumHeight(226)
        self.btn.menu().addMenu(self.menu5)

        for i in range(15):
        # for i in range(100):
            action = QAction("item"+str(i), self)
            self.menu.addAction(action)
            self.menu2.addAction(action)
            self.menu3.addAction(action)
            self.menu4.addAction(action)
            self.menu5.addAction(action)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()

РЕДАКТИРОВАТЬ:

У меня есть рабочий пример, хотя я не совсем уверен, почему он работает.
Я заставил его работать, используя QStyle.PM_MenuScrollerHeight и QStyle.PM_MenuDesktopFrameWidth, но должен быть лучший способ.
Приведенный ниже код работает, но для активации полос прокрутки требуется минимум 23 элемента в подменю.Я уверен, что небольшая настройка может исправить это, но сейчас это то, что я получил.
Если у кого-то есть какие-либо предложения, это будет оценено.

import sys
from PyQt5.QtCore import QPoint, QEvent
from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, \
    QApplication, QAction, QMenu, QProxyStyle, QStyle

class MyMenu(QMenu):
    def event(self, event):
        if event.type() == QEvent.Show:
            self.move(self.parent().mapToGlobal(QPoint(-108, 0)))
        return super(MyMenu, self).event(event)

class CustomStyle(QProxyStyle):
    def pixelMetric(self, QStyle_PixelMetric, option=None, widget=None):
        if QStyle_PixelMetric == QStyle.PM_MenuScrollerHeight:
            return 15
        if QStyle_PixelMetric == QStyle.PM_MenuDesktopFrameWidth:
            return 290
        else:
            return QProxyStyle.pixelMetric(self, QStyle_PixelMetric, option, widget)

class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.layout = QVBoxLayout()
        self.btn = QPushButton("Button")
        self.btn.setFixedHeight(30)
        self.btn.setFixedWidth(100)
        self.myMenu = MyMenu("Menu", self.btn)
        self.myMenu.setFixedHeight(120)
        self.btn.setMenu(self.myMenu)
        self.layout.addWidget(self.btn)
        self.setLayout(self.layout)
        menus = []
        for _ in range(5):
            myMenus = QMenu("Menu"+str(_+1), self.btn)
            myMenus.setFixedHeight(120)
            myMenus.setStyleSheet("QMenu{menu-scrollable: 1; }")
            menus.append(myMenus)
        for i in menus:
            self.btn.menu().addMenu(i)
            for item in range(23):
                action = QAction("item" + str(item), self)
                i.addAction(action)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle(CustomStyle())
    w = MainWindow()
    w.show()
    app.exec_()
...