Implement paintSection for QHeaderView delivered class - qt

protected:
virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->drawRect(2, 2, 10, 10);
}
Rectangle is not painting. But when paintSection removed it is painting. I need to draw rectangle after call base paintSection.

As it was answered in this your question, rect is an area your should paint at.
If you paint outside of this area your drawings might be erased by painting of other cells.
So use rect to draw a rect:
painter->drawRect(rect.adjusted(2, 2, -2 , -2));

You need to protect the painter across the call to super, which modifies it. Try this:
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
Also, as Ezee noted, you should be using the rect passed in as the basis for the coordinates you draw at; as suggested in that answer, something like:
painter->drawRect(rect.adjusted(2, 2, -2 , -2));

Related

Drawing thousands of rects quickly

What is the proper way to draw thousands of rects in QT (around 100,000 or more)?
I tried:
Simple with paintEvent() of QWidget.
Drawing objects to QImage then this image to QWidget.
Using QGraphicsScene (maybe I didn't use it properly, I just added rects to scene)
Every time drawing was really slow and I don't have more ideas on how to do this (maybe with opengl/directx but this doesn't sound like a good idea). I know that there exist applications that do that so there should be some way.
EDIT:
I wonder how drawRects() work? Is there a chance that filling some uchar* array and passing it to QImage will be better?
The first trick is to do the drawing in a separate thread onto a QImage, then pass that into the main thread. This won't make it quicker, but it'll make it not block the GUI thread.
// https://github.com/KubaO/stackoverflown/tree/master/questions/threaded-paint-36748972
#include <QtWidgets>
#include <QtConcurrent>
class Widget : public QWidget {
Q_OBJECT
QImage m_image;
bool m_pendingRender { false };
Q_SIGNAL void hasNewRender(const QImage &);
// Must be thread-safe, we can't access the widget directly!
void paint() {
QImage image{2048, 2048, QImage::Format_ARGB32_Premultiplied};
image.fill(Qt::white);
QPainter p(&image);
for (int i = 0; i < 100000; ++i) {
QColor c{rand() % 256, rand() % 256, rand() % 256};
p.setBrush(c);
p.setPen(c);
p.drawRect(rand() % 2048, rand() % 2048, rand() % 100, rand() % 100);
}
emit hasNewRender(image);
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(0, 0, m_image);
}
public:
Widget(QWidget * parent = 0) : QWidget(parent) {
this->setAttribute(Qt::WA_OpaquePaintEvent);
setMinimumSize(200, 200);
connect(this, &Widget::hasNewRender, this, [this](const QImage & img) {
m_image = img;
m_pendingRender = false;
update();
});
refresh();
}
Q_SLOT void refresh() {
if (!m_pendingRender) {
m_pendingRender = true;
QtConcurrent::run([this] { paint(); });
}
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Widget w;
QPushButton button{"Refresh", &w};
button.connect(&button, &QPushButton::clicked, &w, [&w]{ w.refresh(); });
w.show();
return app.exec();
}
#include "main.moc"
As a separate concern, you can then split the drawing across multiple parallel jobs, by clipping each job's painter to a sub-area of the shared image, and noting that fully clipped rectangle draws are no-ops, and partially clipped ones will only fill the pixels they affect.
Solution which I found:
Create array of uint32_t which can contain all pixels of widget, fill it using memcpy(). Create QImage with this array and use drawImage() to show it.
It can have some optimization like (for profiler) merging rects that are continues ( start time second is equal to end of first ). Don't draw rects that are out of time bounds. Maybe skip too small rects.
For drawing things like text, tool tips you can still use Qt functions.
For alpha blending in simplest case you can just take existing values, blend them in loop and write blended values or maybe use SIMD for this.
Of course for more complex shapes it will get harder to draw but still, I think, it will be faster than using Qt functions.

Qt: How to draw a QRect on top of a QGraphicsVideoItem?

I have a subclass of a QGraphicsObject. In this class, I use a QMediaPlayer with a QGraphicsVideoItem to play a video. I am trying to draw on top of the video.
class MyClass : public QGraphicsObject
{
Q_OBJECT;
public slots:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
public:
QGraphicsVideoItem *_movie_item;
QMediaPlayer *_movie_player;
}
In the paint method, I want to draw a red rectangle on top of _movie_item. To try to do this, I call:
void MyClass::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
_movie_item->setVisible(true);
_movie_item->play();
painter->fillRect(startx, starty, size, size, Qt::red);
}
The red rectangle gets drawn in the appropriate place, but it is always underneath the _movie_item.
Is there a way to draw a rectangle on top of the _movie_item without creating another QGraphicsItem, like:
QGraphicsRectItem *_rect = new QGraphicsRectItem(_movie_item)
Thanks.
Using QGraphicsItem::ItemStacksBehindParent flag may help.
From the docs:
The item is stacked behind its parent. By default, child items are
stacked on top of the parent item. But setting this flag, the child
will be stacked behind it. This flag is useful for drop shadow effects
and for decoration objects that follow the parent item's geometry
without drawing on top of it. This flag was introduced in Qt 4.5.
_movie_item->setFlag(QGraphicsItem::ItemStacksBehindParent);

Change QGraphicsItem's local Co-Ordinate system to make origin at (0,0)

I have a QGraphicsView and a QGraphicsScene called scene with scene->setSceneRect(0,0,600, 600).
I have created a simple custom QGraphicsItem called background with boundingRectangle(0,0,600,600).
Very clearly the center of the background item is (300,300) with minX=0, minY=0 and maxX=600, maxY=600...but I want the center of this background item to be (0,0) with minX=-300, minY=-300 and origin at(0,0) and maxX=300, maxY=300.
In other words I want the background items local co-ordinates system to reflect the natural co-ordinate system that we draw on paper.
(source: shmoop.com)
How do I do this.
If you have a custom QGraphcisItem you're in charge of the painting as well as the geometry. So you may paint the rectangle as top left (-300,-300) and bottom right (300,300) as long as you make sure you return a matching bounding rectangle by overriding and implementing QGraphicsItem::boundingRect().
Here's an example from the Qt documentation:
class SimpleItem : public QGraphicsItem
{
public:
QRectF boundingRect() const
{
qreal penWidth = 1;
return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
20 + penWidth, 20 + penWidth);
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
painter->drawRoundedRect(-10, -10, 20, 20, 5, 5);
}
};

setpixel of QGraphicsScene in Qt

It's simple to draw line or ellipse just by using scene.addellipse(), etc.
QGraphicsScene scene(0,0,800,600);
QGraphicsView view(&scene);
scene.addText("Hello, world!");
QPen pen(Qt::green);
scene.addLine(0,0,200,200,pen);
scene.addEllipse(400,300,100,100,pen);
view.show();
now what should i do to set some pixel color? may i use a widget like qimage? by the way performance is an issue for me.thanks
I think that performing pixel manipulation on a QImage would slow down your application quite a lot. A good alternative is to subclasse QGraphicsItem in a new class, something like QGraphicsPixelItem, and implement the paint function like this:
// code untested
void QGraphicsPixelItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0)
{
painter->save();
foreach(const QPoint& p, pointList) {
// set your pen color etc.
painter->drawPoint(p);
}
painter->restore();
}
where pointList is some kind of container that you use to store the position of the pixels you want to draw.

Qt4 How to draw inside a widget?

Qt4, QtCreator
I am trying to draw inside Widget:
void Widget::on_pushButton_clicked()
{
QPainter painter;
painter.begin(ui->label);
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
painter.drawArc(rectangle, startAngle, spanAngle);
painter.end();
}
But when I press button nothing happens.
How to do this right way?
You need to override paintEvent() and do your painting there. You don't really need the begin() and end(). Declare the painter with
QPainter painter(this);
The constructor will handle begin(), and end() will be called when the painter object goes out of scope and is destroyed.
You also won't need the click event to trigger the painting. paintEvent() will be called whenever the widget needs to draw itself. You could use the the button click to toggle a boolean that the paintEvent() checks to determine whether or not it should display the rectangle and arc. Just make sure you call update() after you toggle the variable.
void Widget::on_pushButton_clicked()
{
drawShapes = !drawShapes;
update();
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
if(drawShapes)
{
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
painter.drawArc(rectangle, startAngle, spanAngle);
}
}
UPDATE:
To avoid having to override the paintEvent() of a widget, you could use a QLabel and assign a pixmap to it and paint to that. Note: As far as I can tell, you will need to set the pixmap each time you modify it.
void MainForm::slot_buttonClick()
{
QPixmap pixmap(100,100);
pixmap.fill(QColor("transparent"));
QPainter painter(&pixmap);
painter.setBrush(QBrush(Qt::black));
painter.drawRect(10, 10, 100, 100);
label.setPixmap(pixmap);
}
If you overwrite the paint-method as described by Arnold Spence, you should call the parent's paintEvent or you end up with a widget that only shows your rectangle on a white background.

Resources