精华内容
下载资源
问答
  • Qt甘特图源码

    2018-07-03 15:05:12
    Qt甘特图源码,刻度缩放原理,甘特图进度条增删改等等
  • qt 甘特图另一个版本

    2019-01-07 15:55:33
    qt甘特图源代码qt甘特图源代码
  • qt绘制甘特图

    2017-01-07 13:55:59
    qt 甘特图
  • qt甘特图

    2019-01-07 15:35:20
    网上搜集的qt甘特图源代码 。qt5.7.1 和vs2013编译正常
  • qt实现甘特图源码

    热门讨论 2013-07-29 20:58:08
    源码中含有使用QT实现甘特图的控件
  • Qt甘特图控件

    千次阅读 2018-07-25 21:06:00
    本文介绍了如何在Qt4中自定义View控件实现甘特图效果。

    本片博客中代码仅使用于Qt4,Qt5中已经提供了QChart类无需在造轮子实现类似效果。

    在这片博客中,我将详细讲述如何是通过QAbstractItemView定制一个GanttView。本篇博文中的代码参考自Qt4例子chart,有兴趣的同学可以查看chart代码深入理解如何定制自己的view控件。(注:在写这篇博客的代码时犯了懒癌,不想写注释……)

    详细代码

    MainWindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QSplitter>
    #include <QTableView>
    #include "GanttView.h"
    #include <QStandardItemModel>
    #include <QTableView>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        void initModel();
        void initView();
    
    private:
        Ui::MainWindow *ui;
    
        QSplitter *_splitter;
        QAbstractItemModel *_model;
        QTableView *_table;
        GanttView *_ganttView;
        QItemSelectionModel *_selectionModel;
    };
    
    #endif // MAINWINDOW_H
    

    MainWindow.cpp

    #include "MainWindow.h"
    #include "ui_MainWindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        initModel();
        initView();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::initModel()
    {
        _model = new QStandardItemModel(5,3,this);
        _model->setHeaderData(0,Qt::Horizontal,QString("event"));
        _model->setHeaderData(1,Qt::Horizontal,QString("StartDate"));
        _model->setHeaderData(2,Qt::Horizontal,QString("EndDate"));
    
        QDate startDate = QDate::currentDate();
        for (int row = 0; row < _model->rowCount(); ++row)
        {
            _model->setData(_model->index(row,0),QString::number(row+1));
            _model->setData(_model->index(row,1),startDate.addDays(row));
            _model->setData(_model->index(row,2),startDate.addDays(row+5));
        }
    }
    
    void MainWindow::initView()
    {
        _splitter = new QSplitter;
    
        _table = new QTableView;
        _table->setModel(_model);
        _table->setSelectionMode(QAbstractItemView::SingleSelection);
        _table->setSelectionBehavior(QAbstractItemView::SelectRows);
        _table->horizontalHeader()->setStretchLastSection(true);
        _table->horizontalHeader()->setDefaultSectionSize(100);
        _table->horizontalHeader()->setMinimumWidth(100);
        _table->verticalHeader()->setVisible(false);
    
        _ganttView = new GanttView;
        _ganttView->setModel(_model);
    
        QItemSelectionModel *selectionModel = new QItemSelectionModel(_model);
        _table->setSelectionModel(selectionModel);
        _ganttView->setSelectionModel(selectionModel);
    
        _splitter->addWidget(_table);
        _splitter->addWidget(_ganttView);
    
        _splitter->setStretchFactor(0, 2);
        _splitter->setStretchFactor(1, 3);
    
        setCentralWidget(_splitter);
    }
    

    GanttView.h

    #ifndef GanttView_H
    #define GanttView_H
    
    #include <QAbstractItemView>
    #include <QFont>
    #include <QItemSelection>
    #include <QItemSelectionModel>
    #include <QStandardItemModel>
    #include <QModelIndex>
    #include <QRect>
    #include <QSize>
    #include <QPoint>
    #include <QWidget>
    #include <QDate>
    
    class GanttView : public QAbstractItemView
    {
        Q_OBJECT
    public:
        explicit GanttView(QWidget *parent = 0);
        ~GanttView(void);
    
        QRect visualRect(const QModelIndex &index) const;
        void scrollTo(const QModelIndex &, ScrollHint = EnsureVisible);
        QModelIndex indexAt(const QPoint &point) const;
    
    protected slots:
        void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
        void rowsInserted(const QModelIndex &parent, int start, int end);
        void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
    
    signals:
        void sgCurrentSerialNumberChanged(const int sn) const;
    
    protected:
        bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event);
        QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
    
        int horizontalOffset() const;
        int verticalOffset() const;
    
        bool isIndexHidden(const QModelIndex &) const;
    
        void setSelection(const QRect&, QItemSelectionModel::SelectionFlags command);
    
        void mousePressEvent(QMouseEvent *event);
    
        void mouseMoveEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
    
        void paintEvent(QPaintEvent *event);
        void resizeEvent(QResizeEvent *);
        void scrollContentsBy(int dx, int dy);
    
        QRegion visualRegionForSelection(const QItemSelection &selection) const;
    
    private:
        QRect itemRect(const QModelIndex &item) const;
        QRegion itemRegion(const QModelIndex &index) const;
        int rows(const QModelIndex &index = QModelIndex()) const;
        void updateGeometries();
        void updateMetaData();
    
    private:
        int _rectHeight;
        int _space;
        int _lengthX;
        int _lengthY;
        QPoint _origin;
        QRubberBand *_rubberBand;
    
        QDate _startDate;
        int _pixPerDay;
    
    };
    
    #endif // GanttView_H
    

    GanttView.cpp

    #include "GanttView.h"
    #include <QtGui>
    #include <QDate>
    
    GanttView::GanttView(QWidget *parent) : QAbstractItemView(parent)
    {
        horizontalScrollBar()->setRange(0, 0);
        verticalScrollBar()->setRange(0, 0);
    
        _rubberBand = 0;
        _rectHeight = 20;
        _space = 0;
        _pixPerDay = 10;
        _lengthX = 100;
        _lengthY = 100;
    
        setEditTriggers(QAbstractItemView::NoEditTriggers);
    }
    
    GanttView::~GanttView()
    {}
    
    QRect GanttView::visualRect(const QModelIndex &index) const
    {
        QRect rect = itemRect(index);
        if (rect.isValid())
            return QRect(rect.left() - horizontalScrollBar()->value(), rect.top() - verticalScrollBar()->value(), rect.width(), rect.height());
        else
            return rect;
    }
    
    void GanttView::scrollTo(const QModelIndex &/*index*/, QAbstractItemView::ScrollHint /*hint*/)
    {
        update();
    }
    
    QModelIndex GanttView::indexAt(const QPoint &point) const
    {
        int wx = point.x() + horizontalScrollBar()->value();
        int wy = point.y() + verticalScrollBar()->value();
    
        double cx = wx - 50;
        double cy = wy - 50;
    
        for (int row = 0; row < model()->rowCount(rootIndex()); ++row)
        {
            QDate currentStartDate = model()->data(model()->index(row,1)).toDate();
            QDate currentEndDate = model()->data(model()->index(row,2)).toDate();
    
            QPoint lt = QPoint(_startDate.daysTo(currentStartDate)*_pixPerDay,(_rectHeight+_space)*row);
            QPoint rd = QPoint(_startDate.daysTo(currentEndDate)*_pixPerDay,(_rectHeight+_space)*row+_rectHeight);
    
            if (cx>lt.x()&&cy>lt.y()&&cx<rd.x()&&cy<rd.y())
            {
                return model()->index(row, 0, rootIndex());
            }
        }
    
        return QModelIndex();
    }
    
    void GanttView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
    {
        QAbstractItemView::dataChanged(topLeft, bottomRight);
        updateMetaData();
        viewport()->update();
    }
    
    void GanttView::rowsInserted(const QModelIndex &parent, int start, int end)
    {
        QAbstractItemView::rowsInserted(parent, start, end);
    }
    
    void GanttView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
    {
        QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
    }
    
    bool GanttView::edit(const QModelIndex &index, QAbstractItemView::EditTrigger trigger, QEvent *event)
    {
        if (index.column() == 0)
            return QAbstractItemView::edit(index, trigger, event);
        else
            return false;
    }
    
    QModelIndex GanttView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
    {
        QModelIndex current = currentIndex();
        if (model() == NULL) return current;
    
        switch (cursorAction) {
        case MoveLeft:
        case MoveUp:
            if (current.row() > 0)
                current = model()->index(current.row() - 1, current.column(), rootIndex());
            else
                current = model()->index(0, current.column(), rootIndex());
            break;
        case MoveRight:
        case MoveDown:
            if (current.row() < rows(current) - 1)
                current = model()->index(current.row() + 1, current.column(), rootIndex());
            else
                current = model()->index(rows(current) - 1, current.column(), rootIndex());
            break;
        default:
            break;
        }
    
        viewport()->update();
        return current;
    }
    
    int GanttView::horizontalOffset() const
    {
        return horizontalScrollBar()->value();
    }
    
    int GanttView::verticalOffset() const
    {
        return verticalScrollBar()->value();
    }
    
    bool GanttView::isIndexHidden(const QModelIndex &/*index*/) const
    {
        return false;
    }
    
    void GanttView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
    {
        // Use content widget coordinates because we will use the itemRegion()
        // function to check for intersections.
        if (model() == NULL) return;
    
        QRect contentsRect = rect.translated( horizontalScrollBar()->value(), verticalScrollBar()->value()).normalized();
    
        int rows = model()->rowCount(rootIndex());
        QModelIndexList indexes;
    
        for (int row = 0; row < rows; ++row)
        {
            QModelIndex index = model()->index(row, 0, rootIndex());
            QRegion region = itemRegion(index);
            if (!region.intersect(contentsRect).isEmpty())
                indexes.append(index);
        }
    
        if (indexes.size() > 0)
        {
            int firstRow = indexes[0].row();
            int lastRow = indexes[0].row();
            int firstColumn = indexes[0].column();
            int lastColumn = indexes[0].column();
    
            for (int i = 0; i < indexes.size(); ++i)
            {
                firstRow = qMin(firstRow, indexes[i].row());
                lastRow = qMax(lastRow, indexes[i].row());
                firstColumn = qMin(firstColumn, indexes[i].column());
                lastColumn = qMax(lastColumn, indexes[i].column());
            }
    
            QItemSelection selection( model()->index(firstRow, firstColumn, rootIndex()), model()->index(lastRow, lastColumn, rootIndex()));
            selectionModel()->select(selection, command);
        }
        else
        {
            QModelIndex noIndex;
            QItemSelection selection(noIndex, noIndex);
            selectionModel()->select(selection, command);
        }
    
        update();
    }
    
    void GanttView::mousePressEvent(QMouseEvent *event)
    {
        QAbstractItemView::mousePressEvent(event);
        _origin = event->pos();
        if (!_rubberBand)
            _rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport());
        _rubberBand->setGeometry(QRect(_origin, QSize()));
        _rubberBand->show();
    }
    
    void GanttView::mouseMoveEvent(QMouseEvent *event)
    {
        if (_rubberBand)
            _rubberBand->setGeometry(QRect(_origin, event->pos()).normalized());
        QAbstractItemView::mouseMoveEvent(event);
    }
    
    void GanttView::mouseReleaseEvent(QMouseEvent *event)
    {
        QAbstractItemView::mouseReleaseEvent(event);
        if (_rubberBand)
            _rubberBand->hide();
        viewport()->update();
    }
    
    void GanttView::paintEvent(QPaintEvent *event)
    {
        if (model() == NULL) return;
    
        QItemSelectionModel *selections = selectionModel();
        QStyleOptionViewItem option = viewOptions();
    
        QBrush background = option.palette.base();
        QPen foreground(option.palette.color(QPalette::WindowText));
    
        QPainter painter(viewport());
        painter.setRenderHint(QPainter::Antialiasing);
    
        painter.fillRect(event->rect(), background);
        painter.setPen(foreground);
    
        painter.save();
        painter.translate(50 - horizontalScrollBar()->value(),50-verticalScrollBar()->value());
        painter.drawLine(0,0,0,_lengthY);
        painter.drawLine(0,0,_lengthX,0);
        painter.drawText(-6,_lengthY+13,QString("sn"));
        painter.drawText(_lengthX+3,3,QString("day"));
    
        ///画Y轴箭头
        painter.translate(0,_lengthY);
        painter.drawLine(1,1,6,-8);
        painter.drawLine(-1,1,-6,-8);
    
        ///画X轴箭头
        painter.translate(_lengthX,-_lengthY);
        painter.drawLine(-1,-1,-8,-6);
        painter.drawLine(-1,1,-8,6);
    
        painter.translate(-_lengthX,0);
    
        /// 画X轴刻度
        for (int i = 0; i < _lengthX; i+=50)
        {
            painter.drawLine(i,0,i,5);
            painter.drawText(i - 7,-5,QString::number(i/10));
        }
    
        /// 画Y轴刻度
        for (int i = 1; i < model()->rowCount()+1; ++i)
        {
            painter.drawLine(0,(_rectHeight+_space)*i,5,(_rectHeight+_space)*i);
            painter.drawText(-15,(_rectHeight+_space)*i - 10,QString::number(i));
        }
    
        for (int row = 0; row < model()->rowCount(); ++row)
        {
            QDate startDate = model()->data(model()->index(row,1)).toDate();
            QDate endDate = model()->data(model()->index(row,2)).toDate();
            int duration = startDate.daysTo(endDate);
    
            QModelIndex index = model()->index(row, 0);
    
            if (currentIndex() == index && selections->isSelected(index))
                painter.setBrush(QBrush(QColor::fromHsvF(qreal(row)/qreal(model()->rowCount()),1.0,1.0), Qt::Dense4Pattern));
            else
                painter.setBrush(QBrush(QColor::fromHsvF(qreal(row)/qreal(model()->rowCount()),1.0,1.0)));
    
            painter.drawRect(_startDate.daysTo(startDate)*_pixPerDay,(_rectHeight+_space)*(row),duration*_pixPerDay,_rectHeight);
        }
        painter.restore();
    }
    
    void GanttView::resizeEvent(QResizeEvent */*event*/)
    {
        updateGeometries();
    }
    
    void GanttView::scrollContentsBy(int dx, int dy)
    {
        viewport()->scroll(dx, dy);
    }
    
    QRegion GanttView::visualRegionForSelection(const QItemSelection &selection) const
    {
        if (model() == NULL) return QRect();;
        int ranges = selection.count();
    
        if (ranges == 0)
            return QRect();
    
        QRegion region;
        for (int i = 0; i < ranges; ++i) {
            QItemSelectionRange range = selection.at(i);
            for (int row = range.top(); row <= range.bottom(); ++row) {
                for (int col = range.left(); col <= range.right(); ++col) {
                    QModelIndex index = model()->index(row, col, rootIndex());
                    region += visualRect(index);
                }
            }
        }
        return region;
    }
    
    QRect GanttView::itemRect(const QModelIndex &index) const
    {
        if (model() == NULL) return QRect();
    
        if (!index.isValid())
            return QRect();
    
        if (index.column() == 0)
        {
            return viewport()->rect();
        }
    
        return QRect();
    }
    
    QRegion GanttView::itemRegion(const QModelIndex &index) const
    {
        if (!index.isValid())
            return QRegion();
    
        if (index.column() != 0)
            return itemRect(index);
    
        for (int row = 0; row < model()->rowCount(rootIndex()); ++row)
        {
            QModelIndex sliceIndex = model()->index(row, 0, rootIndex());
    
            QDate currentStartDate = model()->data(model()->index(row,1)).toDate();
            QDate currentEndDate = model()->data(model()->index(row,2)).toDate();
            int duration = currentStartDate.daysTo(currentEndDate)*_pixPerDay;
    
            if (sliceIndex == index)
            {
                QPainterPath path;
                path.addRect(_startDate.daysTo(currentStartDate)*_pixPerDay+50,(_rectHeight+_space)*row+50,duration,_rectHeight);
                return QRegion(path.toFillPolygon().toPolygon());
            }
        }
    
        return QRegion();
    }
    
    int GanttView::rows(const QModelIndex &index) const
    {
        return model()->rowCount(model()->parent(index));
    }
    
    void GanttView::updateGeometries()
    {
        if (NULL == model()) return;
    
        updateMetaData();
    
        horizontalScrollBar()->setPageStep(viewport()->width());
        horizontalScrollBar()->setRange(0, qMax(0, _lengthX - viewport()->width()));
        verticalScrollBar()->setPageStep(viewport()->height());
        verticalScrollBar()->setRange(0, qMax(0, _lengthY - viewport()->height()));
    }
    
    void GanttView::updateMetaData()
    {
        _lengthX = 5;
        _lengthY = (_rectHeight+_space)*(model()->rowCount()+1);
        if (model())
        {
            _startDate = model()->data(model()->index(0,1)).toDate();
    
            for (int row = 0; row < model()->rowCount(); ++row)
            {
                QDate currentStartDate = model()->data(model()->index(row,1)).toDate();
                QDate currentEndDate = model()->data(model()->index(row,2)).toDate();
                _startDate = qMin(currentStartDate,_startDate);
                _lengthX = qMax(_lengthX,_startDate.daysTo(currentEndDate));
            }
            _lengthX *=10;
            _lengthX += 50;
        }
    }
    

    效果图

    这里写图片描述

    以上就是在Qt4中自定义甘特图视图的全部内容。如有不明白的地方欢迎留言交流,若帖子中有错误的地方同样欢迎留言批评指正,在此谢过,欢迎骚扰。

    展开全文
  • Qt kdChart 甘特图案例

    2019-07-17 19:37:00
    KDChart 甘特图Qt中的加载使用案例,代码来自官方 mainwindow.h /**************************************************************************** ** Copyright (C) 2001-2018 Klaralvdalens ...

    KDChart  甘特图在Qt中的加载使用案例,代码来自官方

     

    mainwindow.h

    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QItemSelection>
    #include <QMainWindow>
    
    QT_BEGIN_NAMESPACE
    class QStandardItemModel;
    class QCloseEvent;
    namespace Ui {
        class MainWindow;
    }
    QT_END_NAMESPACE
    
    namespace KDGantt {
        class ConstraintModel;
        class DateTimeGrid;
        class Legend;
    }
    
    class MainWindow : public QMainWindow {
        Q_OBJECT
    
    public:
        explicit MainWindow( QWidget * parent = 0, Qt::WindowFlags flags = 0 );
        virtual ~MainWindow();
        virtual void closeEvent(QCloseEvent *event);
    
    private slots:
        void addNewEntry();
        void removeEntry();
        void showContextMenu( const QPoint& );
        void enableActions( const QItemSelection& selected );
        void zoomIn();
        void zoomOut();
        void zoomFit();
        void scaleAuto();
        void scaleHour();
        void scaleDay();
        void scaleWeek();
        void scaleMonth();
    
    private:
        void initModel();
        void initActions();
        void initItemDelegate();
        void initGrid();
    
        void setReadOnly( const QModelIndex& index, bool readOnly );
        void addConstraint( const QModelIndex& index1, const QModelIndex& index2 );
    
        QStandardItemModel* model;
        KDGantt::ConstraintModel* constraintModel;
        KDGantt::DateTimeGrid* grid;
        KDGantt::Legend* smallLegend;
        KDGantt::Legend* detailedLegend;
    
        QAction* newEntryAction;
        QAction* removeEntryAction;
        QAction* zoomInAction;
        QAction* zoomOutAction;
        QAction* zoomFitAction;
    
        Ui::MainWindow* ui;
    };
    
    #endif /* MAINWINDOW_H */

    entrydialog.h

    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #ifndef ENTRYDIALOG_H
    #define ENTRYDIALOG_H
    
    #include <QDateTime>
    #include <QDialog>
    #include <QModelIndex>
    
    QT_BEGIN_NAMESPACE
    class QAbstractItemModel;
    namespace Ui {
        class EntryDialog;
    }
    QT_END_NAMESPACE
    
    namespace KDGantt {
        class ConstraintModel;
    }
    
    class EntryDialog : public QDialog {
        Q_OBJECT
    
    public:
        explicit EntryDialog( const QAbstractItemModel* model, QWidget* parent = 0, Qt::WindowFlags f = 0 );
        void initFrom( const QModelIndex& index, const KDGantt::ConstraintModel* constraintModel );
        
        QString name() const;
        int type() const;
        QDateTime startDate() const;
        QDateTime endDate() const;
        int completion() const;
        bool readOnly() const;
        QModelIndex depends() const;
        QString legend() const;
    
    private slots:
        void updateEndDate( const QDateTime& startDate );
        void disableEditing( bool disable );
        void typeChanged( int index );
        
    private:
        void init();
        void addDependItem( const QAbstractItemModel* model, const QModelIndex& index, int indent = 0 );
        
        QList<QPersistentModelIndex> indexList;
        const QAbstractItemModel* model;
        Ui::EntryDialog* ui;
    };
    
    #endif /* ENTRYDIALOG_H */

    entrydelegate.h

    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #ifndef ENTRYDELEGATE_H
    #define ENTRYDELEGATE_H
    
    #include <QItemDelegate>
    
    namespace KDGantt {
        class ConstraintModel;
    }
    
    class EntryDelegate : public QItemDelegate {
    public:
        explicit EntryDelegate( KDGantt::ConstraintModel* constraintModel, QObject* parent = 0 );
        
        bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
        
    private:
        void addConstraint(const QModelIndex & index1, const QModelIndex & index2);
        void setReadOnly(const QModelIndex & index, bool readOnly);
        
        KDGantt::ConstraintModel* constraintModel;
    };
    
    #endif /* ENTRYDELEGATE_H */
    
    
    entrydelegate.cpp
    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #include "entrydelegate.h"
    
    #include "entrydialog.h"
    
    #include <KDGanttConstraintModel>
    #include <KDGanttGlobal>
    #include <QEvent>
    #include <QModelIndex>
    #include <QStandardItemModel>
    #include <QPointer>
    
    EntryDelegate::EntryDelegate( KDGantt::ConstraintModel* constraintModel, QObject* parent )
        : QItemDelegate( parent )
    {
        this->constraintModel = constraintModel;
    }
    
    bool EntryDelegate::editorEvent( QEvent* event, QAbstractItemModel *model, const QStyleOptionViewItem& option, const QModelIndex& index )
    {
        if ( event->type() != QEvent::MouseButtonDblClick )
            return false;
    
        if ( !index.isValid() )
            return QItemDelegate::editorEvent( event, model, option, index );
    
        QPointer<EntryDialog> dialog = new EntryDialog( model );
        dialog->initFrom( index, constraintModel );
        dialog->setWindowTitle( tr( "Edit Entry" ) );
        dialog->exec();  
        if ( !dialog )
            return false;
        
        int row = index.row();
        const QModelIndex parent = index.parent();
        model->setData( model->index( row, 0, parent ), dialog->name() );
        model->setData( model->index( row, 1, parent ), dialog->type() );
        if ( dialog->type() != KDGantt::TypeSummary ) {
            model->setData( model->index( row, 2, parent ), dialog->startDate(), KDGantt::StartTimeRole );
            model->setData( model->index( row, 3, parent ), dialog->endDate(), KDGantt::EndTimeRole );
        }
        model->setData( model->index( row, 4, parent ), dialog->completion() );
        model->setData( model->index( row, 5, parent ), dialog->legend() );
        
        addConstraint( dialog->depends(), model->index( row, 0, parent ) );
        setReadOnly( model->index( row, 0, parent ), dialog->readOnly() );
    
        delete dialog;
        return true;
    }
    
    void EntryDelegate::setReadOnly(const QModelIndex & index, bool readOnly)
    {
        int row = index.row();
        QModelIndex parent = index.parent();
        QStandardItem* item;
        const QStandardItemModel* model = qobject_cast<const QStandardItemModel*>( index.model() );
        if ( !model )
            return;
        
        item = model->itemFromIndex( model->index( row, 0, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
        
        item = model->itemFromIndex( model->index( row, 1, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
        
        item = model->itemFromIndex( model->index( row, 2, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
        
        item = model->itemFromIndex( model->index( row, 3, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
        
        item = model->itemFromIndex( model->index( row, 4, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
    }
    
    void EntryDelegate::addConstraint(const QModelIndex & index1, const QModelIndex & index2)
    {
        if ( !index1.isValid() || !index2.isValid() )
            return;
    
        KDGantt::Constraint c( index1, index2 );
        constraintModel->addConstraint( c );
    }
    entrydialog.cpp
    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #include "entrydialog.h"
    
    #include "ui_entrydialog.h"
    
    #include <KDGanttConstraintModel>
    #include <KDGanttGlobal>
    #include <QAbstractItemModel>
    #include <QDateTime>
    #include <QPersistentModelIndex>
    
    Q_DECLARE_METATYPE( QPersistentModelIndex );
    
    EntryDialog::EntryDialog( const QAbstractItemModel* model, QWidget* parent, Qt::WindowFlags f )
        : QDialog( parent, f ),
          indexList( QList<QPersistentModelIndex>() ),
          ui( new Ui::EntryDialog )
    {
        ui->setupUi( this );
        this->model = model;
        init();
    }
    
    void EntryDialog::init()
    {
        ui->type->addItem( tr( "Event" ), KDGantt::TypeEvent );
        ui->type->addItem( tr( "Task" ), KDGantt::TypeTask );
        ui->type->addItem( tr( "Summary" ), KDGantt::TypeSummary );
        ui->type->addItem( tr( "Multi" ), KDGantt::TypeMulti );
        
        for (int row = 0; row < model->rowCount(); ++row )
            addDependItem( model, model->index( row, 0 ) );
        
        connect( ui->startDate, SIGNAL( dateTimeChanged( const QDateTime& ) ), this, SLOT( updateEndDate( const QDateTime& ) ) );
        connect( ui->readOnly, SIGNAL( toggled( bool ) ), this, SLOT( disableEditing( bool ) ) );
        connect( ui->type, SIGNAL( currentIndexChanged( int ) ), this, SLOT( typeChanged( int ) ) );
        
        ui->startDate->setDateTime( QDateTime::currentDateTime() );
        typeChanged( 0 );
    }
    
    void EntryDialog::initFrom( const QModelIndex & index, const KDGantt::ConstraintModel* constraintModel )
    {
        int row = index.row();
        const QModelIndex parent = index.parent();
        
        ui->name->setText( model->data( model->index( row, 0, parent ) ).toString() );
        ui->legend->setText( model->data( model->index( row, 5, parent ) ).toString() );
        int idx = ui->type->findData( model->data( model->index( row, 1, parent ) ).toInt() );
        ui->type->setCurrentIndex( idx );
        ui->startDate->setDateTime( model->data( model->index( row, 2, parent ), KDGantt::StartTimeRole ).toDateTime() );
        ui->endDate->setDateTime( model->data( model->index( row, 3, parent ), KDGantt::EndTimeRole ).toDateTime() );
        ui->completion->setValue( model->data( model->index( row, 4, parent ) ).toInt() );
        ui->readOnly->setChecked( !(model->flags( model->index( row, 0, parent ) ) & Qt::ItemIsEditable) );
        
        QList<KDGantt::Constraint> constraints = constraintModel->constraintsForIndex( model->index( row, 0, parent ) );
        if ( constraints.isEmpty() )
            return;
        
        QModelIndex constraintIndex;
        for ( int i = 0; i < constraints.size(); ++i ) {
            KDGantt::Constraint constraint = constraints[i];
            if ( constraint.endIndex() == index ) {
                constraintIndex = constraint.startIndex();
                break;
            }
        }
        
        if ( !constraintIndex.isValid() )
            return;
        
        ui->depends->setCurrentIndex( indexList.indexOf( constraintIndex ) + 1 );
    }
    
    void EntryDialog::addDependItem( const QAbstractItemModel* model, const QModelIndex & index, int indent)
    {
        indexList << QPersistentModelIndex( index );
        QString str = QString( "%1%2" ).arg( QString().fill( ' ', indent ) ).arg( model->data( index ).toString() );
        ui->depends->addItem( str );
        
        for (int row = 0; row < model->rowCount( index ); ++row )
            addDependItem( model, model->index( row, 0, index ), indent + 2 );
    }
    
    QString EntryDialog::name() const
    {
        return ui->name->text();
    }
    
    int EntryDialog::type() const
    {
        return ui->type->itemData( ui->type->currentIndex() ).toInt();
    }
    
    QDateTime EntryDialog::startDate() const
    {
        return ui->startDate->dateTime();
    }
    
    QDateTime EntryDialog::endDate() const
    {
        return ui->endDate->dateTime();
    }
    
    int EntryDialog::completion() const
    {
        return ui->completion->value();
    }
    
    void EntryDialog::updateEndDate(const QDateTime & startDate)
    {
        ui->endDate->setMinimumDate( startDate.date() );
        ui->endDate->setMinimumTime( startDate.time() );
    }
    
    bool EntryDialog::readOnly() const
    {
        return ui->readOnly->isChecked();
    }
    
    QModelIndex EntryDialog::depends() const
    {
        if ( ui->depends->currentIndex() == 0 )
            return QModelIndex();
    
        QPersistentModelIndex index = indexList[ ui->depends->currentIndex() - 1 ];
        if ( index.isValid() )
            return index;
        
        return QModelIndex();
    }
    
    QString EntryDialog::legend() const
    {
        return ui->legend->text();
    }
    
    void EntryDialog::disableEditing(bool disable)
    {
        ui->name->setEnabled( !disable );
        ui->type->setEnabled( !disable );
        ui->completion->setEnabled( !disable );
        ui->startDate->setEnabled( !disable );
        ui->endDate->setEnabled( !disable );
        ui->depends->setEnabled( !disable );
    }
    
    void EntryDialog::typeChanged(int index)
    {
        if ( ! index ) {
            ui->label_EndDate->hide();
            ui->endDate->hide();
        } else {
            ui->label_EndDate->show();
            ui->endDate->show();
        }
    }

    mainwindow.cpp
    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #include "mainwindow.h"
    
    #include "ui_mainwindow.h"
    #include "entrydelegate.h"
    #include "entrydialog.h"
    
    #include <algorithm>
    
    #include <KDGanttConstraintModel>
    #include <KDGanttDateTimeGrid>
    #include <KDGanttGraphicsView>
    #include <KDGanttLegend>
    #include <QAbstractItemView>
    #include <QDebug>
    #include <QHeaderView>
    #include <QStandardItemModel>
    #include <QTreeView>
    #include <QCloseEvent>
    #include <QPointer>
    #include <QScrollBar>
    
    class MyStandardItem : public QStandardItem {
    public:
      MyStandardItem( const QVariant& v ) : QStandardItem()
      {
        setData( v, Qt::DisplayRole );
      }
      MyStandardItem( const QString& v ) : QStandardItem()
      {
        setData( v, Qt::DisplayRole );
      }
    };
    
    MainWindow::MainWindow( QWidget* parent, Qt::WindowFlags flags )
        : QMainWindow( parent, flags ),
          smallLegend( 0 ),
          detailedLegend( 0 ),
          ui( new Ui::MainWindow )
    {
        ui->setupUi( this );
    
        initModel();
        initActions();
        initItemDelegate();
        initGrid();
    
        QTreeView* leftView = qobject_cast<QTreeView*>( ui->ganttView->leftView() );
        Q_ASSERT( leftView );
        leftView->setColumnHidden( 1, true );
        leftView->setColumnHidden( 2, true );
        leftView->setColumnHidden( 3, true );
        leftView->setColumnHidden( 4, true );
        leftView->setColumnHidden( 5, true );
        leftView->header()->setStretchLastSection( true );
    
        connect( ui->ganttView->leftView(), SIGNAL( customContextMenuRequested( const QPoint& ) ),
                 this, SLOT( showContextMenu( const QPoint& ) ) );
        connect( ui->ganttView->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
                 this, SLOT( enableActions( const QItemSelection& ) ) );
    }
    
    MainWindow::~MainWindow()
    {
    }
    
    void MainWindow::closeEvent(QCloseEvent *event)
    {
        delete smallLegend;
        delete detailedLegend;
        event->accept();
    }
    
    void MainWindow::initModel()
    {
        model = new QStandardItemModel( 0, 6, this );
        model->setHeaderData( 0, Qt::Horizontal, tr( "Tree View of Entries" ) );
        ui->ganttView->setModel( model );
    
        QStandardItemModel* lmodel = new QStandardItemModel;
        lmodel->appendRow( QList<QStandardItem*>()
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( KDGantt::TypeEvent )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QString::fromLatin1("Event") ) );
        lmodel->appendRow( QList<QStandardItem*>()
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( KDGantt::TypeTask )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QString::fromLatin1("Task") ) );
        lmodel->appendRow( QList<QStandardItem*>()
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( KDGantt::TypeSummary )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QVariant() )
            << new MyStandardItem( QString::fromLatin1("Summary") ) );
    
        smallLegend = new KDGantt::Legend();
        smallLegend->setWindowTitle( tr( "Legend" ) );
        smallLegend->show();
        smallLegend->setModel( lmodel );
    
        detailedLegend = new KDGantt::Legend();
        detailedLegend->setWindowTitle( tr( "List" ) );
        detailedLegend->show();
        detailedLegend->setModel( model );
    
        constraintModel = new KDGantt::ConstraintModel( this );
        ui->ganttView->setConstraintModel( constraintModel );
    }
    
    void MainWindow::initActions()
    {
        newEntryAction = new QAction( tr( "New entry" ), this );
        newEntryAction->setShortcut( QKeySequence::New );
        connect( newEntryAction, SIGNAL( triggered() ), this, SLOT( addNewEntry() ) );
    
        removeEntryAction = new QAction( tr( "Remove entry" ), this );
        removeEntryAction->setShortcut( QKeySequence::Delete );
        connect( removeEntryAction, SIGNAL( triggered() ), this, SLOT( removeEntry() ) );
    
        zoomInAction = new QAction( tr( "Zoom In" ), this );
        zoomInAction->setShortcut( QKeySequence::ZoomIn );
        connect( zoomInAction, SIGNAL( triggered() ), this, SLOT( zoomIn() ) );
    
        zoomOutAction = new QAction( tr( "Zoom Out" ), this );
        zoomOutAction->setShortcut( QKeySequence::ZoomOut );
        connect( zoomOutAction, SIGNAL( triggered() ), this, SLOT( zoomOut() ) );
    
        zoomFitAction = new QAction( tr( "Zoom to Fit" ), this );
        connect( zoomFitAction, SIGNAL( triggered() ), this, SLOT( zoomFit() ) );
    
        ui->ganttView->leftView()->setContextMenuPolicy( Qt::CustomContextMenu );
        ui->ganttView->leftView()->addAction( newEntryAction );
        ui->ganttView->leftView()->addAction( removeEntryAction );
    
        QMenu* entryMenu = menuBar()->addMenu( tr( "Entry" ) );
        entryMenu->addAction( newEntryAction );
        entryMenu->addAction( removeEntryAction );
    
        QMenu* zoomMenu = menuBar()->addMenu( tr( "Zoom" ) );
        zoomMenu->addAction( zoomInAction );
        zoomMenu->addAction( zoomOutAction );
        zoomMenu->addAction( zoomFitAction );
        
        QMenu* scaleMenu = menuBar()->addMenu( tr( "Scale" ) );
        
        scaleMenu->addAction( tr( "Auto" ), this, SLOT(scaleAuto()) );
        scaleMenu->addAction( tr( "Hour" ), this, SLOT(scaleHour()) );
        scaleMenu->addAction( tr( "Day" ), this, SLOT(scaleDay()) );
        scaleMenu->addAction( tr( "Week" ), this, SLOT(scaleWeek()) );
        scaleMenu->addAction( tr( "Month" ), this, SLOT(scaleMonth()) );
    
        enableActions( QItemSelection() );
    }
    
    void MainWindow::initItemDelegate()
    {
        EntryDelegate* delegate = new EntryDelegate( constraintModel, this );
        ui->ganttView->leftView()->setItemDelegate( delegate );
    }
    
    void MainWindow::initGrid()
    {
        grid = new KDGantt::DateTimeGrid();
        grid->setDayWidth( 70 );
        ui->ganttView->setGrid( grid );
    }
    
    void MainWindow::showContextMenu( const QPoint& pos )
    {
        if ( !ui->ganttView->leftView()->indexAt( pos ).isValid() )
            ui->ganttView->selectionModel()->clearSelection();
    
        QMenu menu( ui->ganttView->leftView() );
        menu.addAction( newEntryAction );
        menu.addAction( removeEntryAction );
        menu.exec( ui->ganttView->leftView()->viewport()->mapToGlobal( pos ) );
    }
    
    void MainWindow::enableActions(const QItemSelection & selected)
    {
        if ( selected.indexes().isEmpty() ) {
            newEntryAction->setEnabled( true );
            removeEntryAction->setEnabled( false );
            return;
        }
    
        QModelIndex selectedIndex = selected.indexes()[0];
    
        if ( model->data( model->index( selectedIndex.row(), 1 ) ) == KDGantt::TypeEvent ||
            model->data( model->index( selectedIndex.row(), 1 ) ) == KDGantt::TypeTask ) {
            newEntryAction->setEnabled( false );
            removeEntryAction->setEnabled( true );
            return;
        }
    
        newEntryAction->setEnabled( true );
        removeEntryAction->setEnabled( true );
    }
    
    void MainWindow::addNewEntry()
    {
        QPointer<EntryDialog> dialog = new EntryDialog( model );
        dialog->setWindowTitle( tr( "New Entry") );
        if ( dialog->exec() == QDialog::Rejected || !dialog ) {
            delete dialog;
            return;
        }
    
        QModelIndexList selectedIndexes = ui->ganttView->selectionModel()->selectedIndexes();
        const QModelIndex parent = selectedIndexes.value( 0 );
    
        if ( !model->insertRow( model->rowCount( parent ), parent ) )
            return;
    
        int row = model->rowCount( parent ) - 1;
        if ( row == 0 && parent.isValid() )
            model->insertColumns( model->columnCount( parent ), 5, parent );
    
        model->setData( model->index( row, 0, parent ), dialog->name() );
        model->setData( model->index( row, 1, parent ), dialog->type() );
        if ( dialog->type() != KDGantt::TypeSummary ) {
            model->setData( model->index( row, 2, parent ), dialog->startDate(), KDGantt::StartTimeRole );
            model->setData( model->index( row, 3, parent ), dialog->endDate(), KDGantt::EndTimeRole );
        }
        model->setData( model->index( row, 4, parent ), dialog->completion() );
        const QString legend( dialog->legend() );
        if ( ! legend.isEmpty() )
            model->setData( model->index( row, 5, parent ), legend );
    
        addConstraint( dialog->depends(), model->index( row, 0, parent ) );
        setReadOnly( model->index( row, 0, parent ), dialog->readOnly() );
    
        delete dialog;
    }
    
    void MainWindow::setReadOnly(const QModelIndex & index, bool readOnly)
    {
        int row = index.row();
        const QModelIndex parent = index.parent();
        QStandardItem* item;
    
        item = model->itemFromIndex( model->index( row, 0, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
    
        item = model->itemFromIndex( model->index( row, 1, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
    
        item = model->itemFromIndex( model->index( row, 2, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
    
        item = model->itemFromIndex( model->index( row, 3, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
    
        item = model->itemFromIndex( model->index( row, 4, parent ) );
        item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
    }
    
    void MainWindow::addConstraint(const QModelIndex & index1, const QModelIndex & index2)
    {
        if ( !index1.isValid() || !index2.isValid() )
            return;
    
        KDGantt::Constraint c( index1, index2 );
        ui->ganttView->constraintModel()->addConstraint( c );
    }
    
    void MainWindow::removeEntry()
    {
        QModelIndexList selectedIndexes = ui->ganttView->selectionModel()->selectedIndexes();
        QModelIndex index = selectedIndexes.value( 0 );
    
        if ( !index.isValid() )
            return;
    
        model->removeRow( index.row(), index.parent() );
    }
    
    void MainWindow::zoomIn()
    {
        qreal dayWidth = grid->dayWidth() + 10;
        if ( dayWidth > 400 )
            grid->setScale( KDGantt::DateTimeGrid::ScaleHour );
    
        grid->setDayWidth( dayWidth );
    }
    
    void MainWindow::zoomOut()
    {
        qreal dayWidth = grid->dayWidth() - 10;
        if ( dayWidth < 10 )
            dayWidth = 10;
    
        if ( dayWidth <= 400 )
            grid->setScale( KDGantt::DateTimeGrid::ScaleDay );
    
        grid->setDayWidth( dayWidth );
    }
    
    void MainWindow::zoomFit()
    {
        QModelIndexList selectedIndexes = ui->ganttView->selectionModel()->selectedIndexes();
    
        if ( selectedIndexes.isEmpty() ) {
            return;
        }
    
        KDGantt::Span span;
        Q_FOREACH( QModelIndex idx, selectedIndexes ) {
            const KDGantt::Span s = grid->mapToChart( grid->model()->index( idx.row(), 0 ) );
            if ( span.isValid() ) {
                span = span.expandedTo( s );
            } else {
                span = s;
            }
        }
    
        span.setLength( span.length()+20 );
        span.setStart( span.start()-10 );
    
        qDebug() << selectedIndexes << span;
    
        const qreal view_width = ui->ganttView->graphicsView()->viewport()->width();
        const QDateTime start = grid->mapFromChart( span.start() ).value<QDateTime>();
        const QDateTime end = grid->mapFromChart( span.end() ).value<QDateTime>();
    
        qreal delta = start.date().daysTo(end.date());
        delta += start.time().msecsTo(end.time())/( 1000.*24.*60.*60. );
    
        qDebug() << view_width << "/" << delta;
        grid->setDayWidth( view_width/( std::max( (qreal)1., delta ) ) );
        qDebug() << "daywidth set to" << grid->dayWidth();
        qDebug() << "start scroll to" << grid->mapToChart( start );
        ui->ganttView->graphicsView()->horizontalScrollBar()->setValue( grid->mapToChart( start ) );
    }
    
    void MainWindow::scaleAuto()
    {
        KDGantt::DateTimeGrid* grid = static_cast<KDGantt::DateTimeGrid*>(ui->ganttView->grid());
        grid->setScale( KDGantt::DateTimeGrid::ScaleAuto );
    }
    
    void MainWindow::scaleHour()
    {
        KDGantt::DateTimeGrid* grid = static_cast<KDGantt::DateTimeGrid*>(ui->ganttView->grid());
        grid->setScale( KDGantt::DateTimeGrid::ScaleHour );
    }
    
    void MainWindow::scaleDay()
    {
        KDGantt::DateTimeGrid* grid = static_cast<KDGantt::DateTimeGrid*>(ui->ganttView->grid());
        grid->setScale( KDGantt::DateTimeGrid::ScaleDay );
    }
    
    void MainWindow::scaleWeek()
    {
        KDGantt::DateTimeGrid* grid = static_cast<KDGantt::DateTimeGrid*>(ui->ganttView->grid());
        grid->setScale( KDGantt::DateTimeGrid::ScaleWeek );
    }
    
    void MainWindow::scaleMonth()
    {
        KDGantt::DateTimeGrid* grid = static_cast<KDGantt::DateTimeGrid*>(ui->ganttView->grid());
        grid->setScale( KDGantt::DateTimeGrid::ScaleMonth );
    }
        

    main.cpp

    /****************************************************************************
    ** Copyright (C) 2001-2018 Klaralvdalens Datakonsult AB.  All rights reserved.
    **
    ** This file is part of the KD Chart library.
    **
    ** Licensees holding valid commercial KD Chart licenses may use this file in
    ** accordance with the KD Chart Commercial License Agreement provided with
    ** the Software.
    **
    **
    ** This file may be distributed and/or modified under the terms of the
    ** GNU General Public License version 2 and version 3 as published by the
    ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ** Contact info@kdab.com if any conditions of this licensing are not
    ** clear to you.
    **
    **********************************************************************/
    
    #include <QApplication>
    
    #include "mainwindow.h"
    
    int main( int argc, char* argv[] )
    {
        QApplication app( argc, argv );
        
        MainWindow mainWin;
        mainWin.show();
        
        return app.exec();
    }

    ui_mainwindow.h

    /********************************************************************************
    ** Form generated from reading UI file 'mainwindow.ui'
    **
    ** Created by: Qt User Interface Compiler version 5.12.2
    **
    ** WARNING! All changes made in this file will be lost when recompiling UI file!
    ********************************************************************************/
    
    #ifndef UI_MAINWINDOW_H
    #define UI_MAINWINDOW_H
    
    #include <KDGanttView>
    #include <QtCore/QVariant>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QMainWindow>
    #include <QtWidgets/QMenuBar>
    #include <QtWidgets/QStatusBar>
    #include <QtWidgets/QVBoxLayout>
    #include <QtWidgets/QWidget>
    
    QT_BEGIN_NAMESPACE
    
    class Ui_MainWindow
    {
    public:
        QWidget *centralwidget;
        QVBoxLayout *vboxLayout;
        KDGantt::View *ganttView;
        QMenuBar *menubar;
        QStatusBar *statusbar;
    
        void setupUi(QMainWindow *MainWindow)
        {
            if (MainWindow->objectName().isEmpty())
                MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
            MainWindow->resize(556, 330);
            MainWindow->setContextMenuPolicy(Qt::DefaultContextMenu);
            centralwidget = new QWidget(MainWindow);
            centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
            vboxLayout = new QVBoxLayout(centralwidget);
            vboxLayout->setObjectName(QString::fromUtf8("vboxLayout"));
            ganttView = new KDGantt::View(centralwidget);
            ganttView->setObjectName(QString::fromUtf8("ganttView"));
    
            vboxLayout->addWidget(ganttView);
    
            MainWindow->setCentralWidget(centralwidget);
            menubar = new QMenuBar(MainWindow);
            menubar->setObjectName(QString::fromUtf8("menubar"));
            menubar->setGeometry(QRect(0, 0, 556, 29));
            MainWindow->setMenuBar(menubar);
            statusbar = new QStatusBar(MainWindow);
            statusbar->setObjectName(QString::fromUtf8("statusbar"));
            MainWindow->setStatusBar(statusbar);
    
            retranslateUi(MainWindow);
    
            QMetaObject::connectSlotsByName(MainWindow);
        } // setupUi
    
        void retranslateUi(QMainWindow *MainWindow)
        {
            MainWindow->setWindowTitle(QApplication::translate("MainWindow", "KD Gantt Example", nullptr));
        } // retranslateUi
    
    };
    
    namespace Ui {
        class MainWindow: public Ui_MainWindow {};
    } // namespace Ui
    
    QT_END_NAMESPACE
    
    #endif // UI_MAINWINDOW_H

     

    ui_entrydialog.h

    /********************************************************************************
    ** Form generated from reading UI file 'entrydialog.ui'
    **
    ** Created by: Qt User Interface Compiler version 5.12.2
    **
    ** WARNING! All changes made in this file will be lost when recompiling UI file!
    ********************************************************************************/
    
    #ifndef UI_ENTRYDIALOG_H
    #define UI_ENTRYDIALOG_H
    
    #include <QtCore/QVariant>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QCheckBox>
    #include <QtWidgets/QComboBox>
    #include <QtWidgets/QDateTimeEdit>
    #include <QtWidgets/QDialog>
    #include <QtWidgets/QDialogButtonBox>
    #include <QtWidgets/QGridLayout>
    #include <QtWidgets/QHBoxLayout>
    #include <QtWidgets/QLabel>
    #include <QtWidgets/QLineEdit>
    #include <QtWidgets/QSpacerItem>
    #include <QtWidgets/QSpinBox>
    #include <QtWidgets/QVBoxLayout>
    
    QT_BEGIN_NAMESPACE
    
    class Ui_EntryDialog
    {
    public:
        QVBoxLayout *vboxLayout;
        QHBoxLayout *hboxLayout;
        QLabel *label;
        QLineEdit *name;
        QHBoxLayout *hboxLayout1;
        QLabel *label_6;
        QLineEdit *legend;
        QGridLayout *gridLayout;
        QLabel *label_2;
        QComboBox *type;
        QSpacerItem *spacerItem;
        QLabel *label_3;
        QDateTimeEdit *startDate;
        QLabel *label_5;
        QSpinBox *completion;
        QLabel *label_EndDate;
        QDateTimeEdit *endDate;
        QCheckBox *readOnly;
        QLabel *dependsLabel;
        QComboBox *depends;
        QDialogButtonBox *buttonBox;
    
        void setupUi(QDialog *EntryDialog)
        {
            if (EntryDialog->objectName().isEmpty())
                EntryDialog->setObjectName(QString::fromUtf8("EntryDialog"));
            EntryDialog->resize(439, 206);
            vboxLayout = new QVBoxLayout(EntryDialog);
            vboxLayout->setObjectName(QString::fromUtf8("vboxLayout"));
            hboxLayout = new QHBoxLayout();
            hboxLayout->setObjectName(QString::fromUtf8("hboxLayout"));
            label = new QLabel(EntryDialog);
            label->setObjectName(QString::fromUtf8("label"));
    
            hboxLayout->addWidget(label);
    
            name = new QLineEdit(EntryDialog);
            name->setObjectName(QString::fromUtf8("name"));
    
            hboxLayout->addWidget(name);
    
    
            vboxLayout->addLayout(hboxLayout);
    
            hboxLayout1 = new QHBoxLayout();
            hboxLayout1->setObjectName(QString::fromUtf8("hboxLayout1"));
            label_6 = new QLabel(EntryDialog);
            label_6->setObjectName(QString::fromUtf8("label_6"));
    
            hboxLayout1->addWidget(label_6);
    
            legend = new QLineEdit(EntryDialog);
            legend->setObjectName(QString::fromUtf8("legend"));
    
            hboxLayout1->addWidget(legend);
    
    
            vboxLayout->addLayout(hboxLayout1);
    
            gridLayout = new QGridLayout();
            gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
            label_2 = new QLabel(EntryDialog);
            label_2->setObjectName(QString::fromUtf8("label_2"));
    
            gridLayout->addWidget(label_2, 0, 0, 1, 1);
    
            type = new QComboBox(EntryDialog);
            type->setObjectName(QString::fromUtf8("type"));
    
            gridLayout->addWidget(type, 0, 1, 1, 1);
    
            spacerItem = new QSpacerItem(41, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    
            gridLayout->addItem(spacerItem, 0, 2, 1, 1);
    
            label_3 = new QLabel(EntryDialog);
            label_3->setObjectName(QString::fromUtf8("label_3"));
    
            gridLayout->addWidget(label_3, 0, 3, 1, 1);
    
            startDate = new QDateTimeEdit(EntryDialog);
            startDate->setObjectName(QString::fromUtf8("startDate"));
            startDate->setCalendarPopup(true);
    
            gridLayout->addWidget(startDate, 0, 4, 1, 1);
    
            label_5 = new QLabel(EntryDialog);
            label_5->setObjectName(QString::fromUtf8("label_5"));
    
            gridLayout->addWidget(label_5, 1, 0, 1, 1);
    
            completion = new QSpinBox(EntryDialog);
            completion->setObjectName(QString::fromUtf8("completion"));
            completion->setMaximum(100);
    
            gridLayout->addWidget(completion, 1, 1, 1, 1);
    
            label_EndDate = new QLabel(EntryDialog);
            label_EndDate->setObjectName(QString::fromUtf8("label_EndDate"));
    
            gridLayout->addWidget(label_EndDate, 1, 3, 1, 1);
    
            endDate = new QDateTimeEdit(EntryDialog);
            endDate->setObjectName(QString::fromUtf8("endDate"));
            endDate->setCalendarPopup(true);
    
            gridLayout->addWidget(endDate, 1, 4, 1, 1);
    
            readOnly = new QCheckBox(EntryDialog);
            readOnly->setObjectName(QString::fromUtf8("readOnly"));
    
            gridLayout->addWidget(readOnly, 2, 0, 1, 2);
    
            dependsLabel = new QLabel(EntryDialog);
            dependsLabel->setObjectName(QString::fromUtf8("dependsLabel"));
    
            gridLayout->addWidget(dependsLabel, 2, 3, 1, 1);
    
            depends = new QComboBox(EntryDialog);
            depends->addItem(QString());
            depends->setObjectName(QString::fromUtf8("depends"));
    
            gridLayout->addWidget(depends, 2, 4, 1, 1);
    
    
            vboxLayout->addLayout(gridLayout);
    
            buttonBox = new QDialogButtonBox(EntryDialog);
            buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
            buttonBox->setOrientation(Qt::Horizontal);
            buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    
            vboxLayout->addWidget(buttonBox);
    
    
            retranslateUi(EntryDialog);
            QObject::connect(buttonBox, SIGNAL(accepted()), EntryDialog, SLOT(accept()));
            QObject::connect(buttonBox, SIGNAL(rejected()), EntryDialog, SLOT(reject()));
    
            QMetaObject::connectSlotsByName(EntryDialog);
        } // setupUi
    
        void retranslateUi(QDialog *EntryDialog)
        {
            label->setText(QApplication::translate("EntryDialog", "Name", nullptr));
            label_6->setText(QApplication::translate("EntryDialog", "Legend", nullptr));
            label_2->setText(QApplication::translate("EntryDialog", "Type", nullptr));
            label_3->setText(QApplication::translate("EntryDialog", "Start date", nullptr));
            label_5->setText(QApplication::translate("EntryDialog", "Completion", nullptr));
            completion->setSuffix(QApplication::translate("EntryDialog", "%", nullptr));
            label_EndDate->setText(QApplication::translate("EntryDialog", "End date", nullptr));
            readOnly->setText(QApplication::translate("EntryDialog", "Read Only", nullptr));
            dependsLabel->setText(QApplication::translate("EntryDialog", "Depends on", nullptr));
            depends->setItemText(0, QApplication::translate("EntryDialog", "- None -", nullptr));
    
            Q_UNUSED(EntryDialog);
        } // retranslateUi
    
    };
    
    namespace Ui {
        class EntryDialog: public Ui_EntryDialog {};
    } // namespace Ui
    
    QT_END_NAMESPACE
    
    #endif // UI_ENTRYDIALOG_H

     

    legend_example.pro

    #include( $${TOP_SOURCE_DIR}/examples/examples.pri )
    
    HEADERS += mainwindow.h \
               entrydialog.h \
               entrydelegate.h
    
    SOURCES += main.cpp \
               mainwindow.cpp \
               entrydialog.cpp \
               entrydelegate.cpp
    
    FORMS += mainwindow.ui \
             entrydialog.ui
    
    greaterThan(QT_MAJOR_VERSION, 4):QT += printsupport
    
    message( "Building ''$$TARGET'' using LIBS ''$$LIBS''" )
    
    unix|win32: LIBS += -LE:/Qt/Qt5.12.2/5.12.2/msvc2015_64/lib/ -lkdchartd
    
    INCLUDEPATH += E:/Qt/Qt5.12.2/5.12.2/msvc2015_64/include
    DEPENDPATH += E:/Qt/Qt5.12.2/5.12.2/msvc2015_64/include
    
    INCLUDEPATH += E:/Qt/Qt5.12.2/5.12.2/msvc2015_64/include/KDChart
    DEPENDPATH += E:/Qt/Qt5.12.2/5.12.2/msvc2015_64/include/KDChart
    
    INCLUDEPATH += E:/Qt/Qt5.12.2/5.12.2/msvc2015_64/include/KDGantt
    DEPENDPATH += E:/Qt/Qt5.12.2/5.12.2/msvc2015_64/include/KDGantt

     

     

     

    运行效果:


    ----------------------------------------------------------------

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(3,0,0x1d563494fc0,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    QWindowsWindow::setGeometry: Unable to set geometry 439x206+734+412 on QWidgetWindow/'EntryDialogWindow'. Resulting geometry: 452x206+734+412 (frame: 9, 38, 9, 9, custom margin: 0, 0, 0, 0, minimum size: 452x206, maximum size: 16777215x16777215).

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime

    Skipping item QModelIndex(4,0,0x1d564202660,KDGantt::ProxyModel(0x1d55f32cdd8)) because it doesn't contain QDateTime


    ----------------------------------------------------------------








    如果想修改为自定义样式:
    参考:https://www.cnblogs.com/qnkk123/p/7685477.html
    设置每个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();
    }

    拖动事件:

    在文件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()); // 显示在上面

    这部分转自:

    https://www.cnblogs.com/qnkk123/p/7685477.html

     

    转载于:https://www.cnblogs.com/herd/p/11203195.html

    展开全文
  • Qt4 实现甘特图效果

    2018-07-25 20:37:02
    自定义QAbstractItemView实现甘特图效果,本工程内的代码可参考Qt4的chart例子代码
  • Qt 使用 kdChart 自定义甘特图

    千次阅读 2018-05-29 10:02:37
    Qt绘制甘特图,网上找了很久,只找到kdChart,编译很简单,我是Qt 5.5.0 + VS2013,直接编译就行,kdChart有甘特图例子:但是和项目设计有点出入,所以自定义部分显示:1.左边的是QTreeView,并为其添加委托,控件...

     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()); // 显示在上面




    展开全文
  • Qt 一、甘特图之Tree

    千次阅读 2018-02-02 15:08:28
    甘特图主要有两大块界面:1、Tree; 2、Task的任务条显示;这里先介绍Tree的画法。 1、先画表头,根据列是否隐藏(画显示的)画列的宽度、列名、列与列之间的分割线 我用一个ColumnData类来封装列信息,变量有否...

    甘特图主要有两大块界面:1、Tree;  2、Task的任务条显示;这里先介绍Tree的画法。

    1、先画表头,根据列是否隐藏(画显示的)画列的宽度、列名、列与列之间的分割线

    我用一个ColumnData类来封装列信息,变量有否可隐藏、列名、列宽(列是可拉伸的,也是可移动的)

    再用一个类RowColumnData来保存所有列的结构体ColumnData、所有行高(行高是可以改变的);初始化所有的列的名字、是否隐藏属性、列宽就可开始画表头了:

    qreal columnX = 0;

    ColumnData *colData = Q_NULLPTR;//每一列的结构体

    QList<ColumnData *>  m_columnDataList;//所有列

    qreal verLine = 0;//画表头竖线

    for (int i = 0; i < m_columnDataList.size(); i++) {

     colData = m_columnDataList.at(i);

     if (!colData || colData->m_isHide)

      continue;

     columnX += colData->m_columnWidth;

    verLine = columnX - m_horBarValue; //m_horBarValue为水平滚动条

    painter.drawText(QRectF(verLine -colData->m_columnWidth, 0, colData->m_columnWidth, 40), Qt::AlignCenter, colData->m_columnName);//画列名

    painter.drawLine(verLine, 0, verLine, 40);//画竖线 

    }

    2、画Tree的主体

    每个Task为一行,每一行里,根据获得的列名画上Task想对应的信息,如果Task为父亲,就会在它的左侧画一个带有+-号的小矩形,点击此矩形可以隐藏显示它的孩子(在这里做一个处理,当parentTask它的孩子都隐藏时,它孩子的隐藏ID都为它的ID,Task的Hide ID为0是显示的,否则为隐藏的,到展开节点时,不是它的所有subTask都展开,而是隐藏ID为它的ID的展开)画Tree上的Task根据Task的层级缩进一定的距离来画




    展开全文
  • Qt轮播动画实现

    2020-05-17 00:30:04
    目录Qt轮播动画实现新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一...
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • qt+libtorch+opencv调用u2net实现图像二值分割内容介绍整体流程模型转化qt安装在qt中配置libtorch环境和opencv环境插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居...
  • QtCreator4.11.1 64位安装2、QWT6.1.4安装实现插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的...
  • 这里写自定义目录标题QT4.7的UI界面设计功能效果展示文件机制UI功能详述信号与槽机制顶部菜单栏设定弹窗显示关于界面/窗口背景直接设定背景通过TextBrowser间接设定背景极可能出现的两种无厘头错误小结注释也是必不...
  • 有没有帮忙看qt程序,写流程

    千次阅读 2019-05-10 23:16:45
    有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • 实现过程与步骤详解Qt的下载安装功能包创建带有GUI的ROS工作空间Qt配置如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...
  • 这里写自定义目录标题QtChart实现Y轴单曲线,X轴实时时间轴前言在这里插入代码片欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的...
  • 打开脚本文件选择编译器编译选项生成需要的库文件在Qt中的使用创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章...
  • Qt图表bartchart新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...
  • QT5 项目结构

    2020-02-14 18:48:30
    QT项目.pro项目文件QT内存回收机制信号槽原生信号槽自定义信号槽拓展对话框模态对话框非模态对话框如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义...
  • Qt KDChart编译

    2019-07-17 19:19:00
    最近开发中需要用到甘特图,感觉KDChart这个插件不错,在这里记录一下编译过程(其实很好编译,而且一次性就过了) 下载,kdchart-2.6.1-source,解压 打开src目录,用Qt Creator打开src.pro 我用的是msvc_2015_...
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • Qt Signals and Slots

    2021-01-10 12:39:37
    Qt Signals and Slots简介用法特性功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants...
  • QT动态资源加载

    2020-03-16 15:22:36
    QT动态资源加载编译命令欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左...
  • QT Quick 入门一

    2019-04-25 23:16:28
    QT Quick 入门一代码解析新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建...
  • QT的firstblood

    2019-06-30 03:20:34
    QT的安装和使用欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 173
精华内容 69
关键字:

qt甘特图