PyQt5 QComboBox列表项目更改位置

问题描述 投票:0回答:1

我在Qcombobox项的显示样式方面遇到了一些问题。当前正在对要在组合框中显示的数据进行硬编码。

这里是代码:

self.Dummy = QComboBox(self)
self.Dummy.setGeometry(200,600, 350, 50)

self.Dummy.setStyleSheet("QComboBox {background-color: white;border-style: outset;" border-width: 2px;border-radius: 5px;border-color: #448aff; font:  12px; min-width: 10em; padding: 3px;}")

self.Dummy.addItems(["-Select-", "2", "3","4","5","6","7","8","9","0","11",])

问题在于,每次选择后,下拉列表的位置都会不断变化。这是面临的问题的形象。

下面是我的组合框

enter image description here

该列表包含项,2,3,4,5,6,7,8,9,0,11,其中将是显示的第一个元素。

现在,当我单击该框时,该框列表将“向下”放置这些元素,并假设我选择了“ 2”。然后,如果我尝试选择其他项目,则列表将沿“向下”方向放置。见下文

dropped "down"

现在,假设是否从项目'11'中选择了最后一个元素。现在,如果我尝试通过单击框来选择一个新项目,该列表将“向上”弹出而不是向下弹出。见下文

dropped Up

应该怎么做才能解决?我认为样式表不存在问题,没有它也不会发生此问题。我需要解决此问题的原因是,当列表弹出时,其覆盖了其上方的标签

python-2.7 pyqt5 ubuntu-16.04 qcombobox
1个回答
0
投票

您看到的是与操作系统和样式有关的行为。

为了避免这种情况,最好的方法是将QComboBox子类化并覆盖showPopup(),然后我们调用基类实现(负责显示,调整大小和放置弹出视图),并在必要时移动它。

showPopup()

这也可以不用子类来完成(例如,如果您有很多组合,则是从Designer创建UI的,并且不想使用提升的小部件),但是您必须记住将所有引用更改为该组合。

class Combo(QtWidgets.QComboBox):
    def showPopup(self):
        super().showPopup()
        # find the widget that contains the list; note that this is *not* the view
        # that QComboBox.view() returns, but what is used to show it.
        popup = self.findChild(QtWidgets.QFrame)
        rect = popup.geometry()
        if not rect.contains(self.mapToGlobal(self.rect().center())):
            # the popup is not over the combo, there's no need to move it
            return
        # move the popup at the bottom left of the combo
        rect.moveTopLeft(self.mapToGlobal(self.rect().bottomLeft()))
        # ensure that the popup is always inside the edges of the screen
        # we use the center of the popup as a reference, since with multiple
        # screens the combo might be between two screens, but that position
        # could also be completely outside the screen, so the cursor position
        # is used as a fallback to decide on what screen we'll show it
        done = False
        for i, pos in enumerate((rect.center(), QtGui.QCursor.pos())):
            for screen in QtWidgets.QApplication.screens():
                if pos in screen.geometry():
                    screen = screen.geometry()
                    if rect.x() < screen.x():
                        rect.moveLeft(screen.x())
                    elif rect.right() > screen.right():
                        rect.moveRight(screen.right())
                    if rect.y() < screen.y():
                        rect.moveTop(screen.y())
                    elif rect.bottom() > screen.bottom():
                        # if the popup goes below the screen, move its bottom
                        # *over* the combo, so that the its current selected
                        # item will always be visible
                        rect.moveBottom(self.mapToGlobal(QtCore.QPoint()).y())
                    done = True
                    break
            if done:
                break
        popup.move(rect.topLeft())

或者,如果您希望在所有程序中保持一致的行为而又不总是使用子类,则可以使用某种猴子修补程序。优点是您创建的any QComboBox(即使在运行时加载UI文件或创建组合)也将始终使用新行为。

重要:此必须在程序main文件的开始处,可能就在import节之后。

class MyWindow(QtWidgets.QWidget):
    def __init__(self):
        # ...
        self.combo = QtWidgets.QComboBox()
        self.combo.showPopup = self.showPopupAndCheck

    def showPopupAndCheck(self):
        QtWidgets.QComboBox.showPopup(self.combo)
        popup = self.combo.findChild(QtWidgets.QFrame)
        rect = popup.geometry()
        if not rect.contains(self.combo.mapToGlobal(self.combo.rect().center())):
            # the popup is not over the combo, there's no need to move it
            return
        # change everything from self to self.combo
© www.soinside.com 2019 - 2024. All rights reserved.