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() ) {// TODOqreal 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() ) {// TODOpw-=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 0painter->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()); // 显示在上面
转载请保留出处!