PDA

View Full Version : Problem getting QChartView to display



derrickbj
16th September 2016, 00:32
Hello, I'm working in Qt 5.7 (MSVC2015) and I'm having problems getting QChartView to display in my QHBoxLayout. I'm writing a program that will parse through a file and add up instances of Ford, Chevy or GMC trucks per a given location. I then want to graphically represent them via a pie chart. I'm trying to use QHPieModelMapper to dynamically update the pie chart upon reading other files. Here's what I have:
MainWindow.h


class MainWindow : public QMainWindow, private Ui::MainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private:
void setupModel();
void setupChart();
void readFile();
void updateCarTotals(const QString &, int FORDS=0, int CHEVYS=0,int GMCS=0);
QChart *m_chart;
QStandardItemModel *overallCarCountModel;
int totalFord,totalChevy,totalGMC;
};



MainWindow.cpp


MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupModel()
setupChart()
}

void MainWindow::setupModel()
{
overallCarCountModel = new QStandardItemModel(this);
overallCarCountModel->insertRows(0,2);
overallCarCountModel->insertColumns(0,3);
overallCarCountModel->setHeaderData(0,Qt::Horizontal,"Ford");
overallCarCountModel->setHeaderData(1,Qt::Horizontal,"Chevy");
overallCarCountModel->setHeaderData(2,Qt::Horizontal,"GMC");
}

void MainWindow::setupChart()
{
QHBoxLayout* chartLayout = new QHBoxLayout;
m_chart = new QChart;
m_chart->setTitle("Total Cars");

QPieSeries *series = new QPieSeries();
QHPieModelMapper *pcMapper = new QHPieModelMapper(this);
series->setPieSize(0.7); //I know this is the default, just trying whatever to get it working
pcMapper->setValuesRow(0);
pcMapper->setSeries(series);
pcMapper->setModel(overallCarCountModel );
m_chart->addSeries(series);
QChartView *overallCarsPieChartView = new QChartView(m_chart);
overallCarsPieChartView ->setRenderHint(QPainter::Antialiasing);
overallCarsPieChartView ->setMinimumSize(200,200);
chartLayout->addWidget( overallCarsPieChartView );
overallCarsGroupBox->setLayout(chartLayout);

void MainWindow::readFile()
{
// ...
//code to open file, parse words and tally up cars by site name
// ...
updateCarTotals(siteName, fords, chevys, gmcs)

}

void MainWindow::updateCarTotals(const QString &site, int fords, int chevys, int gmcs)
{
QString fordCount,chevyCount,gmcCount;
fordCount.setNum(fords);
chevyCount.setNum(chevys);
gmcCount.setNum(gmcs);

totalFord+=fords;
totalChevy+=chevys;
totalGMC+=gmcs;

overallCarCountModel->setData(overallCarCountModel->index(0,0),QVariant(totalFord));
overallCarCountModel->setData(overallCarCountModel->index(0,1),QVariant(totalChevy));
overallCarCountModel->setData(overallCarCountModel->index(0,2),QVariant(totalGMC));
}


In Designer, I made a MainWindow and put a TabWidget on there. Right now, I have 1 tab and on that tab I have an group box called "overallCarsGroupBox" where I want the pie chart to be displayed.

The code to read the file and tally up the cars works fine, I checked it through qDebug(). So the values being passed to MainWindow::updateCarTotals are valid. When I run the program, the title of the chart ("Total Cars") is displayed fine, but the chart does not display. Any ideas about what I could be doing wrong that would make this chart not display?

anda_skoa
17th September 2016, 11:03
Is "overallCarsGroupBox" in a layout itself?
Is the TabWidget in a layout?

I.e. is the layout chain up to the central widget complete?

d_stranz
17th September 2016, 19:18
I thought about this. The fact that the chart title (a component of the Chart instance) is displayed means that the chart itself is correctly being placed in the layout chain. I think the problem lies in the communication between the model, mapper, and series. However, I can't see any substantial difference between the OP's code and the code in the BarModelMapper example (http://doc.qt.io/qt-5/qtcharts-barmodelmapper-example.html) with respect to setting up the components.

derrickbj
19th September 2016, 19:35
Thanks for the responses. Yes, I had thought about the layout chain, but since the title is being displayed I didn't think the layout was an issue. If the model is populated, the mapper should pick this up right away, correct? In other words, I don't need to do any particular "refresh" on the mapper/series combo, do I? I couldn't exactly see how to do that anyway, so I hope not :) I really based this code off of the example code, so it's really baffling me why it's not working.

derrickbj
19th September 2016, 22:58
I found the problem. It seems the default QHPieModelMapper::labelsRow() is -1 (invalid mapping). So it would appear that I have to give it a labelsRow setting in order for the mapping to be valid. I was thinking the model mapper would pull the label information from the header data set through QAbstractItemModel::setHeaderData(), but I guess not. So I had to make my model have two rows, one containing the the words "Ford, Chevy, GMC" for the pie labels and the 2nd row containing the values. Then I set QHPieModelMapper::labelsRow() to 0 and QHPieModelMapper::valuesRow() to 1 and my pie chart displayed properly!

d_stranz
20th September 2016, 17:55
Good to know this. As I said, my money was on a problem with the mapper, but with the exception of the problem you identified, it all looked OK. The mapper *should* keep the view updated whenever there is a change to the model, and calling setData() is exactly that.

I am curious now - if you had derived your model from QAbstractTableModel, would the QHPieModelMapper have automatically used the headers from that? QStandardItemModel *could be* used to represent tabular data, whereas QAbstractTableModel *always* does so the mapper could be assured of finding a horizontal header row.

Thanks for following up by posting your solution.