Qt 使用 kdChart 自定义甘特图
Qt绘制甘特图,网上找了很久,只找到kdChart,编译很简单,我是Qt 5.5.0 + VS2013,直接编译就行,kdChart有甘特图例子:
但是和项目设计有点出入,所以自定义部分显示:
1.左边的是QTreeView,并为其添加委托,控件变化主要是通过QStandardItem->setData()来区别,这没什么说的,主要记录修改颜色和获取甘特图item拖动事件
(1).修改颜色(可实现每个item的颜色都不一样):
这是设置每个item的颜色:
topitem->setData(249, KDGantt::ItemColor_R); topitem->setData(171, KDGantt::ItemColor_G); topitem->setData(82, KDGantt::ItemColor_B);
kdChart中,颜色的修改是:
void ItemDelegate::paintGanttItem( QPainter* painter, const StyleOptionGanttItem& opt, const QModelIndex& idx )
函数修改:
void ItemDelegate::paintGanttItem( QPainter* painter, const StyleOptionGanttItem& opt, const QModelIndex& idx ) { if ( !idx.isValid() ) return; const ItemType typ = static_cast<ItemType>( idx.model()->data( idx, ItemTypeRole ).toInt() ); const QString& txt = opt.text; QRectF itemRect = opt.itemRect; QRectF boundingRect = opt.boundingRect; boundingRect.setY( itemRect.y() ); boundingRect.setHeight( itemRect.height() ); painter->save(); int color_r = idx.model()->data( idx, ItemColor_R ).toInt(); int color_g = idx.model()->data( idx, ItemColor_G ).toInt(); int color_b = idx.model()->data( idx, ItemColor_B ).toInt(); QColor itemColor(color_r, color_g, color_b); QPen pen(itemColor); if ( opt.state & QStyle::State_Selected ) pen.setWidth( 2*pen.width() ); painter->setPen( pen ); painter->setBrush( QBrush(Qt::white, Qt::Dense1Pattern) ); bool drawText = true; qreal pw = painter->pen().width()/2.; switch ( typ ) { case TypeTask: if ( itemRect.isValid() ) { // TODO qreal pw = painter->pen().width()/2.; pw-=1; QRectF r = itemRect; r.translate( 0., r.height()/6. ); r.setHeight( 2.*r.height()/3. ); painter->setBrushOrigin( itemRect.topLeft() ); painter->save(); painter->translate( 0.5, 0.5 ); painter->drawRect( r ); bool ok; qreal completion = idx.model()->data( idx, KDGantt::TaskCompletionRole ).toReal( &ok ); if ( ok ) { qreal h = r.height(); QRectF cr( r.x(), r.y()+h/4., r.width()*completion/100., h/2.+1 /*??*/ ); QColor compcolor( painter->pen().color() ); compcolor.setAlpha( 150 ); painter->fillRect( cr, compcolor ); } painter->restore(); } break; case TypeSummary: if ( opt.itemRect.isValid() ) { // TODO pw-=1; const QRectF r = QRectF( opt.itemRect ).adjusted( -pw, -pw, pw, pw ); QPainterPath path; const qreal deltaY = r.height()/2.; const qreal deltaXBezierControl = .25*qMin( r.width(), r.height() ); const qreal deltaX = qMin( r.width()/2., r.height() ); path.moveTo( r.topLeft() ); path.lineTo( r.topRight() ); path.lineTo( QPointF( r.right(), r.top() + 2.*deltaY ) ); //path.lineTo( QPointF( r.right()-3./2.*delta, r.top() + delta ) ); path.quadTo( QPointF( r.right()-deltaXBezierControl, r.top() + deltaY ), QPointF( r.right()-deltaX, r.top() + deltaY ) ); //path.lineTo( QPointF( r.left()+3./2.*delta, r.top() + delta ) ); path.lineTo( QPointF( r.left() + deltaX, r.top() + deltaY ) ); path.quadTo( QPointF( r.left()+deltaXBezierControl, r.top() + deltaY ), QPointF( r.left(), r.top() + 2.*deltaY ) ); path.closeSubpath(); painter->setBrushOrigin( itemRect.topLeft() ); painter->save(); painter->translate( 0.5, 0.5 ); painter->drawPath( path ); painter->restore(); } break; case TypeEvent: /* TODO */ //qDebug() << opt.boundingRect << opt.itemRect; if ( opt.boundingRect.isValid() ) { const qreal pw = painter->pen().width() / 2. - 1; const QRectF r = QRectF( opt.itemRect ).adjusted( -pw, -pw, pw, pw ).translated( -opt.itemRect.height()/2, 0 ); QPainterPath path; const qreal delta = static_cast< int >( r.height() / 2 ); path.moveTo( delta, 0. ); path.lineTo( 2.*delta, delta ); path.lineTo( delta, 2.*delta ); path.lineTo( 0., delta ); path.closeSubpath(); painter->save(); painter->translate( r.topLeft() ); painter->translate( 0, 0.5 ); painter->drawPath( path ); painter->restore(); #if 0 painter->setBrush( Qt::NoBrush ); painter->setPen( Qt::black ); painter->drawRect( opt.boundingRect ); painter->setPen( Qt::red ); painter->drawRect( r ); #endif } break; default: drawText = false; break; } Qt::Alignment ta; switch ( opt.displayPosition ) { case StyleOptionGanttItem::Left: ta = Qt::AlignLeft; break; case StyleOptionGanttItem::Right: ta = Qt::AlignRight; break; case StyleOptionGanttItem::Center: ta = Qt::AlignCenter; break; case StyleOptionGanttItem::Hidden: drawText = false; break; } if ( drawText ) { painter->drawText( boundingRect, ta | Qt::AlignVCenter, txt ); } painter->restore(); }
(2).拖动事件:
在文件kdganttgraphicsview.h中添加信号
void signal_dataChanged( const QModelIndex & index );
void GraphicsView::Private::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight ) { const QModelIndex parent = topLeft.parent(); for ( int row = topLeft.row(); row <= bottomRight.row(); ++row ) { scene.updateRow( scene.summaryHandlingModel()->index( row, 0, parent ) ); } emit q->signal_dataChanged(topLeft); }
外部使用:
connect(ui->ganttView->graphicsView(), SIGNAL(signal_dataChanged(const QModelIndex&)), this, SLOT(onCheckTask(const QModelIndex&)));
修改显示的日期格式,效果:
上面显示年月,下面显示多少号,显示号很简单:
grid.setUserDefinedLowerScale(new KDGantt::DateTimeScaleFormatter(KDGantt::DateTimeScaleFormatter::Day,QString::fromLatin1("dd"),QString::fromLatin1("%1"),Qt::AlignHCenter));
其中有个格式:QString::fromLatin1("dd"),dd:号, ddd:星期几
使用这个函数,只能显示年或者月或者天,不能组合显示,所有重写DateTimeScaleFormatter;
class MyDateTimeScaleFormatter : public KDGantt::DateTimeScaleFormatter { public: MyDateTimeScaleFormatter() : DateTimeScaleFormatter(Month, "MM"){} /*reimp*/QDateTime nextRangeBegin(const QDateTime& datetime) const { return currentRangeBegin(datetime).addMonths(1); } /*reimp*/QDateTime currentRangeBegin(const QDateTime& datetime) const { return datetime; } /*reimp*/QString text(const QDateTime& dt) const { return QObject::tr("%1年%2月").arg(dt.date().year()).arg(dt.date().month()); } };
grid.setUserDefinedUpperScale(new MyDateTimeScaleFormatter()); // 显示在上面
转载请保留出处!