如何在QLineEdit中设置插入符号闪烁光标的颜色

liu*_*gya 5 qt cursor qlineedit qt5

如何设置QLineEdit中插入符号闪烁光标的颜色?我有一个问题,如何更改 QLineEdit 中插入符号闪烁光标的颜色。

小智 -1

这是我使用 QLineEdit 提出的解决方案。它使用paintEvent 生成自定义插入符。我已经思考这个问题大约两年了,在偶然发现这个问题之后,决定尝试寻找解决方案。

我的解决方案假设您正在为该字段分配字体。在此小部件中,我使用 Hasklig Nerd 字体。在这里下载

也许有一种不太复杂的方法可以解决这个问题,但这对我有用。如果更改字体,您可能需要重新评估一些数学运算才能使插入符号步骤感觉良好。

from PySide2.QtCore import Qt, QRect
from PySide2.QtGui import QPainter, QColor, QFont, QFontMetricsF
from PySide2.QtWidgets import QWidget, QLineEdit, QCommonStyle, QStyle, QStyleOption


_WIDGET_HEIGHT: int = 24


class CaretStyle(QCommonStyle):

    def __init__(self, width: int = None):
        """
        This allows us to set the width of the default widget input caret.

        Args:
            width (int): The width of the input caret in pixels.
        """
        super().__init__()
        self._width = 5 if width is None else width

    def pixelMetric(self, pixel_metric: QStyle, option: QStyleOption = None, widget: QWidget = None):
        if pixel_metric == QStyle.PM_TextCursorWidth:
            return self._width
        else:
            return QCommonStyle.pixelMetric(self, pixel_metric, option, widget)


def remap_value(value: float, old: tuple, new: tuple) -> float:
    """Range remaps a value using old and new min/max."""
    old_min, old_max = old
    new_min, new_max = new
    return (new_max - new_min) * (value - old_min) / (old_max - old_min) + new_min


class StringInput(QLineEdit):
    _caret_pos_x: float = 0.0
    _caret_pos_y: float = 1 + _WIDGET_HEIGHT * 0.2
    _font_metric: QFontMetricsF = None

    def __init__(self, *args, **kwargs):
        """
        QLineEdit with custom input field caret.
        """
        super().__init__(parent=kwargs.get("parent", None))
        self.setObjectName("ParmInput")

        self.setFixedHeight(24)
        self.setFocusPolicy(Qt.StrongFocus)

        # hide the default caret by scaling it to 0
        self.setStyle(CaretStyle(width=0))

        # accessing font details is important for accurate
        # caret positioning
        font = QFont("Hasklug NF", 9, QFont.Thin)
        font.setHintingPreference(QFont.HintingPreference.PreferNoHinting)
        self._font_metric = QFontMetricsF(font)
        self.setFont(font)

        # align the text within the field
        self.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)

        # we need this so we can update the caret in the field as the user
        # does stuff.
        self.cursorPositionChanged.connect(self._update_caret_pos_x)

    def _update_caret_pos_x_x(self):
        """Calculate the position of the caret based on cursor position."""
        text: str = self.text()
        step: float = self._font_metric.averageCharWidth() - 1

        # if the field is empty set the character to teh step value.
        # this puts the caret where the first char would be. this also
        # prevents divide by 0 if no text is in the field.
        if len(text) < 1:
            self._caret_pos_x = step
            return

        cursor_pos: int = self.cursorPosition()
        text_width: int = self._font_metric.width(text)
        char_count: len(text)

        # remap the cursor position based on the current text in the field.
        self._caret_pos_x = remap_value(cursor_pos, 0, 1, 0, text_width) / char_count + step

    def get_caret_pos_x(self) -> float:
        """Queries the current position of the caret."""
        return self._caret_pos_x

    def focusInEvent(self, event) -> None:
        """We update the caret position upon focus, based on where the user clicked."""
        self._update_caret_pos_x()

    def focusOutEvent(self, event) -> None:
        """Clear the current text selection if the field loses focus."""
        self.setSelection(0, 0)

    def paintEvent(self, event):
        """This creates a custom caret for the input field."""
        super().paintEvent(event)

        # easy out if the widget doesnt have focus
        if not self.hasFocus():
            return

        width: float = 2.0
        height: float = _WIDGET_HEIGHT/1.5

        painter: QPainter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(Qt.NoPen)

        caret = QRect(self.get_caret_pos_x(), self._caret_pos_y, width, height)
        painter.setBrush(QColor(231, 167, 38, 150))
        painter.drawRect(caret)

        painter.end()
Run Code Online (Sandbox Code Playgroud)