bunto1 bunto1 - 2 months ago 19
C++ Question

How to draw line behind buttons in Qt?

Question



In a custom widget, I'd like to draw lines (using
QPainter
) that connect buttons in a
QGridLayout
. The lines shall be behind the buttons, in order to


  • a) not interfere with buttons in between

  • b) allow starting the lines in the center of the buttons, not the edges



Considering ideas from this question, I could almost realize a simple, basic version running in my GUI application (source code below).

As long as I use
QPushButton
with the standard Qt style, it works like a charm (left), but, as I want to use a custom style, the lines overlap (right):

Qt style buttons Custom style buttons

What property or mechanism is causing this behavior?




Code



MyFrame.h:

#include <QFrame>

class MyFrame : public QFrame
{
public:
MyFrame();
virtual ~MyFrame() = default;
};


MyFrame.cpp:

#include "MyFrame.h"

#include "LineDrawWidget.h"

#include <QVBoxLayout>
#include <QGridLayout>
#include <QPushButton>
#include <QButtonGroup>

MyFrame::MyFrame()
{
auto* mainLayout = new QVBoxLayout(this);
auto* buttonLayout = new QGridLayout();

QPushButton* button;
auto* buttons = new QButtonGroup();
for (int i = 0; i < 3; ++i) {
button = new QPushButton();
button->setText(QString::number(i+1));
button->setFixedHeight(40);
button->setFixedWidth(40);
button->setStyleSheet("QPushButton { color : black; background-color : white; }");
button->setStyleSheet("QPushButton { border-style : outset; border-color: black; border-width: 2px; border-radius: 6px; }");
buttonLayout->addWidget(button);
buttons->addButton(button, i);
}

auto* lineDraw = new LineDrawWidget(
buttons->button(0),
buttons->button(2));
lineDraw->setLayout(buttonLayout);
mainLayout->addWidget(lineDraw);
}


LineDrawWidget.h:

#include <QWidget>

class LineDrawWidget : public QWidget
{
public:
LineDrawWidget(
QWidget* from,
QWidget* to,
QWidget* parent = nullptr);
virtual ~LineDrawWidget() = default;

protected:
virtual void paintEvent(QPaintEvent* e) final override;

private:
QWidget* _from;
QWidget* _to;
};


LineDrawWidget.cpp:

#include "LineDrawWidget.h"

#include <QPainter>

LineDrawWidget::LineDrawWidget(
QWidget* from,
QWidget* to,
QWidget* parent) :
QWidget(parent),
_from(from),
_to(to)
{

}

void LineDrawWidget::paintEvent(QPaintEvent* e)
{
(void)e;

QPainter painter(this);

QPoint start = _from->mapToGlobal(_from->rect().bottomLeft());
QPoint end = _to->mapToGlobal(_to->rect().topRight());
painter.drawLine(mapFromGlobal(start), mapFromGlobal(end));
}

Answer Source

I think the problem is the two separate calls to setStyle for a single QPushButton -- the second call appears to reset all properties not present in it. Try putting it all in a single call...

button->setStyleSheet("color : black; background-color : white; border-style : outset; border-color: black; border-width: 2px; border-radius: 6px;");

Seems to work for me.