I've got four QLineEdit
placed inside of a QLineEdit
s, where I want the first the parent to look as if it is in focus when any of the containing ones is selected. Note: I don't want the focus to actually change, just the "focus frame" (the thin blue border) to appear on the parent LineEdit.
I've tried to draw a rect, but while it works on Windows I'm running into issues of the drawn rectangle not looking like a proper rectangle on ex. Linux, where it is supposed to be rounded. Is there a way to fix this OR, if possible, just make it draw itself as focused despite focus not being on it?
Here's my attempt at drawing a custom rect, but haven't been able to make it successfully mirror the OS style properly.
if (childHasFocus) {
QPainter painter(this);
QLineEdit textBox;
QColor color = textBox.palette().color(QPalette::Highlight);
painter.setPen(color);
QRect rect;
rect.setTopLeft(QPoint(0,0));
rect.setWidth(this->width() - 1);
rect.setHeight(this->height() - 1);
painter.drawRect(rect);
}
EDIT: Added an image of the desired look. Note that I'm trying to get it to look like other LineEdits focusframe independent of OS, so hardcoding a blue rectangle won't work due to ex. Linux having a rounded focusframe.
Here's how to do it. Its a very basic class that draws the focus frame if any of the childs have focus. On focus change, we do an update (which can probably be optimized a bit to avoid unnecessary repaints).
Screenshot:
class IPEdit : public QWidget
{
public:
IPEdit(QWidget *parent = nullptr)
: QWidget(parent)
{
delete layout();
auto l = new QHBoxLayout(this);
setFocusProxy(&a);
setAttribute(Qt::WA_Hover);
for (auto *w : {&a, &b, &c, &d}) {
l->addWidget(w);
w->installEventFilter(this);
}
}
bool eventFilter(QObject *o, QEvent *e) override
{
if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) {
update();
}
return QWidget::eventFilter(o, e);
}
void paintEvent(QPaintEvent *e) override
{
QStyleOptionFrame opt;
opt.initFrom(this);
opt.frameShape = QFrame::StyledPanel;
opt.state |= QStyle::State_Sunken;
// clear mouseOver and focus state
// update from relevant widgets
opt.state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver);
const auto widgets = {&a, &b, &c, &d};
for (const QWidget *w : widgets) {
if (w->hasFocus()) {
opt.state |= QStyle::State_HasFocus;
}
}
opt.rect = contentsRect();
QPainter paint(this);
paint.setClipRegion(e->region());
paint.setRenderHints(QPainter::Antialiasing);
style()->drawControl(QStyle::CE_ShapedFrame, &opt, &paint, this);
}
private:
QLineEdit a;
QLineEdit b;
QLineEdit c;
QLineEdit d;
};