qt继承QAbstractItemView实现甘特图类

参考QAbstractItemView,QTableView:https://blog.csdn.net/lsfreeing/article/details/78269033
参考Qt模型/视图原理(4):自定义视图(QAbstractItemView):https://blog.csdn.net/hyongilfmmm/article/details/83099833
参考Qt官方例子:Chart Example
参考Qt QStandardItemModel用法(超级详细):http://c.biancheng.net/view/1869.html

首先说一下自己对于QAbstractItemView的理解:

1.为什么要使用这个类
为了使模型和视图分开,在我理解模型就是数据,视图就是在屏幕上显示需要给用户看的数据,以一种更直观更容易理解的样式呈现。当然也可以自己定义结构体来管理一份数据来进行刷新。但是这里qt提供了这样一个类专门来干这件事,QAbstractItemModel类来管理模型(我觉得的就是数据),QAbstractItemView类进行视图绘制,一旦模型数据改变,视图会自动根据模型数据进行改变。

2.使用这个类干什么
说的不一定对。我把该类看作是一块区域,在这个区域里你可以用qt的画笔painter来绘制你想要呈现的任何图形样式,当然需要模型数据进行驱动。

以下我觉得比较标准还比较容易理解的定义:
自定义视图(QAbstractItemView),是每一个使用QAbstractItemModel的标准视图的基类。QAbstractItemView是抽象类从而不能实例化。通过信号与槽机制,提供一个标准的接口与model进行交互操作,使子类能够在模型的变化中保持最新。这个类为键盘和鼠标导航、窗口滚动、项编辑和选择提供了标准支持。

KDGantt.h

#pragma once

#include <QMainWindow>

QT_BEGIN_NAMESPACE
class QAbstractItemModel;
class QAbstractItemView;
class QItemSelectionModel;
QT_END_NAMESPACE

class KDGantt : public QMainWindow
{
    Q_OBJECT

public:
    KDGantt();

private:
    void setupModel();
    void setupViews();


private:

    QAbstractItemModel* gantt_model;
    QAbstractItemView* gantt_chart;
};

KDGantt.cpp

#pragma execution_character_set("utf-8")
#include <QtWidgets>

#include "KDGantt.h"
#include "GanttView.h"

KDGantt::KDGantt()
{
    setupModel();
    setupViews();
    gantt_model->insertRows(0, 1, QModelIndex());
    gantt_model->setData(gantt_model->index(0, 0, QModelIndex()), "1");
    gantt_model->setData(gantt_model->index(0, 1, QModelIndex()), "3:00");
    gantt_model->setData(gantt_model->index(0, 2, QModelIndex()), "14:00");
    gantt_model->setData(gantt_model->index(0, 3, QModelIndex()), "8:00");
}

void KDGantt::setupModel()
{
    gantt_model = new QStandardItemModel(0, 4, this);
    gantt_model->setHeaderData(0, Qt::Horizontal, tr("id"));
    gantt_model->setHeaderData(1, Qt::Horizontal, tr("起始时间"));
    gantt_model->setHeaderData(2, Qt::Horizontal, tr("终止时间"));
    gantt_model->setHeaderData(3, Qt::Horizontal, tr("进程"));
}

void KDGantt::setupViews()
{
    QSplitter* splitter = new QSplitter;
    QTableView* table = new QTableView;
    gantt_chart = new GanttView;
    splitter->addWidget(table);
    splitter->addWidget(gantt_chart);
    splitter->setStretchFactor(0, 0);
    splitter->setStretchFactor(1, 1);

    table->setModel(gantt_model);
    table->setModel(gantt_model);

    QHeaderView* headerView = table->horizontalHeader();
    headerView->setStretchLastSection(true);
   
    setCentralWidget(splitter);
}

GanttView.h

#pragma once

#include <QAbstractItemView>

class GanttView : public QAbstractItemView
{
	Q_OBJECT

public:
	GanttView(QWidget *parent = 0);
	~GanttView();

	// 用于计算项目所占据的矩形(即位置和大小)
	// 该函数在初次运行时便会由Qt调用,调用次数依模型而定
	// 参数index包含模型的索引,index会在调用时循环传递
	virtual QRect visualRect(const QModelIndex& index) const override;

	// 返回鼠标光标所在位置的项目的索引
	// 在点击鼠标时Qt会调用,参数point包含了鼠标光标的坐标位置(视图坐标)
	virtual QModelIndex indexAt(const QPoint& point) const override;

	//以下3个函数用于计算视图的滚动,不需要滚动不需要实现
	virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible) override;
	virtual int horizontalOffset() const override;
	virtual int verticalOffset() const override;

protected:
	//用于处理键盘按键,不处理不用实现
	virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;

	//是否隐藏项目,不需要直接返回0
	virtual bool isIndexHidden(const QModelIndex& index) const override;

	//以下2个函数主要用于处理对项目的选择,当选择视图中的项目时,Qt才会调用他们。
	//当不需要选择项目时,以下两个函数可以不用实现。
	//参数rect包含了所选项目的矩形(位置和大小,使用视图坐标)
	//参数flags包含了选择项目时的选择标志。
	virtual void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command) override;
	//此函数用于计算所有被选择的项目占据的区域(即位置和大小)。
	//参数s包含了所选择的项目的范围。
	virtual QRegion visualRegionForSelection(const QItemSelection& selection) const override;

	void paintEvent(QPaintEvent* event) override;
	void resizeEvent(QResizeEvent* event) override;
	//根据滚动条设置偏移
	virtual void scrollContentsBy(int dx, int dy) override;

private:
	//缩小后垂直水平滚动条计算大小
	void updateGeometries() override;
	
	//转换时间
	//int changeTime(QString _time);

private:
	int time_wide;	//时间轴宽度
	int time_high;	//时间轴高度
	int total_size;	//总尺寸

};

GanttView.cpp

#include "GanttView.h"
#include <QtWidgets>

GanttView::GanttView(QWidget *parent)
	: QAbstractItemView(parent)
{
	//水平垂直滚动条
	horizontalScrollBar()->setRange(0, 0);
	verticalScrollBar()->setRange(0, 0);

	total_size = 1600;
	time_wide = 1440;
	time_high = 30;
}

GanttView::~GanttView()
{
}

QRect GanttView::visualRect(const QModelIndex& index) const
{
	return QRect();
}

void GanttView::scrollTo(const QModelIndex& index, ScrollHint hint /*= EnsureVisible*/)
{
	return;
}

QModelIndex GanttView::indexAt(const QPoint& point) const
{
	return QModelIndex();
}

QModelIndex GanttView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
	return QModelIndex();
}

int GanttView::horizontalOffset() const
{
	return horizontalScrollBar()->value();
}

int GanttView::verticalOffset() const
{
	return verticalScrollBar()->value();
}

bool GanttView::isIndexHidden(const QModelIndex& index) const
{
	return 0;
}

void GanttView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command)
{
	return;
}

QRegion GanttView::visualRegionForSelection(const QItemSelection& selection) const
{
	return QRegion();
}

void GanttView::paintEvent(QPaintEvent* event)
{
	QPainter time_axis_painter(viewport());
	//初始偏移量
	time_axis_painter.translate(80, 30);
	//根据滚动条变化设置偏移量
	time_axis_painter.translate(0 - horizontalScrollBar()->value(), 0 - verticalScrollBar()->value());

	QFont axis_font("宋体", 5);
	time_axis_painter.setFont(axis_font);

	QPen time_axis_pen;
	time_axis_pen.setWidth(1.5);
	time_axis_pen.setColor(QColor(0, 0, 0));

	//画时间轴
	time_axis_painter.setPen(time_axis_pen);
	//画时间轴矩形
	time_axis_painter.drawRect(0, 0, time_wide, time_high);

	//画时间轴大刻度线and标尺
	int average = time_wide / 24;
	int interval = average;
	int min_interval = interval / 10;
	time_axis_painter.drawText(0, time_high + 15, "0:00");
	for (int min_axis=0;min_axis<10;min_axis++)
	{
		time_axis_painter.drawLine(QPoint(min_interval * min_axis, time_high - 5), QPoint(min_interval * min_axis, time_high));
	}
	for (int i=1;i<24;i++)
	{
		time_axis_painter.drawLine(QPoint(interval, 0), QPoint(interval, time_high));
		for (int min_axis=0;min_axis<10;min_axis++)
		{
			time_axis_painter.drawLine(QPoint(interval + (min_interval * min_axis), time_high - 5), QPoint(interval + (min_interval * min_axis), time_high));
		}
		time_axis_painter.drawText(interval, time_high + 15, QString::number(i) + ":00");
		interval = interval + average;
	}
	time_axis_painter.drawText(interval, time_high + 15, "24:00");
	interval = 0;

	//画进度
	//刻度精度到分
// 	int scale = time_wide / 24 / 60;
// 	int height_change = 10;
// 	int row,column;
// 	for (row = 0; row < model()->rowCount(); ++row) {
// 		int begin_time_int = 0;
// 		for (column=1;column<4;++column)
// 		{
// 			QModelIndex index = model()->index(row, column,rootIndex());
// 			QString begin_time = model()->data(index).toString();
// 			QStringList begin_time_list = begin_time.split(":");
// 			int begin_hour = begin_time_list[0].toInt()*60;
// 			int begin_minute = begin_time_list[1].toInt();
// 			begin_time_int = begin_hour + begin_minute;
// 		}
// 		time_axis_painter.drawRect(begin_time_int, 30+height_change* (row+1), time_wide, 30);
// 	}

}

void GanttView::resizeEvent(QResizeEvent* event)
{
	updateGeometries();
}

void GanttView::scrollContentsBy(int dx, int dy)
{
	//界面根据滚动条动起来
	viewport()->scroll(dx, dy);
}

void GanttView::updateGeometries()
{
	//设置滚动条能显示到的最大范围
	horizontalScrollBar()->setPageStep(viewport()->width());
	horizontalScrollBar()->setRange(0, qMax(0, total_size - viewport()->width()));
	verticalScrollBar()->setPageStep(viewport()->height());
	verticalScrollBar()->setRange(0, qMax(0, total_size - viewport()->height()));
}

main.cpp

#include "KDGantt.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    KDGantt w;
    w.show();
    return a.exec();
}

  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇树谦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值