Всем доброго времени суток. Хочу с помощью QML реализовать столбчатую диаграмму. Для это использовал ListView, модель на C++ и делегат к ней на QML. До какого-то момента времени работало замечательно, но недавно обнаружил(диаграмма на отдельной вкладке, редко заглядывал туда), что она поломалась. Причину уже второй день понять не могу. Поломка заключается в том, что рисуется только 1 item модели. Всегда только один. в методе модели Data проходится по всем элементам, отображает только один.
Модель:
#ifndef TREEMODEL_H
#define TREEMODEL_H
#include <QAbstractListModel>
#include <QDeclarativeContext>
#include <QDeclarativeView>
#include <QDeclarativeEngine>
#include <QDeclarativeComponent>
#include <QDebug>
#include <QDate>
#include <QStandardItemModel>
#include "../../Data/Entyties/transaction.h"
class GraphicsModelItem;
class GraphicsModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit GraphicsModel(QDeclarativeView *view, QObject *parent=0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QList<GraphicsModelItem *> items;
int amount_length;
int amount_max;
int date_height;
Account *current_acc;
QMap<QDate,GraphicsModelItem*> *map;
QDeclarativeView *view;
public slots:
void ItemsFromTransactions(QList<Transaction*> *l, Account *acc);
private:
Q_DISABLE_COPY(GraphicsModel)
enum ListMenuItemRoles
{
IncomeRole = 10,
OutcomeRole = 20,
CountRole = 30,
DateRole = 40,
DayCountRole = 50
};
};
#endif // TREEMODEL_H
#include "GraphicsModel.h"
class GraphicsModelItem
{
public:
GraphicsModelItem(int income, int outcome, int number, QDate date)
{
this->income = income;
this->outcome = outcome;
this->count = number;
this->date = date;
}
int income;
int outcome;
int count;
QDate date;
};
GraphicsModel::GraphicsModel(QDeclarativeView *view, QObject *parent) :
QAbstractListModel(parent)
{
QHash<int, QByteArray> roles = roleNames();
roles.insert(IncomeRole, QByteArray("income"));
roles.insert(OutcomeRole, QByteArray("outcome"));
roles.insert(CountRole, QByteArray("count"));
roles.insert(DateRole, QByteArray("date"));
roles.insert(DayCountRole, QByteArray("dayCount"));
setRoleNames(roles);
amount_max = 0;
amount_length = 1;
this->view = view;
this->view->setSource(QUrl("qrc:/QML/GraphView"));
this->view->rootContext()->setContextProperty("GraphModel",this);
this->view->rootContext()->setContextProperty("amount_length", amount_length);
this->view->rootContext()->setContextProperty("amount_max", amount_max);
this->view->setResizeMode(QDeclarativeView::SizeRootObjectToView);
/*this->view->setCacheMode(QGraphicsView::CacheBackground);
this->view->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
this->view->setOptimizationFlags(QGraphicsView::DontSavePainterState|QGraphicsView::DontAdjustForAntialiasing);
*/}
void GraphicsModel::ItemsFromTransactions(QList<Transaction*> *l,Account *acc)
{
this->current_acc = acc;
amount_max = 0;
QMap<QDate,GraphicsModelItem*> map;
for (int i=0; i<l->size();i++)
{
Transaction* tr = l->at(i);
if (map.contains(l->at(i)->created_at().date()))
{
GraphicsModelItem* item = map.value(tr->created_at().date()) ;
if (tr->acc_from()==current_acc)
item->outcome+=tr->amount_from();
else
item->income+=tr->amount_to();
}else
{
GraphicsModelItem* item ;
if (tr->acc_from()==current_acc)
item = new GraphicsModelItem(0,tr->amount_from(),map.size(),tr->created_at().date());
else
item = new GraphicsModelItem(tr->amount_to(),0,map.size(),tr->created_at().date());
map.insert(tr->created_at().date(),item);
}
}
this->items.clear();
QList<GraphicsModelItem*> ll = map.values();
for (int i=0;i<ll.length();i++)
{
if (ll.at(i)->income>amount_max)
amount_max = ll.at(i)->income;
if (ll.at(i)->outcome>amount_max)
amount_max = ll.at(i)->outcome;
this->items.push_back(ll.at(i));
}
qDebug() <<"size of elements " << items.size();
if (items.size()>0)
{
amount_length = QString().setNum(amount_max).length()+1;
this->view->rootContext()->setContextProperty("GraphModel",this);
this->view->rootContext()->setContextProperty("amount_length", amount_length);
this->view->rootContext()->setContextProperty("amount_max", amount_max);
this->reset();
}
}
QVariant GraphicsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() > (items.size()-1) )
return QVariant();
GraphicsModelItem *item = items.at(index.row());
qDebug()<< " items row = "<< index.row();
switch (role)
{
case Qt::UserRole:
{
case IncomeRole:
return QVariant::fromValue(item->income);
case OutcomeRole:
return QVariant::fromValue(item->outcome);
case CountRole:
qDebug()<< " items size = "<< items.size();
qDebug()<< " item count = " <<item->count;
return QVariant::fromValue(index.row());
case DateRole:
return QVariant::fromValue(item->date.toString("dd.MM"));
case DayCountRole:
return QVariant::fromValue(items.size());
}
}
return QVariant();
}
int GraphicsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return items.size();
}
часть QML, отвечающая за отображение:
ListView
{
id: graphicView
delegate: dayActivity
model: GraphModel
Rectangle {
id: yLine
width: 1
height: myGraphic.height-mainRect.adaptFontSize()*2
x: mainRect.adaptFontSize()*amount_length/1.5
color: "black"
}
Rectangle {
id: xLine
x: yLine.x
height: 1
width: myGraphic.width
y: yLine.height;
color: "black"
}
}
Component {
id: dayActivity
Item {
Item {
visible: false
id: levelMarginElement
x:0
y:0
height:1
width:10*count //count*((myGraphic.width-yLine.x)/100)+5 + yLine.x
}
Rectangle
{
id: incomeRect
radius: 10
height: (xLine.y-myGraphic.height*0.03)/amount_max * income
x:levelMarginElement.width
y:xLine.y-height+2
width:(myGraphic.width-yLine.x)*0.9/(dayCount*2)
color: "red"
}
Rectangle
{
id: outcomeRect
radius: 10
height: (xLine.y-myGraphic.height*0.03)/amount_max * outcome
x:levelMarginElement.width+incomeRect.width-1
y: xLine.y-height+2
width:(myGraphic.width-yLine.x)*0.9/(dayCount*2)
color: "blue"
}
Text
{
id:dateText
x:outcomeRect.x-mainRect.adaptFontSize()
y:xLine.y+2
text:date
font.pixelSize: mainRect.adaptFontSize()+1
}
}
}