This example demonstrates how to use low level drawing methods to create a polygon shape and then set the pen to draw the border and the brush for the fill characteristics.
class DrawArea;
class MainWindow : public QWidget
{
public:
MainWindow();
private:
DrawArea *renderArea;
QComboBox *penCB;
QComboBox *brushCB;
void penChanged();
void brushChanged();
};
class DrawArea : public QWidget
{
CS_OBJECT(DrawArea)
public:
DrawArea(QWidget *parent = nullptr);
void setPen(const QPen &pen);
void setBrush(const QBrush &brush);
protected:
void paintEvent(QPaintEvent *event);
private:
QPen pen;
QBrush brush;
};
The forward declaration on line 1 is required since line 9 declares a pointer to a variable of type DrawArea. As an alternative the class declaration for DrawArea could be moved before the class declaration for MainWindow.
The DrawArea class is used to provide a render area where low level shapes can be drawn. The paintEvent() method declared on line 29 is where the actual drawing commands will appear. The method declarations on line 25 and 26 are slots which will be activated when the pen and brush combo box values are changed.
MainWindow::MainWindow()
{
setMinimumSize(700, 500);
renderArea = new DrawArea;
//
QLabel *penLabel = new QLabel("Pen:");
penCB = new QComboBox;
penCB->addItem("Solid",
QVariant::fromValue(Qt::SolidLine));
penCB->addItem("Dash",
QVariant::fromValue(Qt::DashLine));
penCB->addItem("Dot",
QVariant::fromValue(Qt::DotLine));
penCB->addItem("Dash Dot",
QVariant::fromValue(Qt::DashDotLine));
penCB->addItem("Dash Dot Dot",
QVariant::fromValue(Qt::DashDotDotLine));
penCB->addItem("None",
QVariant::fromValue(Qt::NoPen));
//
QLabel *brushLabel = new QLabel("Brush:");
brushCB = new QComboBox;
brushCB->addItem("Linear Gradient",
QVariant::fromValue(Qt::LinearGradientPattern));
brushCB->addItem("Radial Gradient",
QVariant::fromValue(Qt::RadialGradientPattern));
brushCB->addItem("Conical Gradient",
QVariant::fromValue(Qt::ConicalGradientPattern));
brushCB->addItem("Solid",
QVariant::fromValue(Qt::SolidPattern));
brushCB->addItem("Horizontal",
QVariant::fromValue(Qt::HorPattern));
brushCB->addItem("Vertical",
QVariant::fromValue(Qt::VerPattern));
brushCB->addItem("Cross",
QVariant::fromValue(Qt::CrossPattern));
brushCB->addItem("Backward Diagonal",
QVariant::fromValue(Qt::BDiagPattern));
brushCB->addItem("Forward Diagonal",
QVariant::fromValue(Qt::FDiagPattern));
brushCB->addItem("Diagonal Cross",
QVariant::fromValue(Qt::DiagCrossPattern));
brushCB->addItem("None",
QVariant::fromValue(Qt::NoBrush));
QPushButton *pb_close = new QPushButton();
pb_close->setText("Close");
QGridLayout *layout_grid = new QGridLayout;
layout_grid->setColumnStretch(2, 1);
layout_grid->setHorizontalSpacing(20);
layout_grid->setVerticalSpacing(15);
layout_grid->addWidget(penLabel, 2, 0);
layout_grid->addWidget(penCB, 2, 1);
layout_grid->addWidget(brushLabel, 3, 0);
layout_grid->addWidget(brushCB, 3, 1);
QHBoxLayout *layout_pb = new QHBoxLayout();
layout_pb->addStretch();
layout_pb->addWidget(pb_close);
layout_pb->addStretch();
QVBoxLayout *layoutMain = new QVBoxLayout(this);
layoutMain->setContentsMargins(40, 35, 40, 15);
layoutMain->addWidget(renderArea);
layoutMain->addSpacing(25);
layoutMain->addLayout(layout_grid);
layoutMain->addSpacing(25);
layoutMain->addLayout(layout_pb);
connect(penCB, cs_mp_cast<int>(&QComboBox::activated),
this, &MainWindow::penChanged);
connect(brushCB, cs_mp_cast<int>(&QComboBox::activated),
this, &MainWindow::brushChanged);
connect(pb_close, &QPushButton::clicked,
this, &QWidget::close);
penChanged();
brushChanged();
}
On line 5 the constructor for a new DrawArea is created and assigned to the variable renderArea. This defines the region where the paintEvent() method will draw the shape.
The two combo boxes created on lines 10 and 33 provide a way for the user to specify the border line shape and fill brush. These parameters will be used when drawing the shape. On line 71 a grid layout is created and the GUI elements are added.
On lines 96 and 99 two Signal/Slot connections are made to call the penChanged() and brushChanged() slot methods when the value of the corresponding combo box is modified by the user. A third call to connect() is made on line 102 which will close the program when the user clicks the Close push button.
The last two lines (105 and 106) call the two draw slot methods to initialize the pen and brush. This will trigger a repaint of the renderArea and display the shape at program start up.
Signal / Slot Connections
In the prior block on line 96 a signal/slot connection is set up and will be triggered when the pen combo box value is changed. The slot method penChanged() is called which will assign several values and then construct a new QPen object. The new pen value is passed on line 12 to the DrawArea::setPen() method, which is shown in the next block of code.
The call to connect() on line 99 is triggered when the brush combo box value is changed and the slot brushChanged() is called. This method works very similar to the penChanged() method. Source code for this method can be viewed in the example zip file.
void MainWindow::penChanged()
{
int width = 4;
Qt::PenStyle style =
penCB->itemData(penCB->currentIndex(),
Qt::UserRole).value<Qt::PenStyle>();
Qt::PenCapStyle cap = Qt::PenCapStyle::RoundCap;
Qt::PenJoinStyle join = Qt::PenJoinStyle::RoundJoin;
renderArea->setPen(QPen(Qt::blue, width, style, cap, join));
}
DrawArea Class
DrawArea::DrawArea(QWidget *parent)
: QWidget(parent)
{
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
}
void DrawArea::setPen(const QPen &newPen)
{
pen = newPen;
update();
}
void DrawArea::setBrush(const QBrush &newBrush)
{
brush = newBrush;
update();
}
void DrawArea::paintEvent(QPaintEvent *)
{
static const QVector<QPoints> points = {
QPoint(30, 240), QPoint(60, 30),
QPoint(240, 90), QPoint(270, 210)
};
QPainter painter(this);
painter.setPen(pen);
painter.setBrush(brush);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.save();
painter.translate(175, 10);
painter.drawPolygon(points.constData(), points.size());
painter.restore();
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setPen(palette().dark().color());
painter.setBrush(Qt::NoBrush);
painter.drawRect(QRect(0, 0, width()-1, height()-1));
}
The last line of the slot method MainWindow::penChanged() calls DrawArea::setPen() and the slot method MainWindow::brushChanged() calls DrawArea::setBrush(). Both setPen() and setBrush() are methods which set new values and then call QWidget::update().
The call to update() will trigger a repaint event. Since DrawArea inherits from QWidget this will call
the reimplemented paintEvent() method the DrawArea class.
Main Function
Since the source code for main() has not changed there is no need to show it again. Refer to example 3 or download the full source for this example.
Running the Example
To build and run this example use the same CMake build file and commands as we showed for the first example. The only suggested modification is on line 2 of the CMakeLists.txt file, change “example_1” to “example_32”.