如何在 PyQt5 标签中制作光标

How to make a cursor in a PyQt5 label

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

此处显示的文本来自 python 字符串变量。该字符串由用户单击屏幕上的按钮构建,然后该字符串输出到该标签中的 window。

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

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

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

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

有人有什么想法吗?

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

来实现的
self.label.setTextInteractionFlags(
    QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextSelectableByKeyboard)

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

解决方案是使用 QLineEdit 并覆盖数字的 keyPressEvent, which is the function that is always called on a widget whenever a key press happens (and it has input focus). Considering that number input seems still required, just ensure that the event.key() corresponds to a 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 函数中有您需要的所有剩余功能:getting/setting 文本和光标位置。
其他的,就研究完整的documentation.