qt表格控件操作(Qt制作桌面小控件-待办列表)
qt表格控件操作(Qt制作桌面小控件-待办列表)//初始化列表 void J_ToDoList::initTableView() { m_pTableView = new QTableView(this); m_pTableView->setObjectName("todo_TableView"); m_pTableView->setCursor(Qt::ArrowCursor); m_pModel = new QStandardItemModel; m_pModel->setColumnCount(1); m_pTableView->setModel(m_pModel); m_pTableView->horizontalHeader()->setVisible(false); m_pTableView->horiz
前言千呼万唤始出来,QT组件库终于迎来了它的第一个小组件——待办列表。之所以编写这个组件,是因为感觉很多工作或学习中的朋友需要,可能你们已经在使用一些类似功能的软件,来帮助自己记录事项和规划时间。但是我根据自己平常的工作体会和自己的使用需求,完成了今天要分享的这个待办列表,主要设计理念就是简单、方便、快捷,主要功能包括添加、修改、删除、清空事项、标记为已完成和自动保存。其实本来还计划实现全局热键和提醒功能的,但是全局热键还是打算后面单独用一篇文章来讲解,因为它在不同平台的实现不同。而提醒功能需要设置时间,时间控件后面我也要自定义,所以这里就不使用QDateTimeEdit来实现了,这两个功能暂且先放一下,现在先来看一下实现效果:
添加事项:
删除事项:
缩放、移动和清空事项:
标记完成状态:
自动保存:
每次操作完成后都会进行自动保存,所以不必担心会有信息丢失。
实现方法首先整个窗口都是基于自己封装的无边框窗口类,主界面用的也是这个类,窗口和标题栏的背景色都可以通过封装好的接口进行修改,这个在前面的文章中都介绍过。下面的待办列表其实就是一个QTableView,然后通过qss设置了一些自定义样式,本来还打算使用自定义模型的,后来觉得既然默认的QStandardItemModel就能实现基本的功能了,就没再费那功夫。列表初始化及qss样式设置实现如下:
//初始化列表
void J_ToDoList::initTableView()
{
m_pTableView = new QTableView(this);
m_pTableView->setObjectName("todo_TableView");
m_pTableView->setCursor(Qt::ArrowCursor);
m_pModel = new QStandardItemModel;
m_pModel->setColumnCount(1);
m_pTableView->setModel(m_pModel);
m_pTableView->horizontalHeader()->setVisible(false);
m_pTableView->horizontalHeader()->setStretchLastSection(true);
m_pTableView->verticalHeader()->setVisible(false);
m_pTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_pTableView SIGNAL(customContextMenuRequested(const QPoint &)) this SLOT(showMenu(const QPoint &)));
connect(m_pModel SIGNAL(itemChanged(QStandardItem*)) this SLOT(saveToFile()));
}
QTableView#todo_TableView
{
background-color: rgba(255 255 255 80%);
min-height: 150px;
border: 0px;
}
QTableView:item:hover
{
color: black;
background-color: #FFA500;
}
QTableView:item:selected
{
color: black;
background-color: #FFA500;
}
不同类型的事项通过不同的颜色来区分,设置QTableView中某个节点颜色的方法如下:
m_pModel->item(nRow 0)->setForeground(QBrush(QColor("#FF0000")));
当事项被标记为完成时,该节点中的文字会被加上删除线,QT中给文字加删除线的方法有多种,这里我们只介绍一种,即利用Qfont类进行实现:
QFont font("Microsoft YaHei" 10 QFont::Bold false);//设置字体、字号、加粗、斜体
font.setStrikeOut(true);//设置删除线
m_pModel->item(nRow 0)->setData(font Qt::FontRole);//设置字体
当模型发生变化时,会发射itemChanged()信号,自动保存功能就是在接收到该信号时对修改进行保存,但是这样做有个缺陷,就是删除节点或清空列表的时候,不会发射该信号,因此删除和清空操作后要再调用一次保存函数。
源码整个待办列表的完整代码如下,大家如果感兴趣的话,可以参考一下:
#ifndef J_TODOLIST_H
#define J_TODOLIST_H
#include "MyFramelessWidget.h"
#include <QTableView>
#include <QStandardItemModel>
#include <QVector>
typedef struct
{
int nType; //事项类型
bool bIsMark; //是否标记完成
}TODO_TYPE;
class J_ToDoList : public MyFramelessWidget
{
Q_OBJECT
public:
explicit J_ToDoList(MyFramelessWidget *parent = nullptr);
void initTableView(); //初始化列表
public slots:
void showMenu(const QPoint &pos); //显示右键菜单
void add(); //添加待办事项
void addProject(); //项目工作类别
void addMaintenance(); //维护工作类别
void addDaily(); //日常工作类别
void addPersonal(); //个人私事类别
void setEditOn(); //设置item处于编辑状态
void remove(); //删除待办事项
void clear(); //清空待办事项
void setMark(); //标记已完成
void removeMark(); //标记未完成
void readFromFile(); //从配置文件读取保存事项
void saveToFile(); //保存配置到本地文件;
private:
QTableView * m_pTableView;
QStandardItemModel * m_pModel;
bool m_bSaveFlag; //是否保存文件标记
QVector<TODO_TYPE> m_qVector;
};
#endif // J_TODOLIST_H
#include "J_ToDoList.h"
#include <QVBoxLayout>
#include <QHeaderView>
#include <QMenu>
#include <QMap>
#include <QSettings>
#include <QApplication>
#include <QTextCodec>
#include <QDebug>
J_ToDoList::J_ToDoList(MyFramelessWidget *parent) : MyFramelessWidget(parent)
{
this->resize(350 600);
this->setAttribute(Qt::WA_DeleteOnClose);
this->titleLogo_Label->setPixmap(QPixmap(":/Images/ToDoList.png"));
initTableView();
QVBoxLayout *pVLayout = new QVBoxLayout;
pVLayout->setMargin(0);
pVLayout->setSpacing(0);
pVLayout->addWidget(m_pTableView);
this->central_Widget->setLayout(pVLayout);
setWidgetModal(false);
setWidgetOpacity(0.7);
setTitleBarStyle("QWidget#titleBar_MyFramelessWidget {"
"background: rgb(255 255 255); "
"min-height: 25px; "
"max-height: 25px; }"); //54 54 54
m_qVector.clear();
readFromFile();
}
//初始化列表
void J_ToDoList::initTableView()
{
m_pTableView = new QTableView(this);
m_pTableView->setObjectName("todo_TableView");
//m_pTableView->setMouseTracking(true);
m_pTableView->setCursor(Qt::ArrowCursor);
m_pModel = new QStandardItemModel;
m_pModel->setColumnCount(1);
m_pTableView->horizontalHeader()->setVisible(false);
m_pTableView->horizontalHeader()->setStretchLastSection(true);
m_pTableView->verticalHeader()->setVisible(false);
m_pTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
//m_pTableView->setFocusPolicy(Qt::NoFocus);
m_pTableView->setModel(m_pModel);
// m_pTableView->setStyleSheet("QTableView#todo_TableView {"
// "background-color: rgba(54 54 54 80%);"
// "border: 0px; }");
m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_pTableView SIGNAL(customContextMenuRequested(const QPoint &)) this SLOT(showMenu(const QPoint &)));
connect(m_pModel SIGNAL(itemChanged(QStandardItem*)) this SLOT(saveToFile()));
}
//显示右键菜单
void J_ToDoList::showMenu(const QPoint &pos)
{
QMenu menu;
QMenu childMenu("添加事项");
childMenu.addAction("项目" this SLOT(addProject()));
childMenu.addAction("维护" this SLOT(addMaintenance()));
childMenu.addAction("日常" this SLOT(addDaily()));
childMenu.addAction("个人" this SLOT(addPersonal()));
menu.addMenu(&childMenu);
menu.addAction("删除事项" this SLOT(remove()));
menu.addAction("清空事项" this SLOT(clear()));
menu.addSeparator();
menu.addAction("标记已完成" this SLOT(setMark()));
menu.addAction("标记未完成" this SLOT(removeMark()));
menu.exec(QCursor::pos());
}
//添加待办事项
void J_ToDoList::add()
{
QStandardItem *item = new QStandardItem("");
QPixmap pixmap(":/Images/ToDo.png");
pixmap = pixmap.scaled(24 24 Qt::KeepAspectRatio);
item->setData(pixmap Qt::DecorationRole);//设置图标
item->setData(item->text() Qt::ToolTipRole);//设置提示
item->setData(QFont("Microsoft YaHei" 10 QFont::Bold false) Qt::FontRole);//设置字体
m_pModel->setItem(m_pModel->rowCount() 0 item);
}
//添加项目待办事项
void J_ToDoList::addProject()
{
TODO_TYPE todo;
todo.nType = 1;
todo.bIsMark = false;
m_qVector.append(todo);
add();
m_pModel->item(m_pModel->rowCount()-1 0)->setForeground(QBrush(QColor("#FF0000")));
setEditOn();
}
//添加维护待办事项
void J_ToDoList::addMaintenance()
{
TODO_TYPE todo;
todo.nType = 2;
todo.bIsMark = false;
m_qVector.append(todo);
add();
m_pModel->item(m_pModel->rowCount()-1 0)->setForeground(QBrush(QColor("#336600")));
setEditOn();
}
//添加日常待办事项
void J_ToDoList::addDaily()
{
TODO_TYPE todo;
todo.nType = 3;
todo.bIsMark = false;
m_qVector.append(todo);
add();
m_pModel->item(m_pModel->rowCount()-1 0)->setForeground(QBrush(QColor("#FF6600")));
setEditOn();
}
//添加个人待办事项
void J_ToDoList::addPersonal()
{
TODO_TYPE todo;
todo.nType = 4;
todo.bIsMark = false;
m_qVector.append(todo);
add();
m_pModel->item(m_pModel->rowCount()-1 0)->setForeground(QBrush(QColor("#0066FF")));
setEditOn();
}
//设置item处于编辑状态
void J_ToDoList::setEditOn()
{
if (!m_bSaveFlag)
return;
QStandardItem *item = m_pModel->item(m_pModel->rowCount()-1 0);
QModelIndex index = item->index();
m_pTableView->edit(index);
}
//删除待办事项,支持多行删除
void J_ToDoList::remove()
{
QItemSelectionModel *selections = m_pTableView->selectionModel();
QModelIndexList selected = selections->selectedIndexes();
QMap<int int> rowMap;
foreach (QModelIndex index selected)
rowMap.insert(index.row() 0);
int rowToDel;
QMapIterator<int int> rowMapIterator(rowMap);
rowMapIterator.toBack();
while (rowMapIterator.hasprevious())
{
rowMapIterator.previous();
rowToDel = rowMapIterator.key();
m_pModel->removeRow(rowToDel);
m_qVector.erase(m_qVector.begin() rowToDel);
}
saveToFile(); //删除和清空不会发送itemChanged信号,需要手动调用
}
//清空待办事项
void J_ToDoList::clear()
{
m_pModel->clear();
m_qVector.clear();
saveToFile(); //删除和清空不会发送itemChanged信号,需要手动调用
}
//标记已完成
void J_ToDoList::setMark()
{
m_bSaveFlag = false; //标记完成的时候也会改变model,此时不应该进行文件的保存操作
QItemSelectionModel *selections = m_pTableView->selectionModel();
QModelIndexList selected = selections->selectedIndexes();
QMap<int int> rowMap;
foreach (QModelIndex index selected)
rowMap.insert(index.row() 0);
int rowToDel;
QMapIterator<int int> rowMapIterator(rowMap);
rowMapIterator.toBack();
while (rowMapIterator.hasPrevious())
{
rowMapIterator.previous();
rowToDel = rowMapIterator.key();
QStandardItem *item = m_pModel->item(rowToDel 0);
item->setData(item->text() Qt::DisplayRole);
QFont font("Microsoft YaHei" 10 QFont::Bold false);
font.setStrikeOut(true);
item->setData(font Qt::FontRole);//设置字体
m_qVector[rowToDel].bIsMark = true;
}
m_bSaveFlag = true;
saveToFile(); //删除和清空不会发送itemChanged信号,需要手动调用
}
//标记未完成
void J_ToDoList::removeMark()
{
m_bSaveFlag = false; //标记未完成的时候也会改变model,此时不应该进行文件的保存操作
QItemSelectionModel *selections = m_pTableView->selectionModel();
QModelIndexList selected = selections->selectedIndexes();
QMap<int int> rowMap;
foreach (QModelIndex index selected)
rowMap.insert(index.row() 0);
int rowToDel;
QMapIterator<int int> rowMapIterator(rowMap);
rowMapIterator.toBack();
while (rowMapIterator.hasPrevious())
{
rowMapIterator.previous();
rowToDel = rowMapIterator.key();
QStandardItem *item = m_pModel->item(rowToDel 0);
item->setData(item->text() Qt::DisplayRole);
QFont font("Microsoft YaHei" 10 QFont::Bold false);
item->setData(font Qt::FontRole);//设置字体
m_qVector[rowToDel].bIsMark = false;
qDebug() << rowToDel << ": " << m_qVector[rowToDel].bIsMark;
}
m_bSaveFlag = true;
saveToFile(); //删除和清空不会发送itemChanged信号,需要手动调用
}
//从配置文件读取保存事项
void J_ToDoList::readFromFile()
{
m_bSaveFlag = false; //读取文件的时候也会改变model,此时不应该进行文件的保存操作
QString strPath = qApp->applicationDirPath();
strPath = "/../sys/ToDoList.ini";
QSettings settings(strPath QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("system"));
int nCount = settings.value("ToDoList/Count" 0).toInt();
QString strNote strType strMark strContent;
int nType;
bool bMark;
for (int i=0; i<nCount; i )
{
strNote = "ToDoList/Note" QString::number(i);
strType = "ToDoList/Type" QString::number(i);
strMark = "ToDoList/Mark" QString::number(i);
strContent = settings.value(strNote "").toString();
nType = settings.value(strType -1).toInt();
bMark = settings.value(strMark 0).toBool();
switch (nType)
{
case 1:
addProject();
break;
case 2:
addMaintenance();
break;
case 3:
addDaily();
break;
case 4:
addPersonal();
break;
default:
addPersonal();
break;
}
m_qVector[m_qVector.count()-1].bIsMark = bMark;
QStandardItem *item = m_pModel->item(m_pModel->rowCount()-1 0);
item->setData(strContent Qt::DisplayRole);
QFont font("Microsoft YaHei" 10 QFont::Bold false);
if (bMark) font.setStrikeOut(true);
item->setData(font Qt::FontRole);//设置字体
}
m_bSaveFlag = true;
}
//保存配置到本地文件
void J_ToDoList::saveToFile()
{
if (!m_bSaveFlag)
return;
QString strPath = qApp->applicationDirPath();
strPath = "/../sys/ToDoList.ini";
QSettings settings(strPath QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("system"));
settings.clear();
settings.setValue("ToDoList/Count" m_pModel->rowCount());
QString strNote strType strMark;
for (int i=0; i<m_pModel->rowCount(); i )
{
strNote = "ToDoList/Note" QString::number(i);
strType = "ToDoList/Type" QString::number(i);
strMark = "ToDoList/Mark" QString::number(i);
settings.setValue(strNote m_pModel->item(i 0)->text());
settings.setValue(strType m_qVector[i].nType);
qDebug() << i << ": " << m_qVector[i].bIsMark;
settings.setValue(strMark m_qVector[i].bIsMark);
}
}