How to set the color of caret blinking cursor in QLineEdit? I have a question, which is how to change the color of caret blinking cursor in QLineEdit.
2 Answers
Here's a solution I came up with using QLineEdit. It uses the paintEvent to generate a custom caret. I have thought about this for about 2 years and, after stumbling on this thread, decided to try to find a solution.
My solution makes an assumption that you're assigning a font to the field. In this widget, I am using the Hasklig Nerd Font. Download here.
Maybe there is a less convoluted way to go about this, but this works for me. If you change the font, you may need to re-evaluate some of the math to get the caret step feeling good.
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()

- 11
- 3
There is one way you can give a try. Theoretically it looks like it should work (not tested. Look for compile time errors.)
First get the image of icon you want to set.
Then load the image to get QPixmap
object.
QPixmap myPixmap;
myPixmap.load("<<YOURIMAGEPATH>>/cursoricon.png");
Now set the color to QPixmap
using
https://doc.qt.io/qt-5/qpixmap.html#fill
myPixmap.fill(QColor(0,255,0));
Now create a QCursor
object using QPixmap
object
https://doc.qt.io/qt-5/qcursor.html#QCursor-3
QCursor cursor = QCursor(myPixmap);
Then set the cursor to your line edit object.
pLineEdit->setCursor(cursor);
Actually the setCursor function, first I thought it works only for mouse cursor. But the documentation says it holds good for editor widgets also. https://doc.qt.io/qt-5/qwidget.html#cursor-prop
An editor widget might use an I-beam cursor

- 11,671
- 5
- 26
- 34
-
Has anybody ever tested this? This is about the mouse cursor right? – ManuelSchneid3r Nov 03 '22 at 11:36