关键代码:
#ifndef STUDENT_H
#define STUDENT_H
#include <QString>
class Student
{
public:
Student();
void setId(int id);
int id();
void setName(const QString &name);
QString name();
private:
int m_id;
QString m_name;
};
#endif // STUDENT_H
#include "student.h"
Student::Student()
{
m_id=0;
m_name="";
}
void Student::setId(int id)
{
this->m_id=id;
}
int Student::id()
{
return this->m_id;
}
void Student::setName(const QString &name)
{
this->m_name=name;
}
QString Student::name()
{
return this->m_name;
}
#ifndef STUDENTTABLEVIEWMODEL_H
#define STUDENTTABLEVIEWMODEL_H
#include <QAbstractTableModel>
#include <QList>
#include <QMap>
class Student;
class StudentTableViewModel : public QAbstractTableModel
{
Q_OBJECT
public:
StudentTableViewModel(QObject *parent=0);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
void add();
void remove(int id);
Student *get(int id);
private:
QList<Student*> m_studentList;
QMap<int, Student*> m_studentMap;
int m_testNumber;
void updateModel();
};
#endif // STUDENTTABLEVIEWMODEL_H
#include "studenttableviewmodel.h"
#include "student.h"
StudentTableViewModel::StudentTableViewModel(QObject *parent)
: QAbstractTableModel(parent)
{
m_testNumber=10000;
}
int StudentTableViewModel::rowCount(const QModelIndex &parent) const
{
return m_studentList.size();
}
int StudentTableViewModel::columnCount(const QModelIndex &parent) const
{
return 3;
}
QVariant StudentTableViewModel::data(const QModelIndex &index, int role) const
{
Student* student=m_studentList.at(index.row());
switch (role) {
case Qt::DisplayRole:
if(index.column()==0)
{
return student->id();
}
else if(index.column()==1)
{
return student->name();
}
else if(index.column()==2)
{
return QString("<a href=\"about://add\">Add</a> <a href=\"about://remove?%1\">Remove</a> <a href=\"about://alert?%1\">Alert</a>").arg(student->id());
}
break;
case Qt::UserRole:
return student->id();
break;
default:
break;
}
return QVariant();
}
QVariant StudentTableViewModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role==Qt::DisplayRole && orientation==Qt::Horizontal)
{
if(section==0)
{
return "ID";
}
else if(section==1)
{
return "Name";
}
else if(section==2)
{
return "Operation";
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
Qt::ItemFlags StudentTableViewModel::flags(const QModelIndex &index) const
{
return QAbstractTableModel::flags(index);
}
void StudentTableViewModel::add()
{
Student *student=new Student;
student->setId(m_testNumber);
student->setName(QString("Name%1").arg(m_testNumber));
m_studentMap.insert(m_testNumber, student);
updateModel();
m_testNumber++;
}
void StudentTableViewModel::remove(int id)
{
Student *student=m_studentMap.value(id);
if(student)
{
delete student;
}
m_studentMap.remove(id);
updateModel();
}
Student *StudentTableViewModel::get(int id)
{
return m_studentMap.value(id);
}
void StudentTableViewModel::updateModel()
{
m_studentList.clear();
QList<int> keys=m_studentMap.keys();
qSort(keys.begin(), keys.end());
for(int i=0; i<keys.size(); i++)
{
m_studentList.push_back(m_studentMap.value(keys.at(i)));
}
emit layoutChanged();
}
#ifndef LINKABLEITEMDELEGATE_H
#define LINKABLEITEMDELEGATE_H
#include <QStyledItemDelegate>
class LinkableItemDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
explicit LinkableItemDelegate(QObject *parent = 0);
QString anchorAt(QString html, const QPoint &point) const;
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif // LINKABLEITEMDELEGATE_H
#include "linkableitemdelegate.h"
#include <QPainter>
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QIcon>
#include <QSize>
LinkableItemDelegate::LinkableItemDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
}
QString LinkableItemDelegate::anchorAt(QString html, const QPoint &point) const
{
QTextDocument doc;
doc.setHtml(html);
auto textLayout = doc.documentLayout();
Q_ASSERT(textLayout != 0);
return textLayout->anchorAt(point);
}
void LinkableItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
/********* 一种简单的实现 ***********
auto options = option;
initStyleOption(&options, index);
painter->save();
QTextDocument doc;
doc.setHtml(options.text);
options.text = "";
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &option, painter);
painter->translate(options.rect.left(), options.rect.top());
QRect clip(0, 0, options.rect.width(), options.rect.height());
doc.drawContents(painter, clip);
painter->restore();
***********************************/
QStyleOptionViewItemV4 options = option;
initStyleOption(&options, index);
painter->save();
QTextDocument doc;
doc.setHtml(options.text);
options.text = "";
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
QSize iconSize = options.icon.actualSize(options.rect.size());
// right shit the icon
painter->translate(options.rect.left() + iconSize.width(), options.rect.top());
QRect clip(0, 0, options.rect.width() + iconSize.width(), options.rect.height());
painter->setClipRect(clip);
QAbstractTextDocumentLayout::PaintContext ctx;
// Adjust color palette if the cell is selected
if (option.state & QStyle::State_Selected)
ctx.palette.setColor(QPalette::Text, option.palette.color(QPalette::Active, QPalette::HighlightedText));
ctx.clip = clip;
// Vertical Center alignment instead of the default top alignment
painter->translate(0, 0.5*(options.rect.height() - doc.size().height()));
doc.documentLayout()->draw(painter, ctx);
painter->restore();
}
QSize LinkableItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 options = option;
initStyleOption(&options, index);
QTextDocument doc;
doc.setHtml(options.text);
doc.setTextWidth(options.rect.width());
return QSize(doc.idealWidth(), doc.size().height());
}
#ifndef LINKABLEVIEW_H
#define LINKABLEVIEW_H
#include <QTableView>
class LinkableTableView : public QTableView
{
Q_OBJECT
public:
explicit LinkableTableView(QWidget *parent = 0);
signals:
void linkActivated(QString link);
void linkHovered(QString link);
void linkUnhovered();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
QString anchorAt(const QPoint &pos) const;
private:
QString _mousePressAnchor;
QString _lastHoveredAnchor;
};
#endif // LINKABLEVIEW_H
#include "linkabletableview.h"
#include <QApplication>
#include <QCursor>
#include <QMouseEvent>
#include "linkableitemdelegate.h"
LinkableTableView::LinkableTableView(QWidget *parent) :
QTableView(parent)
{
// needed for the hover functionality
setMouseTracking(true);
}
void LinkableTableView::mousePressEvent(QMouseEvent *event) {
QTableView::mousePressEvent(event);
auto anchor = anchorAt(event->pos());
_mousePressAnchor = anchor;
}
void LinkableTableView::mouseMoveEvent(QMouseEvent *event) {
auto anchor = anchorAt(event->pos());
if (_mousePressAnchor != anchor) {
_mousePressAnchor.clear();
}
if (_lastHoveredAnchor != anchor) {
_lastHoveredAnchor = anchor;
if (!_lastHoveredAnchor.isEmpty()) {
QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
emit linkHovered(_lastHoveredAnchor);
} else {
QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
emit linkUnhovered();
}
}
}
void LinkableTableView::mouseReleaseEvent(QMouseEvent *event) {
if (!_mousePressAnchor.isEmpty()) {
auto anchor = anchorAt(event->pos());
if (anchor == _mousePressAnchor) {
emit linkActivated(_mousePressAnchor);
}
_mousePressAnchor.clear();
}
QTableView::mouseReleaseEvent(event);
}
QString LinkableTableView::anchorAt(const QPoint &pos) const {
auto index = indexAt(pos);
if (index.isValid()) {
auto delegate = itemDelegate(index);
auto linkableDelegate = qobject_cast<LinkableItemDelegate *>(delegate);
if (linkableDelegate != 0) {
auto itemRect = visualRect(index);
auto relativeClickPosition = pos - itemRect.topLeft();
auto html = model()->data(index, Qt::DisplayRole).toString();
return linkableDelegate->anchorAt(html, relativeClickPosition);
}
}
return QString();
}
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
class StudentTableViewModel;
class LinkableItemDelegate;
class LinkableTableView;
class MainWidget : public QWidget
{
Q_OBJECT
public:
explicit MainWidget(QWidget *parent = 0);
~MainWidget();
private slots:
void doAdd();
void doLinkActivated(QString link);
private:
StudentTableViewModel *m_studentTableViewModel;
LinkableItemDelegate *m_linkableItemDelegate;
LinkableTableView *m_linkableTableView;
};
#endif // MAINWIDGET_H
#include "mainwidget.h"
#include <QPushButton>
#include <QVBoxLayout>
#include "linkableitemdelegate.h"
#include "linkabletableview.h"
#include "studenttableviewmodel.h"
#include <QMessageBox>
#include <QHeaderView>
#include "student.h"
MainWidget::MainWidget(QWidget *parent) :
QWidget(parent)
{
m_linkableTableView=new LinkableTableView;
m_linkableTableView->setSelectionMode(QTableView::NoSelection);
m_linkableTableView->horizontalHeader()->setStretchLastSection(true);
QVBoxLayout *vLayout=new QVBoxLayout;
this->setLayout(vLayout);
vLayout->addWidget(m_linkableTableView);
QPushButton *buttonAdd=new QPushButton;
buttonAdd->setText("Add");
connect(buttonAdd, SIGNAL(clicked(bool)), this, SLOT(doAdd()));
vLayout->addWidget(buttonAdd);
m_studentTableViewModel=new StudentTableViewModel(this);
m_linkableTableView->setModel(m_studentTableViewModel);
m_linkableItemDelegate=new LinkableItemDelegate(this);
m_linkableTableView->setItemDelegate(m_linkableItemDelegate);
connect(m_linkableTableView, SIGNAL(linkActivated(QString)), this, SLOT(doLinkActivated(QString)));
}
MainWidget::~MainWidget()
{
}
void MainWidget::doAdd()
{
m_studentTableViewModel->add();
}
void MainWidget::doLinkActivated(QString link)
{
if(link.contains("add"))
{
m_studentTableViewModel->add();
}
else if(link.contains("remove"))
{
int id=link.mid(link.indexOf("?")+1).toInt();
m_studentTableViewModel->remove(id);
}
else if(link.contains("alert"))
{
int id=link.mid(link.indexOf("?")+1).toInt();
Student *student=m_studentTableViewModel->get(id);
if(student)
{
QMessageBox::about(this, "Alert", QString("id:%1, name:%2").arg(student->id()).arg(student->name()));
}
}
}
运行效果:
参考资料: