一半君的总结纸

听话只听一半君

如何创建一个带下拉菜单的QPushButton

想让按钮的右侧有个像QCombobox一样的倒三角,并且有下拉菜单(点击三角区域?长按鼠标左键?)

  • 最容易想到的方法,直接用QPushButton的setMenu(),可是这样按钮本身连着的slot就废了,按下左键就只能弹出菜单而已,要触发slot必须选择一个菜单,而且菜单出现在按钮左侧

    from PyQt4 import QtGui, QtCore
    import sys
    
    # http://stackoverflow.com/a/6901696/2052889
    class Main(QtGui.QMainWindow):
    
        def __init__(self, parent=None):
            super(Main, self).__init__(parent)
            pushbutton = QtGui.QPushButton('Popup Button')
            menu = QtGui.QMenu()
            menu.addAction('This is Action 1', self.Action1)
            menu.addAction('This is Action 2', self.Action2)
            pushbutton.setMenu(menu)
            self.setCentralWidget(pushbutton)
            self.resize(200, 30)
    
        def Action1(self):
            print 'You selected Action 1'
    
        def Action2(self):
            print 'You selected Action 2'
    
    
    if __name__ == '__main__':
    
        app = QtGui.QApplication(sys.argv)
        main = Main()
        main.show()
        app.exec_()
    
  • QToolButton有好几个 ToolButtonPopupMode可以支持长按,而且可以在按钮右侧显示一个下拉倒三角,和上面方法不同之处是单击非三角区域时可以执行按钮本身连接的slot.

    可是在某些style影响下看起来和QPushButton外观不同,如果混在一大堆QPushButton中间显得很不和谐. 此外,如果使用了DelayedPopup,右侧的三角会移动倒右下角,不过应该可以用qss移动到右侧中部

    from PyQt4 import QtGui, QtCore
    import sys
    
    
    class Main(QtGui.QMainWindow):
    
        def __init__(self, parent=None):
            super(Main, self).__init__(parent)
            button = QtGui.QToolButton()
            button.setText('Popup Button')
            # Use DelayedPopup for tapAndHold effect
            # button.setPopupMode(QtGui.QToolButton.DelayedPopup)
            button.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
    
            menu = QtGui.QMenu()
            menu.addAction('This is Action 1', self.Action1)
            menu.addAction('This is Action 2', self.Action2)
    
            button.setMenu(menu)
    
            self.setCentralWidget(button)
            self.resize(200, 30)
    
        def Action1(self):
            print 'You selected Action 1'
    
        def Action2(self):
            print 'You selected Action 2'
    
    
    if __name__ == '__main__':
    
        app = QtGui.QApplication(sys.argv)
        main = Main()
        main.show()
        app.exec_()
    
    

    可以用qss把三角移回中间

            button.setStyleSheet('''
                QToolButton::menu-indicator{
                    subcontrol-position: right center;
                    right: 5px;
                }
                ''')
    
  • 综合以上两者,如果非得用QPushButton,但是又想让他保留自己的按下去就能执行slot的功能,而不是像方法一里那样失去按钮功能的话。lz在eventFilter里把弹出的菜单移到了按钮的右侧
    from PyQt4 import QtGui, QtCore
    import sys
    
    
    class DropdownButton(QtGui.QPushButton):
    
        def __init__(self, parent=None):
            super(DropdownButton, self).__init__(parent)
    
            # button = QtGui.QToolButton()
            self.setText('Popup Button')
            # Use DelayedPopup for tapAndHold effect
            # button.setPopupMode(QtGui.QToolButton.DelayedPopup)
            # button.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
    
            self.installEventFilter(self)
    
            self.setStyleSheet('''
                QToolButton::menu-indicator{
                    subcontrol-position: right center;
                    right: 5px;
                }
                ''')
    
        def mousePressEvent(self, event):
    
            if event.type() == QtCore.QEvent.MouseButtonPress:
    
                pos = event.pos()
    
                topRight = self.rect().topRight()
                bottomRight = self.rect().bottomRight()
    
                hotspotTopLeft = QtCore.QPoint(topRight.x()-25, topRight.y())
    
                hotspotRect = QtCore.QRect(hotspotTopLeft, bottomRight)
    
                if hotspotRect.contains(pos):
                    print 'clicked inside hotspot'
                    QtGui.QPushButton.mousePressEvent(self, event)
                else:
                    print 'clicked outside hotspot'
                    self.blockSignals(True)
                    QtGui.QPushButton.mousePressEvent(self, event)
                    self.blockSignals(False)
    
        def eventFilter(self, obj, event):
            if event.type() == QtCore.QEvent.Paint:
                menu = self.menu()
                if menu and menu.isVisible():
                    pos = menu.pos()
                    pos.setX(pos.x() + self.width() - menu.width())
    
                    # move menu up if needed
                    # frameWidth = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
                    # buttonMargin = self.style().pixelMetric(QtGui.QStyle.PM_ButtonMargin)
                    # pos.setY(pos.y() - buttonMargin+ frameWidth + 2)
    
                    menu.move(pos)
    
            return False
    
    
    class MyDialog(QtGui.QDialog):
    
        def __init__(self, parent=None):
            super(MyDialog, self).__init__(parent)
            layout = QtGui.QVBoxLayout()
            button = DropdownButton()
    
            menu = QtGui.QMenu()
            menu.addAction('This is Action 1', self.Action1)
            menu.addAction('This is Action 2', self.Action2)
            button.setMenu(menu)
    
            layout.addWidget(button)
            self.setLayout(layout)
            self.resize(300, 30)
    
        def Action1(self):
            print 'You selected Action 1'
    
        def Action2(self):
            print 'You selected Action 2'
    
    if __name__ == '__main__':
    
        app = QtGui.QApplication(sys.argv)
        win = MyDialog()
        win.show()
        app.exec_()
    
    
  • 自找麻烦模式,在paintEvent里自己画倒三角
    
    
  • 把QPushButton的style复制给QToolButton?
    
    

参考:
PyQT QPushButton.setMenu? How to make it work?

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: