Qt Charts Bar Plot Resize Crash - c++

Situation:
I wrote a bar plot using QtCharts, QChartView, QChart, QBarSeries, QBarSet, QValueAxis and QCategoryAxis and it works fine.
Problem:
When i resize the window or use QRubberbandon the plot, it crashes.
What i tried:
Every other plot i wrote is not affected by that problem, including the ones using QStackedBarSeries. The Problem also occured in another program i wrote in the same situation.
Code - Head:
int D_Plot::Plot_Stat_Multi_MeanMedian(
QChartView *pChartView,
vector<vector<double> > *vv_SetSta,
bool pl_mean,
bool pl_sd,
bool pl_median,
bool pl_adm,
QString name_title,
QString name_categories,
QString name_y)
Code - Body:
//Chart
QChart *chart = new QChart();
chart->setTitle(name_title);
//Sets
QBarSet set_mean("Mean");
QBarSet set_sdev("Standard Deviation");
QBarSet set_medi("Median");
QBarSet set_aadm("Average Absolute Deviation from Median");
//Categories
QStringList categories;
//Series
QBarSeries *series = new QBarSeries();
for(unsigned int set = 0; set < vv_SetSta->size(); set++)
{
if(pl_mean) set_mean.append((*vv_SetSta)[set][c_STAT_MEAN_ARITMETIC]);
if(pl_sd) set_sdev.append((*vv_SetSta)[set][c_STAT_STAN_DEV_SAMPLE]);
if(pl_median) set_medi.append((*vv_SetSta)[set][c_STAT_MEDIAN]);
if(pl_adm) set_aadm.append((*vv_SetSta)[set][c_STAT_ABS_DEV_MED]);
categories.append(QString::number(set));
}
if(pl_mean) series->append(&set_mean);
if(pl_sd) series->append(&set_sdev);
if(pl_median) series->append(&set_medi);
if(pl_adm) series->append(&set_aadm);
chart->addSeries(series);
//Axis
QBarCategoryAxis *X_axis = new QBarCategoryAxis();
X_axis->append(categories);
X_axis->setTitleText(name_categories);
chart->setAxisX(X_axis, series);
QValueAxis *Y_axis = new QValueAxis();
Y_axis->setTitleText(name_y);
chart->setAxisY(Y_axis, series);
//Showing
pChartView->setChart(chart);
return ER_Okay;

You are creating your QBarSet objects locally (i.e. not via the new operator) and passing a pointer to these sets to the QBarSet::append method which AFAIK takes ownership if the objects pointed to i.e feels obliged to de-allocate them when going out of scope. This is bound to fail with locally allocated objects.

Related

Qchart exception triggered

I'm developing an application that shows 3 charts in the main window and everything works fine. but now I came across an error when I make the instance
of the main window inside the class of another window the application crush and when do the debugger shows an exception triggered in one of the charts.
I used a graphic view and promote to Qchartview and for each chart the code is this:
chart_1
QPieSlice *slice = pieSeries->slices().at(0);
QFont font = slice->labelFont() ;
font.setBold(true);
font.setPointSize(15);
slice->setExploded();
slice->setLabelVisible();
slice->setPen(QPen(Qt::darkGreen, 1));
slice->setBrush(Qt::darkBlue);
slice->setLabelFont(font);
QChart *chart = new QChart();
chart->addSeries(pieSeries);
chart->setTitle("<h2>Total money of each currency</h2>");
chart->setAnimationOptions(QChart::SeriesAnimations);
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignBottom);
pieSeries->setLabelsVisible();
pieSeries->setLabelsPosition(QPieSlice::LabelOutside);
for(auto slice : pieSeries->slices())
slice->setLabel(QString("%1%").arg(100*slice->percentage(), 0, 'f', 1));
ui->chartView_1->setChart(chart);
ui->chartView_1->setRenderHint(QPainter::Antialiasing);
chart_2
QChart *donutBreakdown = new QChart();
donutBreakdown->setAnimationOptions(QChart::AllAnimations);
donutBreakdown->setTitle("<h2>Cassettes Information</h2>");
donutBreakdown->legend()->setAlignment(Qt::AlignBottom);
donutBreakdown->addSeries(series1);
donutBreakdown->addSeries(pieSeriesPie2);
donutBreakdown->addSeries(series3);
pieSeriesPie2->setLabelsVisible();
pieSeriesPie2->setLabelsPosition(QPieSlice::LabelOutside);
double arm = 0.04;
for(int i = 0; i < pieSeriesPie2->count(); i++){
double arm = (double)i/24;
double arm2= i*0.040;
QPieSlice *slice1 = pieSeriesPie2->slices().at(i);
slice1->setLabelArmLengthFactor(arm2);
}
ui->chartView_2->setChart(donutBreakdown);
ui->chartView_2->setRenderHint(QPainter::Antialiasing);
the two charts are pie chart and the triggered exception is on chart_2
I already replaced the chart_2, already replaced the graphical view that I am using in form
the days that I am fighting this error.
please help me please
Your static_cast
m_slice = static_cast<CustomSlice *>(slice1);
is probably not working as intended. I guess you made the CustomSlice class yourself, which inherits QPieChart. Please take a look at the https://en.cppreference.com/w/cpp/language/static_cast.
Did you mean dynamic_cast? Comment the line(s) out and try to reproduce the error.

Creating Graphics Tiles Using QVector(Basics Before QCache)

I am trying to upgrade my Seismic Graph Viewer to use tile graphics rendering. I am very unfamiliar with the process but my attempt to create a simple example is below. The reason why I need to use either QVector or QCache(I'm using QVector right now for simplicity) is to save ram and the tiles needed to be created on the fly. I'm not entirely sure if you're able to do what I'm trying to do below, but essentially it creates an array of bitmaps, makes them items, and then tries to add them to the scene. There are twelve errors when this program compiles, none of which directly refer the code that I made in the mainWindow.cpp.
the errors are either this
C:\Qt\Qt5.9.1\5.9.1\mingw53_32\include\QtCore\qvector.h:713: error:
use of deleted function 'QGraphicsPixmapItem&
QGraphicsPixmapItem::operator=(const QGraphicsPixmapItem&)' with the
only thing changing being the location of the error (different header
files)
or this
C:\Qt\Qt5.9.1\5.9.1\mingw53_32\include\QtWidgets\qgraphicsitem.h:861:
error: 'QGraphicsPixmapItem::QGraphicsPixmapItem(const
QGraphicsPixmapItem&)' is private Q_DISABLE_COPY(QGraphicsPixmapItem)
which is in the qgraphicsitem.h header file
The code that produces doesn't compile due to these errors popping up in the header files
int count;
QVector<QBitmap> BitmapArrayTiles;
QVector<QGraphicsPixmapItem> PixmapItemsArray;
QGraphicsPixmapItem currentItem;
QBitmap currentBitmap;
QGraphicsScene *scene = new QGraphicsScene();
for(count = 0; count < 4; count++)
{
currentBitmap = QBitmap(150,150);
QPainter Painter(&currentBitmap);
QPen Pen(Qt::black); // just to be explicit
Painter.setPen(Pen);
drawStuff(Painter);
BitmapArrayTiles.insert(0, currentBitmap);
currentItem.setPixmap(BitmapArrayTiles[count]);
PixmapItemsArray.insert(count, currentItem);
scene->addItem(&currentItem);
currentItem.mapToScene((count*150)+150, (count*150)+150);
}
ui->TileView->setScene(scene);
^
I have not changed the header files manually so I'm not entirely sure why I would be getting these errors.
Using pointers and tears
int count;
QGraphicsScene *scene = new QGraphicsScene(0, 0, 150*4, 150*4);
QVector<QBitmap*> BitmapArrayTiles;
QVector<QGraphicsPixmapItem*> BitmapItemsArray;
QGraphicsPixmapItem* CurrentItem;
QBitmap *CurrentBitmap;
const QBitmap* CurrentBitmapConstPointer = CurrentBitmap;
for(count = 0; count < 4; count++)
{
CurrentBitmap = new QBitmap(150,150);
QPainter Painter(CurrentBitmap);
QPen Pen(Qt::black); // just to be explicit
Painter.setPen(Pen);
drawStuff(Painter);
BitmapArrayTiles.insert(count, CurrentBitmap);
CurrentItem = new QGraphicsPixmapItem(*BitmapArrayTiles[count]);
BitmapItemsArray.insert(count, CurrentItem);
//PixmapItemsArray.insert(count, currentItem);
scene->addItem(BitmapItemsArray[count]);
BitmapItemsArray[count]->setPos((count*150)+150, (count*150)+150);
}
ui->TileView->setScene(scene);

How to update/redraw QChart after data is added to QLineSeries?

I am generating some data that I want to chart using QChart & friends. This is my first time using QChart, and so basically what I did was copy the QLineSeries Example and modify it to my needs. My current code looks like this:
quint64 last=0;
quint64 *lastp=&last;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, series( nullptr )
{
ui->setupUi(this);
QChart *chart = new QChart();
series=new QLineSeries(chart);
chart->legend()->hide();
chart->addSeries(series);
chart->createDefaultAxes();
chart->setTitle("Simple line chart example");
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
setCentralWidget(chartView);
GeneticTask *gTask = new GeneticTask();
connect(gTask, &GeneticTask::point, this, [=](QPointF pt) {
// New point added to series
*series<<pt;
// Limit updates to once per second
quint64 now=QDateTime::currentMSecsSinceEpoch();
if(now-(*lastp)>1000) {
qDebug()<<"UPDATE";
// [A] WHAT TO PUT HERE TO HAVE CHART REDRAW WITH NEW DATA?
*lastp=now;
}
}
);
QThreadPool::globalInstance()->start(gTask);
}
When I run this code I would expect my new data to show up in the graph, but it does not, so my question is: How can I have the chart update to show the new data? In other words, what should I put in the code where the comment reads [A]?
Appending a value to QLineSeries using the operator << or the append method should repaint the graph. If it does not happen form some reason, you could trying calling the repaint method on the QChartView.
Here is some code that will center the data once it is added with a cap of at most once per second:
// Global or class scope or
qreal max=-10000000000;
qreal min=-max;
qreal *maxp=&max;
qreal *minp=&min;
// Same scope as before
connect(gTask, &GeneticTask::point, this, [=](QPointF pt) {
if(pt.y()>*maxp) {
*maxp=pt.y();
}
if(pt.y()<*minp) {
*minp=pt.y();
}
*series<<pt;
quint64 now=QDateTime::currentMSecsSinceEpoch();
if(now-(*lastp)>1000) {
qDebug()<<"UPDATE";
chart->axisX()->setRange(0,series->count());
chart->axisY()->setRange(*minp,*maxp);
*lastp=now;
}
}
);
Little correction to the answer above. Qt Documentation says:
void QWidget::repaint()
Repaints the widget directly by calling
paintEvent() immediately, unless updates are disabled or the widget is
hidden. We suggest only using repaint() if you need an immediate
repaint, for example during animation. In almost all circumstances
update() is better, as it permits Qt to optimize for speed and
minimize flicker.
Warning: If you call repaint() in a function which
may itself be called from paintEvent(), you may get infinite
recursion. The update() function never causes recursion.
As result, QChartView::update() works for me.

Qt Scroll Area does not add in scroll bars

Hi guys I have to dynamically create push buttons depending on user inputs, therefore if user gives a large input number the widget containing the push buttons has to have the ability to scroll up and down. For this reason I am using QScrollArea. I generate the template in Qt designer and the UIC generates the code for me after which I add in my part which should handle dynamic creation of push buttons. However, I can not seem to get the vertical scroll bars to appear. Here is the relevant part of the code.
verticalWidget = new QWidget(FWHMWorkflowDialog);
verticalWidget->setObjectName(QString::fromUtf8("verticalWidget"));
verticalWidget->setMinimumSize(QSize(150, 0));
verticalWidget->setMaximumSize(QSize(150, 16777215));
verticalLayout_5 = new QVBoxLayout(verticalWidget);
verticalLayout_5->setObjectName(QString::fromUtf8("verticalLayout_5"));
scrollArea = new QScrollArea(verticalWidget);
scrollArea->setObjectName(QString::fromUtf8("scrollArea"));
scrollArea->setMaximumSize(QSize(150, 16777215));
scrollArea->setWidgetResizable(true);
scrollAreaWidgetContents = new QWidget();
scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents"));
scrollAreaWidgetContents->setGeometry(QRect(0, 0, 130, 432));
numberOfSlices = numberSlices;
for (int i = 0; i < numberOfSlices; i++)
{
QWidget *horizontalWidget = new QWidget(scrollAreaWidgetContents);
horizontalWidget->setMaximumSize(150,40);
horizontalWidget->setGeometry(QRect(0, i*40, 150, 40));
hWidgetList.push_back(horizontalWidget);
QHBoxLayout *hLayout = new QHBoxLayout(horizontalWidget);
hLayoutList.push_back(hLayout);
hLayout->setSizeConstraint(QLayout::SetMinimumSize);
hLayout->setContentsMargins(-1, 1, -1, 1);
QPushButton *pushButton = new QPushButton(horizontalWidget);
pushButtonList.push_back(pushButton);
QString temp = QString("m_sliceButton").arg(i);
pushButtonList[i]->setObjectName(temp);
pushButtonList[i]->setGeometry(QRect(10, 20+i*40, 98, 27));
hLayout->addWidget(pushButton);
QCheckBox *checkBox = new QCheckBox(horizontalWidget);
checkBoxList.push_back(checkBox);
temp = QString("m_checkBox").arg(i);
checkBoxList[i]->setObjectName(temp);
checkBoxList[i]->setEnabled(true);
checkBoxList[i]->setGeometry(QRect(110, 20+i*40, 21, 22));
hLayout->addWidget(checkBox);
}
scrollArea->setWidget(scrollAreaWidgetContents);
//scrollArea->setWidgetResizable(true);
verticalLayout_5->addWidget(scrollArea);
The output window always looks like the following.
In this example the input by the user is 25 however you can see that the 21st button is cut off and 4 other buttons are not visible.
The size window problem occurring after scroll functionality started working.
You need to add your horizontalWidget to a vertical widget like so:
QVBoxLayout* vLayout = new QVBoxLayout();
for (int i = 0; i < numberOfSlices; i++)
{
QWidget *horizontalWidget = new QWidget();
vLayout->addWidget(horizontalWidget);
....
}
scrollAreaWidgetContents->setLayout(vLayout);
You second problem looks like it comes from this line:
scrollArea = new QScrollArea(verticalWidget);
You're adding scrollArea directly to verticalWidget, but to get it to lay out the way you want you need to put it in a layout. Try the following instead:
QVBoxLayout* l = new QVBoxLayout();
l->addWidget(sliceLabel); // or whatever you call it
l->addWidget(scrollArea);
l->addWidget(clearButton); // again, your name here
verticalWidget->setLayout(l);
Try playing around with the QScrollBarPolicy.
http://doc.qt.digia.com/qt/qabstractscrollarea.html#horizontalScrollBarPolicy-prop
I'm guessing that the default behavior isn't working because there is something strange going on with layouts.

Segfault when adding Qwt plot to layout

I try to build chart demo using Qwt and C++. I've added the following code to button click handler:
QwtPlot *plot = new QwtPlot(QwtText("Demo"));
plot->setGeometry(0, 0, 100, 100);
QwtPlotCurve curve("Sine");
QVector<double> xs;
QVector<double> ys;
for (double x = 0; x < 100; x++)
{
xs.append(x);
ys.append(sin(x));
}
QwtPointArrayData *series = new QwtPointArrayData(xs, ys);
curve.setData(series);
curve.attach(plot);
plot->show();
QLayout *lay = ui->centralWidget->layout();
lay->addWidget(plot);
and it segfaults at addWidget(plot);.
What am I doing wrong?
The layout of centralWidget is probably NULL or you haven't initialized the ui (e.g. calling setUp()). Check the first case with if(lay == NULL) and the second by looking at your code.
If the first case is correct have a look at your UI file in QDesigner and add a layout.