【问题标题】:How to make a cursor in a PyQt5 label如何在 PyQt5 标签中制作光标
【发布时间】:2021-07-19 22:29:28
【问题描述】:

我有一个 PyQt5 窗口,其中有一个带有文本的标签。

那里出现的文本来自 python 字符串变量。该字符串由用户单击屏幕上的按钮构建,然后将该字符串输出到该标签中的窗口。

到目前为止,我有一个退格按钮,可以删除字符串中的最后一个字符,但我也希望用户能够单击标签中字符前面的位置,然后能够删除那个角色。

所以,我想知道如何做两件事。

  1. 如何根据用户点击获取字符串中的字符位置
  2. 我已经看到了一些示例,但我还想在用户单击该位置后在该位置显示一个光标。

我想使用标签小部件来执行此操作,而不是使用文本输入字段。

有人有什么想法吗?

【问题讨论】:

  • 使用标签无法获得 100% 可靠的光标位置,但有一些方法可以禁用 QLineEdit 中的文本输入(最重要的是,通过覆盖 keyPressEvent())。为什么您特别需要 QLabel?
  • @musicamante 如果我覆盖 KeyPressEvent() 则无法从键盘输入用户输入?如果是这样,那么只要我可以在 QLineEdit 中放置一个字符串变量,那么它可能会起作用。
  • 有没有办法禁用键盘上除数字之外的所有键?
  • 这是您避免 QLineEdit 的唯一要求吗?
  • 我不会说唯一的要求,但其他要求我觉得我会在网上找到解决方案更舒服(例如将光标设置为在其他要求中单击之前不显示)

标签: python qt user-interface pyqt label


【解决方案1】:

让 QLabel 像这样工作很困难(QLabel 比看起来更复杂)。
可以在点击后显示光标,这可以通过设置textInteractionFlags 属性来实现:

self.label.setTextInteractionFlags(
    QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextSelectableByKeyboard)

第一个标志允许处理鼠标事件,而第二个标志允许在标签获得焦点后立即显示光标(例如,单击它之后)。
不幸的是,这不允许您获取光标位置(也不能更改它); 种方法(使用 QFontMetrics 和 QTextDocument),但您需要一个复杂的实现以使其真正可靠。

解决方案是使用 QLineEdit 并覆盖 keyPressEvent,这是在发生按键时始终在小部件上调用的函数(并且它具有输入焦点)。考虑到数字输入似乎仍然需要,只需确保 event.key() 对应于数字的 Qt.Key 枚举,在这种情况下,调用基本实现。
您甚至可以通过正确设置其样式表使其看起来与 QLabel 完全一样。

class CommandLineEdit(QtWidgets.QLineEdit):
    allowedKeys = (
        QtCore.Qt.Key_0, 
        QtCore.Qt.Key_1, 
        QtCore.Qt.Key_2, 
        QtCore.Qt.Key_3, 
        QtCore.Qt.Key_4, 
        QtCore.Qt.Key_5, 
        QtCore.Qt.Key_6, 
        QtCore.Qt.Key_7, 
        QtCore.Qt.Key_8, 
        QtCore.Qt.Key_9, 
    )
    def __init__(self):
        super().__init__()
        self.setStyleSheet('''
            CommandLineEdit {
                border: none;
                background: transparent;
            }
        ''')

    def keyPressEvent(self, event):
        if event.key() in self.allowedKeys:
            super().keyPressEvent(event)

那么,如果你想以编程方式设置文本,同样基于光标,这里有一个基本用法:

from functools import partial

class CommandTest(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QVBoxLayout(self)
        self.commandLineEdit = CommandLineEdit()
        layout.addWidget(self.commandLineEdit)
        keys = (
            'QWERTYUIOP', 
            'ASDFGHJKL', 
            'ZXCVBNM'
        )
        backspaceButton = QtWidgets.QToolButton(text='<-')
        enterButton = QtWidgets.QToolButton(text='Enter')
        self.shiftButton = QtWidgets.QToolButton(text='Shift', checkable=True)
        for row, letters in enumerate(keys):
            rowLayout = QtWidgets.QHBoxLayout()
            rowLayout.addStretch()
            layout.addLayout(rowLayout)
            for letter in letters:
                btn = QtWidgets.QToolButton(text=letter)
                rowLayout.addWidget(btn)
                btn.clicked.connect(partial(self.typeLetter, letter))
            rowLayout.addStretch()
            if row == 0:
                rowLayout.addWidget(backspaceButton)
            elif row == 1:
                rowLayout.addWidget(enterButton)
            else:
                rowLayout.addWidget(self.shiftButton)
        spaceLayout = QtWidgets.QHBoxLayout()
        layout.addLayout(spaceLayout)
        spaceLayout.addStretch()
        spaceButton = QtWidgets.QToolButton(minimumWidth=200)
        spaceLayout.addWidget(spaceButton)
        spaceLayout.addStretch()

        backspaceButton.clicked.connect(self.commandLineEdit.backspace)
        spaceButton.clicked.connect(lambda: self.typeLetter(' '))

    def typeLetter(self, letter):
        text = self.commandLineEdit.text()
        pos = self.commandLineEdit.cursorPosition()
        if not self.shiftButton.isChecked():
            letter = letter.lower()
        self.commandLineEdit.setText(text[:pos] + letter + text[pos:])

import sys
app = QtWidgets.QApplication(sys.argv)
w = CommandTest()
w.show()
sys.exit(app.exec_())

如您所见,您可以调用backspace() 来清除最后一个字符(或选择),并且在typeLetter 函数中还有您需要的所有剩余功能:获取/设置文本和光标位置。
对于其他任何事情,只需研究完整的documentation

【讨论】:

  • 我设法使 QLineEdit 看起来与 Label 相似,但在使用 keyPressOverride 禁用键盘时遇到了问题。我尝试查找有关该主题的更多信息,并且在将其实施到我的代码中时遇到了麻烦。您能否再解释一下您发布的第一个代码 sn-p,以便我可以尝试更好地理解如何将其实现到我的代码中?
  • 实现非常简单:如果事件的key()(它返回一个Qt.Key枚举)包含在allowedKeys元组中,那么该事件将作为基础QLineEdit处理,否则它只是忽略。我不知道您是如何实现代码的,如果没有任何上下文,我们无法为您提供更多帮助。
  • 我知道缺少什么。我需要事先添加self.centralwidget.keyPressEvent = self.keyPressEvent(其中centralwidget 是主窗口)以使keyPressEvent 覆盖
  • 您是否也知道如何禁用选择 QLineEdit 中的文本?我想要一个光标,但不允许用户用光标选择文本(使其变为蓝色或灰色)(我在 PyQt4 中找到了这样做的方法,但我在 PyQ5 上遇到了更多麻烦)?
  • 1.从您所写的内容来看,您不是子类化,我相信这只是因为您正在尝试使用在 Designer 中创建的 UI。如果是这样,这就引出了下一点,为此... 2. 您需要子类化,如果使用 Designer UI,唯一的方法是使用提升的小部件;对这个主题进行一些研究,因为有很多关于它的资源,即使对于 PyQt 也是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-27
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 2020-10-26
  • 2011-03-14
相关资源
最近更新 更多