How to draw a Image in child's view through paintEvent - c++

I'm a Chinese and poor in English,so I show the code to express myself.
class Widget:public QWidget
{
private:
//As a child object of Widget object
QLabel* label;
};
// Override the paintEvent
void Widget::paintEvent(QPaintEvent* event)
{
//How to draw a picture in the QLabel not in the full Widget's view,thx!!
}

First, you need to initialize your label in constructor, add something like this:
void Widget::Widget()
{
label=new QLabel(this);
}
and then your paintEvent do something like this -
void Widget::paintEvent(QPaintEvent* event)
{
// create QPixmap or QImage object or how else you store it and load it to label
QImage img("./myimage.jpg");
label->setPixmap(img.pixmap());
}
and it will be drawn on tha label, but by default label has growing sizePolicy - it will be resized to fill as many space as possibly if your widget doesn't have any other objects - your label will take the whole space, so it will be good to add your QLabel to some of the layouts (QGridLayout) and you need to setSizePolicy of your QLabel to QSizePolicy::Maximum

Related

How to draw when holding down the mouse button?

I am trying to create a simple painting application - it is just supposed to draw when you click and drag a cursor (just like Paint). I know I have to use QPainter but how can I handle it? How to do it? Any help would be really appreciated. I tried lurking through internet but didn't find too much info (I daw drawing lines etc. by code that you launch an app and it is here but I can not find an example of drawing something by user).
Here's Jeremy's answer in code instead of prose:
// https://github.com/KubaO/stackoverflown/tree/master/questions/simplepaint-39358392
#include <QtWidgets>
// Make a subclass of the QWidget class, so that you can override some of its
// virtual methods
class PaintWidget : public QWidget {
// Create a QPixmap object that you will use to store the bitmap
// that the user will draw [on].
QPixmap m_pixmap;
QPoint m_lastPos;
// Override the paintEvent(QPaintEvent *) [...]
void paintEvent(QPaintEvent *) override {
QPainter painter{this};
painter.drawPixmap(0, 0, m_pixmap);
}
void resizeEvent(QResizeEvent *) override {
// [...] size the QPixmap to be at least as big as the maximum size of the window
// We'll also never let it shrink so as not to lose the already drawn image.
auto newRect = m_pixmap.rect().united(rect());
if (newRect == m_pixmap.rect()) return;
QPixmap newPixmap{newRect.size()};
QPainter painter{&newPixmap};
painter.fillRect(newPixmap.rect(), Qt::white);
painter.drawPixmap(0, 0, m_pixmap);
m_pixmap = newPixmap;
}
// Override the mousePressEvent(QMouseEvent *) [...]
void mousePressEvent(QMouseEvent * ev) override {
m_lastPos = ev->pos();
draw(ev->pos());
}
// Override the mouseMoveEvent(QMouseEvent *) [...]
void mouseMoveEvent(QMouseEvent * ev) override {
draw(ev->pos());
}
void draw(const QPoint & pos) {
QPainter painter{&m_pixmap};
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen({Qt::blue, 2.0});
painter.drawLine(m_lastPos, pos);
m_lastPos = pos;
update();
}
public:
using QWidget::QWidget;
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
// Create an object of your subclass and call show()
PaintWidget ui;
ui.show();
return app.exec();
}
It is not necessary to override the mouseReleaseEvent. In a widget, the default behavior is to track the mouse movement only when a mouse button is depressed. The mouseMoveEvent won't be called unless a button is depressed.
It's a pretty broad question, but here are the basics:
Make a subclass of the QWidget class, so that you can override some of its virtual methods later on.
Create an object of your subclass and call show() on it (just before calling QApplication::exec()). This object will appear on screen as a very simple window, and it will serve as your user's painting-surface.
Create a QPixmap object that you will use to store the bitmap that the user will draw. Make sure to size the QPixmap to be at least as big as the maximum size of the window that you want to support. Call fill() on the QPixmap to fill it with your favorite background color.
Override the mousePressEvent(QMouseEvent *) method of your object to set a boolean is_mouse_down flag, and also to record the current position of the mouse pointer within the window (by calling pos() on the QMouseEvent object that gets passed in to the mousePressEvent() call and storing that into a member variable of your object).
Override the mouseMoveEvent(QMouseEvent *) method so that if is_mouse_down_is set to true, it creates a QPainter object on the stack -- pass a pointer to the QPixmap to the QPainter object's constructor so that the QPainter will draw into your QPixmap object. Then call drawLine() on the QPainter object to draw a line from the previous mouse position to your current one. Finally, call update() to tell Qt to call paintEvent() for you ASAP.
Override the mouseReleaseEvent(QMouseEvent *) method to set is_mouse_down to false again
Override the paintEvent(QPaintEvent *) method to create a QPainter object on the stack -- pass a pointer to (this) to the QPainter object's constructor, so that it will paint onto the QWidget directly. Then call drawPixmap() on the QPainter object so that it will draw your QPixmap object onto the widget's visible surface.
If you'd like to see a pre-written example, check out the Scribble application included with Qt, in $QTDIR/examples/widgets/widgets/scribble.

App crash when using QPainter on QPixmap

I am trying to make a class that will make a dot graphic. The class inherits from QWidget. I want it to draw lines and dots on a QPixmap that will be displayed in a QLabel.
The constructor of the class looks like this:
MyClass::MyClass()
{
calcul_proprietes(); // Function that makes calculation of what to draw.
pix = new QPixmap(760,350);
dessiner_graphique(); // Function that does the drawing.
//Displaying the qpixmap
layout_principal = new QVBoxLayout(this);
label_pix = new QLabel(this);
label_pix->setPixmap(*pix);
layout_principal->addWidget(label_pix);
this->setLayout(layout_principal);
}
And a short part of the function that does the drawing
void MyClass::dessiner_graphique()
{
// ...
QPainter painter(pix);
QRect contour(x_depart,y_depart,largeur_grille,hauteur_grille);
painter.drawRect(contour);
// ...
}
I don't want to use the paintEvent function because it gets called all the time and i only need my graphic to be painted once. What do i do wrong?
Did you call the default base class constructor before Your class constructor ?
MyClass( QObject *parent )
: QWidget( parent )
{
// Your posted code.
}

Paint over top of label, not behind it in Qt

I am creating a simple gauge in Qt 4.7.4, and everything is working wonderfully. Except for the fact that, for the life of me, I cannot get the dial shape to paint over the text labels when it passes over them. It always paints it behind the label. I am just using a simple drawpolygon() method.
I'm thinking this has something to do about paint events? I am drawing everything inside a QFrame inside a MainWindow. I am using QFrame's paintEvent.
Edit:
The QLabels are created on start up with new QLabel(this). They are only created once, and never touched again ( Similar to manually adding them on the Ui with Designer). The drawpolygon() is in the QFrame's Paint event.
"myclass.h"
class gauge : public QFrame
{
Q_OBJECT
public:
explicit gauge(QWidget *parent = 0);
~gauge();
void setValues(int req, int Limit, bool extra=false);
private:
void drawDial();
protected:
void paintEvent(QPaintEvent *e);
};
"myclass.cpp"
void gauge::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
drawDial();
return;
}
void gauge::drawDial()
{
QPainter Needle(this);
Needle.save();
Needle.setRenderHint(Needle.Antialiasing, true); // Needle was Staggered looking, This will make it smooth
Needle.translate(centrePt); // Center of Widget
Needle.drawEllipse(QPoint(0,0),10,10);
Needle.restore();
Needle.end();
}
If the gauge widget and the QLabels are siblings, then you can move the gauge widget to the front by calling its raise() method.
If the QLabels are children of the gauge widget, on the other hand, then they will always display in front of it. In that case you can either reorganize your widget hierarchy so that they are siblings instead, or you can get rid of the QLabels and simply call drawText() from your paintEvent() method instead (after drawDial() returns)

Draw on custom widget after it's drawing

I have a custom widget, which inherits QWidget. It has own paintEvent and I cannot change it. So I want to use such a widget in my dialog object, but I need to draw some graphics on it after it draws its own graphics (that widget draws video frames on it, an I need to draw some lines over it). Can I draw every time after the paintEvent of that widget? I used installEventFilter and caught the event wuth type Qt::Paint, but I canoont see anything I've drown. Is there any other way?
You can derive from the custom widget class, reimplement paintEvent, and call the inherited paintEvent first, then do your drawing.
You can install an event filter on the widget and do the same: call the widget's paintEvent first, then do your drawing.
Hide the other widget. Create your own widget, and call the other widget's render method in your widget's paintEvent, then do your drawing. Since the other widget is presumably rendering video frames that change periodically over time, you might need to use a timer to update() your widget.
In neither case are you modifying the 3rd party custom widget.
In order to call other widget's protected paintEvent you need to be using a QWidget, even if just a dummy, invisible one.
This is a very simple code sample that draw inside a custom widget. It draws a blue rectangle inside of a QPushButton.
The method used is exactly what has been described in option 1 by #Kuba
So, you inherit from the custom widget class where you want to draw in, reimplement paintEvent, and call the inherited paintEvent first and the do your drawing.
Hope this helps
#include <QApplication>
#include <QPushButton>
#include <QPainter>
#include <QPaintEvent>
// inherit from the class over which you want to draw
class DrawOverButton : public QPushButton
{
Q_OBJECT
public:
DrawOverButton(const QString &text, QWidget *parent = 0) :
QPushButton(text, parent)
{
// enlarge the button so there is some space to draw in
setStyleSheet("QPushButton {min-height: 60px; "
"min-width: 120px; margin: 5px;}");
}
protected:
virtual void paintEvent(QPaintEvent *event) {
// call the base class paint event method
// this will draw the base class content
QPushButton::paintEvent(event);
// draw a blue border inside the button
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor("#3cf"), 4));
const int distance = 20;
painter.drawRoundedRect(QRect(distance, distance,
width() - 2 * distance, height() - 2 * distance),
10, 10);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DrawOverButton *button = new DrawOverButton("Button");
button->show();
return a.exec();
}
#include "main.moc"

How do I place the QScrollBar on the content of the QScrollArea?

I want to make a scrollbar that fades in and out depending on usage. I subclassed QScrollBar and got the look that I want. The problem is that the scrollbar is placed next to the content. How do I instead make it go on top of the content?
I created a new QScrollbar which I connected to the original via signals and then used widget->setParent and then widget->setGeometry() to paint it on top
I quicker solution is to reparent the QScrollBars that the QScrollArea creates and add it to a new QLayout to position it how you want.
QScrollArea *scrollArea = new QScrollArea();
QScrollBar *scrollBar = scrollArea->horizontalScrollBar();
scrollBar->setParent(scrollArea);
scrollBar->setFixedHeight(20);//required for later
QVBoxLayout *scrollAreaLayout = new QVBoxLayout(scrollArea);
scrollAreaLayout->setContentsMargins(0, 0, 0, 10);//use whatever margins you want
scrollAreaLayout->addStretch(1);
scrollAreaLayout->addWidget(scrollBar);
This gets the basic functionality working, however the QScrollArea still adds space where the scrollbar would have been. To remove this, subclass QProxyStyle and override pixelMetric().
#include <QProxyStyle>
class StyleFixes : public QProxyStyle
{
public:
int pixelMetric(PixelMetric metric, const QStyleOption *option = Q_NULLPTR, const QWidget *widget = Q_NULLPTR) const override
{
if(metric == PM_ScrollBarExtent)
{
return 0;
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
};
Then just apply it in main.cpp
QApplication::setStyle(new StyleFixes);
This will remove the arrows on the scrollbar however so you'll need to style it yourself.