pyqt qtableview 添加下拉框控件_Qt制作桌面小控件-待办列表,从此事情再多也不会忘了
前言
千呼万唤始出来,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 #include #include typedef struct{ int nType; //事项类型 bool bIsMark; //是否标记完成}TODO_TYPE;class J_ToDoList : public MyFramelessWidget{ Q_OBJECTpublic: 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 m_qVector;};#endif // J_TODOLIST_H
#include "J_ToDoList.h"#include #include #include #include #include #include #include #include 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 rowMap; foreach (QModelIndex index, selected) rowMap.insert(index.row(), 0); int rowToDel; QMapIterator 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 rowMap; foreach (QModelIndex index, selected) rowMap.insert(index.row(), 0); int rowToDel; QMapIterator 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 rowMap; foreach (QModelIndex index, selected) rowMap.insert(index.row(), 0); int rowToDel; QMapIterator 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; iitem(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; irowCount(); 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); }}