QChart in a QTextDocument - c++

I want to generate a pdf report containing text and a QChart. I currently use the QTextDocument and add the chart into it as an image, then I use the QPdfWriter to export to pdf.
#include <QtGui>
#include <QtCore>
#include <QApplication>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
using namespace QtCharts;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Create a chart
QLineSeries *series = new QLineSeries();
series->append(0,0);
series->append(1,1);
QChart *chart = new QChart();
chart->addSeries(series);
chart->createDefaultAxes();
chart->axisX()->setTitleText(QString("x [m]"));
chart->axisY()->setTitleText(QString("y [m]"));
chart->setTitle("Simple chart example");
chart->resize(500,500);
// Paint the chart into an image
QImage img(500,500,QImage::Format_RGB32);
QPainter painter(&img);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
chartView->show();
chartView->render(&painter);
// Set up pdf writer
QString filename = "myfile.pdf";
QPdfWriter writer(filename);
writer.setPageSize(QPagedPaintDevice::A4);
// Create the document
QTextDocument doc;
QTextCursor cursor(&doc);
cursor.insertText(QString("some text\n"));
cursor.insertImage(img);
// Print the document
doc.print(&writer);
return a.exec();
}
Although it works, I would like to avoid converting the chart into an image because it messes up the image quality. Is there a way to do it?

Here is a workaround, if the image quality is really what matters : you can use QPainter directly on the TextDocument. It requires more work and adjustement, but the quality is not lost.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Create a chart
QLineSeries *series = new QLineSeries();
series->append(0,0);
series->append(1,1);
QChart *chart = new QChart();
chart->addSeries(series);
chart->createDefaultAxes();
chart->axisX()->setTitleText(QString("x [m]"));
chart->axisY()->setTitleText(QString("y [m]"));
chart->setTitle("Simple chart example");
chart->resize(500,500);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::TextAntialiasing);
chartView->show();
// Set up pdf writer
QString filename = "myfile.pdf";
QPdfWriter writer(filename);
writer.setPageSize(QPagedPaintDevice::A4);
// Create the document
QTextDocument doc;
QPainter painter(&writer);
QFont font = painter.font();
font.setPixelSize(200);
painter.setFont(font);
painter.drawText(QPoint(700,100),"Some text");
chartView->render(&painter);
doc.drawContents(&painter);
return a.exec();
}

Related

How to get chart view in a widget

here I get a chart result in window. I get this source code in Qt official page. And i get some number result in this program and how I get the result in a widget
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineSeries *series0 = new QLineSeries();
QLineSeries *series1 = new QLineSeries();
*series0 << QPointF(2.3,5)<<QPointF(-11,4)<<QPointF(-8,3.2)<<QPointF(-9,7.2);
QAreaSeries *series = new QAreaSeries(series0, series1);
series->setName("Area Enclosed");
QPen pen(0x059605);
pen.setWidth(2);
series->setPen(pen);
QLinearGradient gradient(QPointF(0, 10), QPointF(0, 10));
gradient.setColorAt(0.0, 0x26f626);
gradient.setColorAt(1.0, 0x26f626);
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
series->setBrush(gradient);
QChart *chart = new QChart();
chart->addSeries(series);
chart->setTitle("hello world");
chart->createDefaultAxes();
chart->axes(Qt::Horizontal).first()->setRange(-15, 15);
chart->axes(Qt::Vertical).first()->setRange(-15, 15);
chart->resize(400,400);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(600, 600);
window.show();
return a.exec();
}
how i get a result in the widget view

QLineSeries::setUseOpenGL work incorrectly with specific data

I work on Windows 10, ide - Qt Creator, compiler - Visual Studio 2017.
I am testing "LineChart Example"
https://doc.qt.io/qt-5/qtcharts-linechart-example.html#
I change data in this one. I can see a good result.
If uncomment line
//series->setUseOpenGL(true); //don'n work!
a chart is not drawn.
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QValueAxis>
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
const int count = 1495;
const double _xmin(17249.999500);
const double _xmax(17250.000500);
const double _ymin(4.0);
const double _ymax(8.0);
double _xstep((_xmax-_xmin)/count);
double _ystep((_ymax-_ymin)/count);
QValueAxis* _axisX = new QValueAxis;
QValueAxis* _axisY = new QValueAxis;
_axisX->setRange(_xmin, _xmax);
_axisY->setRange(_ymin, _ymax);
QLineSeries *series = new QLineSeries();
for(int i=0; i<count; i++) {
series->append(_xmin + _xstep*i, _ymin + _ystep*i);
}
//series->setUseOpenGL(true); //don'n work!
QChart *chart = new QChart();
chart->legend()->hide();
chart->addSeries(series);
chart->createDefaultAxes();
chart->setTitle("Simple line chart example");
chart->setAxisX(_axisX, series);
chart->setAxisY(_axisY, series);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(600, 400);
window.show();
return a.exec();
}
I did some new experiments with data. In case series->setUseOpenGL(true);
If I set
const double _xmin(17249.999500); //stairs
const double _xmax(17250.015500); //stairs
I can see the stairs instead of straight!

QPolarChart hide radial tick labels

I have created a QPolarChart and I want to hide the radial tick labels but leave the tick circles. I simply want to get rid of the text which shows "0.0", "20.0" and so on. I tried to change the label format but this did not work.
Here is a minimal example of what I tried:
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QPolarChart>
#include <QtCharts/QValueAxis>
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPolarChart *chart = new QPolarChart();
QValueAxis *angularAxis = new QValueAxis();
angularAxis->setTickCount(13);
angularAxis->setLabelFormat("%d");
angularAxis->setRange(0, 361);
chart->addAxis(angularAxis, QPolarChart::PolarOrientationAngular);
QValueAxis *radialAxis = new QValueAxis();
radialAxis->setTickCount(10);
radialAxis->setLabelFormat(""); // <-- what do I have to add here?
radialAxis->setRange(0, 90);
chart->addAxis(radialAxis, QPolarChart::PolarOrientationRadial);
chart->legend()->setVisible(false);
QLineSeries *series = new QLineSeries();
*series << QPointF(0, 0) << QPointF(90, 22.5) << QPointF(180, 45) << QPointF(270, 67.5) << QPointF(360, 90);
chart->addSeries(series);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
chart->legend()->hide();
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(400, 400);
window.show();
return a.exec();
}
This is how the result looks like.
I want to get rid of the radial axis labels ("0.0", "10.0" ... "90.0")
The trick is to set as labelFormat to " " or an invalid format like "#":
radialAxis->setLabelFormat(" ");
# or radialAxis->setLabelFormat("#");
radialAxis->setLabelsVisible(false);

Changing text color for each label in QCategoryAxis

Is there a way to assign a color for each label in a QCategoryAxis?
I know I can have a legend, but I prefer setting the colors on the axis to match the colors of the lines I have. I want to change the color of the markers (text of the categories) themselves, not the ticks. Notice that I want to set a different color for each axis label.
Tried using axisY.setLabelsBrush(QBrush(Qt::red));
But this sets the same color for all the labels.
Using Qt 5.10
the labels of QCategoryAxis are QGraphicsTextItem so they support HTML, so you could pass the color through that method:
#include <QApplication>
#include <QMainWindow>
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineSeries *series = new QLineSeries();
*series << QPointF(0, 6) << QPointF(9, 4) << QPointF(15, 20) << QPointF(25, 12) << QPointF(29, 26);
QChart *chart = new QChart();
chart->legend()->hide();
chart->addSeries(series);
QCategoryAxis *axisX = new QCategoryAxis();
QCategoryAxis *axisY = new QCategoryAxis();
// Customize axis label font
QFont labelsFont;
labelsFont.setPixelSize(12);
axisX->setLabelsFont(labelsFont);
axisY->setLabelsFont(labelsFont);
// Customize axis colors
QPen axisPen(QRgb(0xd18952));
axisPen.setWidth(2);
axisX->setLinePen(axisPen);
axisY->setLinePen(axisPen);
axisX->append("<span style=\"color: #339966;\">low</span>", 10);
axisX->append("<span style=\"color: #330066;\">optimal</span>", 20);
axisX->append("<span style=\"color: #55ff66;\">high</span>", 30);
axisX->setRange(0, 30);
axisY->append("<font color=\"red\">slow</font>", 10);
axisY->append("<font color=\"green\">med</font>", 20);
axisY->append("<span style=\"color: #ffff00;\">fast</span>", 30);
axisY->setRange(0, 30);
chart->setAxisX(axisX, series);
chart->setAxisY(axisY, series);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(400, 300);
window.show();
return a.exec();
}

Align QLabel with custom QGraphicsItem

I'm new to Qt programming and I want to align a QLabel with a custom QGraphicsItem i created. Here's inside my custom item constructor:
QGraphicsProxyWidget* pMyProxy = new QGraphicsProxyWidget(this);
QLabel *label = new QLabel();
label->setText("Some Text");
pMyProxy->setWidget(label);
label->setAlignment(Qt::AlignLeft);
the last line seems to have no effect whether its AlignLeft, Center, or Right.
myItem is a custom rectangle, and I'd like the label to be centered inside the rectangle, as it is the first word of label is being centered at the rectangle instead of the center of the label.
Please help
When you add a widget through a proxy, the proxy is the child of the initial item so its position will be relative to it and by default the position is (0, 0), so you see that although you set an alignment does not change, what you must do to place it in the center through setPos():
#include <QApplication>
#include <QGraphicsProxyWidget>
#include <QGraphicsView>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsView w;
QGraphicsScene *scene = new QGraphicsScene;
QGraphicsRectItem *item = new QGraphicsRectItem;
item->setRect(QRect(0, 0, 200, 200));
item->setBrush(Qt::red);
scene->addItem(item);
QGraphicsProxyWidget *pMyProxy = new QGraphicsProxyWidget(item);
QLabel *label = new QLabel();
label->setText("Some Text");
pMyProxy->setWidget(label);
pMyProxy->setPos(item->boundingRect().center()-label->rect().center());
w.setScene(scene);
w.show();
return a.exec();
}
Assuming this is the item, you should do the following:
QGraphicsProxyWidget *pMyProxy = new QGraphicsProxyWidget(this);
QLabel *label = new QLabel();
label->setText("Some Text");
pMyProxy->setWidget(label);
pMyProxy->setPos(boundingRect().center()-label->rect().center());
If you want to access the widget regarding the item you must follow the children tree:
QGraphiscScene
└── QGraphiscItem
    └── (children)
QGraphicsProxyWidget
   └── (widget)
QLabel
Example:
main.cpp
#include <QApplication>
#include <QGraphicsProxyWidget>
#include <QGraphicsView>
#include <QLabel>
#include <QTimer>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsView w;
QGraphicsScene *scene = new QGraphicsScene;
QGraphicsRectItem *item = new QGraphicsRectItem;
item->setRect(QRect(0, 0, 200, 200));
item->setBrush(Qt::red);
scene->addItem(item);
item->setFlag(QGraphicsItem::ItemIsSelectable, true);
item->setFlag(QGraphicsItem::ItemIsMovable, true);
QGraphicsProxyWidget *pMyProxy = new QGraphicsProxyWidget(item);
QLabel *label = new QLabel();
label->setText("Some Text");
pMyProxy->setWidget(label);
pMyProxy->setPos(item->boundingRect().center()-label->rect().center());
w.setScene(scene);
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&](){
if(!scene->selectedItems().isEmpty()){
auto *item = scene->selectedItems().first();
if(!item->childItems().isEmpty()){
auto proxy = static_cast<QGraphicsProxyWidget *>(item->childItems().first());
if(proxy){
auto label = qobject_cast<QLabel *>(proxy->widget());
if(label){
label->setText(QString("x: %1, y: %2").arg(item->pos().x()).arg(item->pos().y()));
}
}
}
}
});
timer.start(100);
w.show();
return a.exec();
}