QtChart - C++ - Saving a chart which wasn't displayed - c++

I'm trying to save a chart to a file, in a QTextDocument in this example :
QTextDocument doc("Frame rate test\n");
QTextCursor cursor(&doc);
cursor.movePosition(QTextCursor::End);
if (getTestFinishedStatus())
{
QPixmap pix = _pFrameRateChart->grab(); //_pFrameRateChart is QChartView
cursor.insertImage(pix.toImage());
}
QTextDocumentWriter docWriter;
docWriter.setFileName("framerate.odf");
docWriter.setFormat("ODF");
docWriter.write(&doc);
The problem is the result isn't same if I'm displaying the chart in an ui.
Here is the result when not displayed :
Here is the result when displayed :
Obviously I would like to have the second result even when I don't add the ChartView to a widget to display it on an ui.
I've tried resizing the QChartView, resizing the QChart, adding the Chart to a temporarly widget and QVBoxLayout then saving it, showing temporarly the QChartView before saving it etc... but didn't managed to get a good result.

I use the following code to render a QGraphivsView on a Pixmap, since QtCharts is based on QGraphivsView, I think this will also work.
Try to render the image instead of trying to grab the pixmap.
void Printer::putProfileImage(QRect profilePlaceholder, QRect viewPort, QPainter *painter, QGraphivsView* profile)
{
int x = profilePlaceholder.x() - viewPort.x();
int y = profilePlaceholder.y() - viewPort.y();
QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height());
profile->render(painter, pos);
}

I didn't find any easy way to this, so here's my solution, which is more like a workaround though :
QPixmap ChartView::getChartPixmap()
{
QWidget* w = new QWidget; //creating a temporary widget, which will enable to display the chart
w->resize(REPORT_IMAGE_WIDTH, REPORT_IMAGE_HEIGHT);
QVBoxLayout *vl;
vl = new QVBoxLayout(w);
vl->addWidget(this); //'this' being the QChartView
w->show(); //showing the widget so it is resized and can be grabbed with the correct dimensions
QTest::qWait(500); //we need to wait for a little for the graph to be drawn otherwise you'll still have the same size problem
QPixmap pixmap = w->grab(); //retrieve the pixmap
w->hide(); //hiding the widget
return pixmap;
}
It's working but you'll have a small window opened with the graph for 500 ms.

Related

How do I grab a QPixmap of a QtDataVizualisation in a QWidget and save to file?

I am trying to make a 3D scatter plot using QtDataVisualizationQ3DScatter and then to take a QPixmap of that and save to file.
Here is my code.
//set up the 3D scatter chart
QtDataVisualization::Q3DScatter *graph = new QtDataVisualization::Q3DScatter();
QWidget *widget = QWidget::createWindowContainer(graph);
QtDataVisualization::QScatter3DSeries *series = new QtDataVisualization::QScatter3DSeries;
//set up the data variable
QtDataVisualization::QScatterDataArray data;
//add data to the data variable
for (int i; i < nodes.size(); i = i + 1)
{
data << QVector3D(x[i], y[i], z[i]);
}
//add the data to series
series->dataProxy()->addItems(data);
//add series to graph
graph->addSeries(series);
//set the graph properties
graph->activeTheme()->setType(QtDataVisualization::Q3DTheme::ThemeArmyBlue);
graph->scene()->activeCamera()->setCameraPreset(QtDataVisualization::Q3DCamera::CameraPresetIsometricRight);
graph->seriesList().at(0)->setMesh(QtDataVisualization::QAbstract3DSeries::MeshPoint);
graph->setShadowQuality(QtDataVisualization::QAbstract3DGraph::ShadowQuality(0));
//widget->show();
const QRect rectangle(0,0,widget->width(),widget->height());
QPixmap test = widget->grab(rectangle);
test.save(QString(workingDirectory) + "/test.png", "PNG");
When I uncomment the "widget->show()", the test.png is just a white square but the widget comes up and shows the full 3DScatter. When I comment out the "widget->show()", test.png is still just a white square. I can't seem to get this to work.
When commenting widget->show(), add a widget->repaint() call to force the widget to be painted/rendered before saving it in the file.
I realise this question is quite old but for anyone who's interested:
QAbstract3DGraph has a function renderToImage. This is inherited by Q3DScatter.
You should be able to grab a qimage of your scene using:
QImage myImage = graph->renderToImage();
and then convert this to a pixmap:
QPixmap p;
p.convertFromImage(myImage);

How do I prevent QListView in QGraphicsScene from drawing outside scroll area when scaling with QT_SCALE_FACTOR

When I display a QListWidget or QListView in a QGraphicsScene the text for each item is drawn outside of the widget boundaries if scroll bars are necessary. This only occurs when I use QT_SCALE_FACTOR to scale the application. Is there a way to prevent the list widget/list view items from being displayed outside the scroll area without explicitly setting a width for the items? If I set the width I lose some of the text. I have also tried setting the GraphicsItemFlag QGraphicsItem::ItemClipsToShape. This keeps the overhang restricted to the width of the outer widget but I want to prevent overhang entirely.
QListWidget in QGraphicsScene
QWidget *w = new QWidget();
QVBoxLayout *l = new QVBoxLayout(w);
lw = new QListWidget();
l->addWidget(lw);
QGraphicsProxyWidget *pw = scene()->addWidget(w);
pw->resize(200,300);
for(int i = 0; i < 25; i++) {
QListWidgetItem *litem = new QListWidgetItem("Text text text text text text text");
lw->insertItem(0, litem);
}
Setting the cache mode to QGraphicsItem::DeviceCoordinateCache prevents the listview/listwidget text from displaying outside the boundaries of the widget. The text does become a little blurry but the user can still read it. Thank you harism for your response!
pw->setCacheMode(QGraphicsItem::DeviceCoordinateCache);

Rounded icon on Qpushbutton

I have a QPushButton to which I want to add an icon (that I add to the button by using QPushButton::setIcon()) with rounded corners. However I have a pixmap which is a square image. Is it possible to adapt the pixmap in such a way that it becomes rounded?
I have found the setMask() function on the QPixmap, which I can maybe use. But how would I make a bitmap that masks the edges of my QPixmap?
Or is there a better way for this?
This is how you can prepare a QPixmap with rounded corners:
const QPixmap orig = QPixmap("path to your image");
// getting size if the original picture is not square
int size = qMax(orig.width(), orig.height());
// creating a new transparent pixmap with equal sides
QPixmap rounded = QPixmap(size, size);
rounded.fill(Qt::transparent);
// creating circle clip area
QPainterPath path;
path.addEllipse(rounded.rect());
QPainter painter(&rounded);
painter.setClipPath(path);
// filling rounded area if needed
painter.fillRect(rounded.rect(), Qt::black);
// getting offsets if the original picture is not square
int x = qAbs(orig.width() - size) / 2;
int y = qAbs(orig.height() - size) / 2;
painter.drawPixmap(x, y, orig.width(), orig.height(), orig);
Then you can use the resulting pixmap to set a QPushButton icon:
QPushButton *button = new QPushButton(this);
button->setText("My button");
button->setIcon(QIcon(rounded));
And of course you have a second option to use some image editor to prepare images with rounded corners beforehand.

Qt setGeometry to negative value doesn't work

Im working with QT and I have a form with a QLabel in a QFrame. I want to set the QLabel's geometry so the bottom part of the QLabel is in the same place of the bottom of the frame. Since the label is longer than the frame, it's y coordinate should be negative.
int pos = ui->imageFrame->height() - ui->imageLabel->pixmap()->height();
ui->imageLabel->setGeometry(0, pos, ui->imageFrame->width(), p.height());
Although when printing the QLabel's geometry, the y coordinate is correct, the label is showing on the upper part of the frame.
Help is much appreciated.
You can set the label's alignment with setAlignment. Here's a working example:
#include <QtWidgets>
#include "MyWidget.h"
MyWidget::MyWidget()
{
setFixedSize(200,200);
QLabel *label = new QLabel;
label->setPixmap(QPixmap("/some/image/file.jpg"));
label->setAlignment(Qt::AlignBottom);
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(label);
hbox->setContentsMargins(0,0,0,0);
setLayout(hbox);
}

Resizing a QPixmap inside a QLabel according to the Window

In my window class, inheriting of QMainWindow, I have a QLabel containing a QPixmap, updated every 20ms.
I want the QLabel, and the QPixmap inside it, to be resized according to the resizing of the window.
I want this Central Widget to take as much space as neccessary but also to be able to resize it down. Even smalled than the original size. But always keeping the ratio.
The actual code :
// in the window constructor
this->setWindowFlags(Qt::Window);
this->resize(500, 300);
this->setCentralWidget(this->label);
// in the updating function
QPixmap output;
output = output.fromImage(Mat2QImage(theImage));
this->label->setPixmap(output);
Now I've tried with :
output.scaled(this->label->x(), this->label->y(), Qt::KeepAspectRatio)
but it doesn't work ...
How can I do that ?
EDIT : I'm using Qt 5.3
QPixmap::scaled is const. Next code doesn't work:
// in the window constructor
this->setCentralWidget(this->label);
// in the updating function
QPixmap output;
output = output.fromImage(Mat2QImage(theImage));
output.scaled( this->label->x(), this->label->y(), Qt::KeepAspectRatio );
this->label->setPixmap(output);
Because output doesn't change. Maybe you need something like this:
// in the window constructor
this->setCentralWidget(this->label);
// in the updating function
QPixmap output;
output = output.fromImage(Mat2QImage(theImage));
output = output.scaled( this->label->x(), this->label->y(), Qt::KeepAspectRatio );
this->label->setPixmap(output);
Try puting your QLabel inside a Layout.
hl = new QHBoxLayout;
hl->addWidget(label);
centralWidget()->setLayout(hl);
check this out: http://qt-project.org/doc/qt-4.8/layout.html