I try to render a widget whose size is 3000x50000.
#include <QApplication>
#include <QPainter>
class widget: public QWidget{
protected:
void paintEvent(QPaintEvent *event) override{
QPainter painter(this);
painter.setPen(QPen(Qt::black, 12, Qt::DashDotLine, Qt::RoundCap));
painter.drawLine(QPoint(0,0),rect().bottomRight());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
widget wid;
wid.setGeometry(0,0,3000,500000);
QPixmap pixmap(3000,50000);
wid.render(&pixmap);
pixmap.save("PATH_TO_IMAGE");
exit(EXIT_SUCCESS);
return a.exec();
}
but in output I have this image result after 32767px image was not rendered.
Maybe you have any idea how to fix it?
The limitation comes from the internal raster paint engine (see qoutlinemapper_p.h: const int QT_RASTER_COORD_LIMIT = 32767;). Upgrade to Qt6 and use a 64bit build - then this limit is updated to 8388607 (2^23-1) pixels.
The better solution which I make is to render the widget to QImage step by step (step should be lower the 32767px) and then copy bits of QImage(usingQImage::bits()) into one buffer(QVector). And after all these steps you can create one QImage(using QImage(&buffer.first())
Related
I have in my Qt code a QLabel with a defined background color.
I would in a function to change the background color for one second only and then set it back to the original color.
I thought about using a sleep() function but is there a way to do that without blocking the rest of the program activities ?
Thanks!
You have to use a QTimer::singleShot(...) and QPalette:
#include <QApplication>
#include <QLabel>
#include <QTimer>
class Label: public QLabel{
public:
using QLabel::QLabel;
void changeBackgroundColor(const QColor & color){
QPalette pal = palette();
pal.setColor(QPalette::Window, color);
setPalette(pal);
}
void changeBackgroundColorWithTimer(const QColor & color, int timeout=1000){
QColor defaultColor = palette().color(QPalette::Window);
changeBackgroundColor(color);
QTimer::singleShot(timeout, [this, defaultColor](){
changeBackgroundColor(defaultColor);
});
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Label label;
label.setText("Hello World");
label.show();
label.changeBackgroundColorWithTimer(Qt::green, 2000);
return a.exec();
}
Maybe you can use QTimer to wait a second. Use timer->start(1000) to wait a second and create a SLOT in your class that recive the Qtimer::timeOut signal to changeback the label background color.
Bellow you can see minimal example code to demonstrate problem.
If you run it and give focus to QLineEdit, you get output every second: paintEvent, paintEvent and so on.
I can not understand why MyW::paintEvent called on every
cursor blinking in child widget? As you see I do not configure QLineEdit,
by default on my linux box it have no transparent elements,
but still for some reason cursor cause all widgets to redraw their content?
#include <QApplication>
#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QLineEdit>
class MyW final : public QWidget {
public:
MyW() {
//setAutoFillBackground(false);
}
void paintEvent(QPaintEvent *e) {
e->accept();
qDebug("paintEvent");
QPainter painter{this};
painter.fillRect(rect(), Qt::green);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyW w;
w.resize(600, 600);
w.show();
auto le = new QLineEdit{&w};
le->show();
return app.exec();
}
I'm trying to generate pixmaps with the following code
QList<QPixmap> pixmapList;
for (int i=0;i<50;++i){
QPixmap pixmap = QPixmap(10050,10050);
pixmap.fill(Qt::transparent);
pixmapList<<pixmap;
}
The above part works find. And I would like to paint on those pixmaps later, e.g.
QPixmap pixmap = pixmapList[10];
QPainter painter(&pixmap);
painter.drawPixmap(....); // this pixmap is 10*10
pixmapList[10]=pixmap;
or
QPainter painter(&pixmapList[10]);
painter.drawPixmap(....); // this pixmap is 10*10
but they both gave me "QPainter::begin: Paint device returned engine == 0, type: 2". May I ask the right way to paint on pixmaps in the pixmapList? Thanks very much!
Your code is OK, except that the pixmaps are too big (they occupy ~400MBytes each).
After making the pixmaps smaller, it works fine (shown for Qt 5):
#include <QGuiApplication>
#include <QPixmap>
#include <QPainter>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QList<QPixmap> pixmapList;
for (int i=0;i<50;++i){
QPixmap pixmap = QPixmap(1000,1000);
pixmap.fill(Qt::transparent);
pixmapList<<pixmap;
}
QPainter painter(&pixmapList[10]);
painter.drawLine(0, 0, 100, 100);
return 0;
}
I acquire images from a camera by using a SDK which returns the data in an unsigned char array. However this SDK doesn't offer functionality to display the data, so I tried to implement this by using Qt 4.8 under Ubuntu 12.04.
At the moment my code looks like this:
#include <QtGui/QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
QGraphicsView view(&scene);
while (..) // condition which breaks after a number of images where grabbed
{
// Get the image from the third party SDK into an unsigned char array
// named pImageBuffer
QImage image ((unsigned char *) pImageBuffer,
GetWidth(),
GetHeight(),
QImage::Format_Indexed8);
QVector<QRgb> colorTable(256);
for(int i=0;i<256;i++)
colorTable[i] = qRgb(i,i,i);
image.setColorTable(colorTable);
QPixmap pixmap = QPixmap::fromImage(image);
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
scene.addItem(item);
view.show();
a.exec();
}
}
This works like expected, the images are displayed properly. However a.exec() blocks the main thread until I close the QtWindow.
Is there any easy way to modify this, so the window stays open all the time and just updates the displayed image? Performance doesn't matter at all at the moment, but I need to keep the code simple.
While a call to QApplication::processEvents will work, it's just a hack and not the best solution.
Ideally the image grabber should run on a separate thread as an object derived from QObect. This object emits signals of the images that it receives, which are received by an object on the main thread.
The receiving object can then set the image on the QGraphicsPixmapItem object.
Note that the code in the question creates a new QGraphicsPixmapItem for every image that is received from the grabber. Assuming you're wanting to create an animated image, you should only be creating and adding a single QGraphicsPixmapItem to the scene.
Using QThread is very easy and if you've not done it before, I suggest you read this article, which clearly explains what to do, with example code.
class ImageGrabber
{
Q_OBJECT
public:
ImageGrabber(QPixmapItem* item) : _item(item)
{
connect( &timer, SIGNAL(timeout()), this, SLOT(grabImage()) )
_timer.start(33); // 33 ms between timeouts.
}
public slots:
void grabImage()
{
// Update image
QImage image(...);
_item->setPixmap( QPixmap::fromImage(image) );
}
private:
QPixmapItem* _item;
QTimer _timer;
};
int main(...)
{
QApplication a(argc,argv);
...
view.show();
QGraphicsPixmapItem* pixmapItem = scene.addPixmap(QPixmap());
ImageGrabber ig(pixmapItem);
return a.exec();
}
I want to animate small (100x20) image by changing the color of its pixels by the same value. For example, increase red-channel value by 1 every frame and then decrease back. The image has alpha channel, the animation speed is 30...100 fps (platform dependent; 30 is enough for linux, but windows requires ~70 to look smooth).
As i know, drawing is faster when done in QImage, but displaying is faster with QPixmap.
I like QGraphicsEffects, and QPropertyAnimations. White doesn't colorize, but black does.
#include <QLabel>
#include <QPixmap>
#include <QGraphicsColorizeEffect>
#include <QTimerEvent>
#include <QPropertyAnimation>
#include <QShowEvent>
#include <QDebug>
class Widget : public QLabel
{
Q_OBJECT
Q_PROPERTY(qreal redness READ getRedness WRITE setRedness)
public:
Widget(QWidget *parent = 0)
{
QPixmap p(300, 300);
p.fill(Qt::black);
this->setPixmap(p);
colorize = new QGraphicsColorizeEffect();
colorize->setColor(Qt::red);
redness = 0;
colorize->setStrength(redness);
this->setGraphicsEffect(colorize);
animation = new QPropertyAnimation(this,"redness");
animation->setDuration(2000);
animation->setLoopCount(10);
animation->setStartValue(0.0);
animation->setEndValue(1.0);
animation->setEasingCurve(QEasingCurve::CosineCurve);
animation->start();
}
~Widget(){}
qreal getRedness()
{
return redness;
}
void setRedness(qreal val)
{
redness = val;
colorize->setStrength(redness);
this->update();
// qDebug() << redness;
}
public slots:
void showEvent(QShowEvent *)
{
animation->start();
}
private:
qreal redness;
QGraphicsColorizeEffect * colorize;
QPropertyAnimation * animation;
};
and here is the main.cpp
#include <QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Hope that helps.