【发布时间】:2020-08-10 15:43:22
【问题描述】:
我正在从下拉菜单的(子类)QLineEdit 和 QListWidget 构建一个自定义组合框
我将窗口标志设置为 QTool,以便它是一个浮动窗口,但不会从 lineedit 中窃取焦点(因为用户需要能够输入文本来过滤列表)。这工作正常,但列表现在与父小部件完全分离,因此我可以拖动顶部菜单栏并将其从我不想要的列表中移开。
有没有办法使用 QTool 或 QTooltip 但将其作为小部件的父级?
另一种方法是将窗口标志设置为 QPopup,在这种情况下,当单击顶部菜单栏时弹出窗口会关闭,因此无法拖走。但是使用 QPopup 它会从行编辑中窃取焦点
以下是说明问题的简单示例:
from PySide2 import QtCore, QtWidgets, QtGui
import sys
class LineEditClickable(QtWidgets.QLineEdit):
"""Custom QLineEdit to detect clicked, focus and key events
Signals: clicked, focusOut, arrowUp, arrowDown
"""
clicked = QtCore.Signal(QtGui.QMouseEvent)
def __init__(self, value=''):
super(LineEditClickable, self).__init__(value)
# remove border on Mac
self.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
self.setFocusPolicy(QtCore.Qt.ClickFocus)
def mousePressEvent(self, event):
"""Emit clicked signal"""
self.clicked.emit(event)
super(LineEditClickable, self).mousePressEvent(event)
class popup(QtWidgets.QWidget):
def __init__(self, parent = None, widget=None):
QtWidgets.QWidget.__init__(self, parent)
layout = QtWidgets.QVBoxLayout(self)
self.list = QtWidgets.QListWidget()
layout.addWidget(self.list)
# adjust the margins or you will get an invisible, unintended border
layout.setContentsMargins(0, 0, 0, 0)
self.adjustSize()
# tag this widget as a popup
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool)
# self.setWindowFlags(QtCore.Qt.Popup)
def update(self, widget):
# calculate the botoom right point from the parents rectangle
point = widget.rect().bottomRight()
# map that point as a global position
global_point = widget.mapToGlobal(point)
# by default, a widget will be placed from its top-left corner, so
# we need to move it to the left based on the widgets width
self.move(global_point - QtCore.QPoint(self.width(), 0))
def show_popup(self, widget):
self.update(widget)
self.show()
class Window(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.le = LineEditClickable(self)
self.le.clicked.connect(self.handleOpenDialog)
self.le.move(250, 50)
self.resize(600, 200)
self.popup = popup(self, self.le)
self.popup.list.addItems(['one','two','three'])
def handleOpenDialog(self):
self.popup.show_popup(self.le)
self.popup.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())```
【问题讨论】:
-
明确一点,你为什么要使用这个类?除了关于焦点的问题之外,您正在寻找什么特殊行为并且 QComboBox 没有?
-
我开始自定义 QComboBox 如此之多,因为这样做更容易。我正在构建一个模拟这种设计的小部件:material.angular.io/components/autocomplete/examples(带有动画)
-
@MichaelB 根据链接和您所描述的内容,您不需要 QComboBox,而是需要 QCompleter。请使用
@username -
@eyllanesc 我已经实现了自己的逻辑,而不是使用 QCompleter,这一切都很好。我唯一的问题是将我的列表小部件固定在父小部件上,而不会从行编辑中窃取焦点。我已经描述了我尝试过的两个标志(Popup 和 Tool)(我实际上已经尝试过所有这些标志)以及它们各自的问题
-
@MichaelB 除了动画和“顶部标签”之外,您需要与 QCompleter 弹出窗口的默认行为有什么区别?当行编辑获得焦点并且还没有文本时,您想显示所有元素吗?