PyQt项目实战-工作小助手(4 利用QSqlTableModel和tableView 实现Todolist)

PyQt项目实战-工作小助手(4 利用QSqlTableModel和tableView 实现Todolist)

本部分通过QSqlTableModel和tableView控件实现todolist工作待办的查询、新增、修改、删除和导出功能

文章目录

  • PyQt项目实战-工作小助手(4 利用QSqlTableModel和tableView 实现Todolist)
  • 1、界面设计
  • 2、实现todolist查询
  • 3、利用delegate实现tableview数据的个性化显示
  • 3、实现新增功能
  • 4、实现删除功能
  • 5、导出功能
  • 6、界面各Button点击事件和槽函数的链接

1、界面设计

界面支持筛选查询、新增、删除和导出功能。先上图。
PyQt项目实战-工作小助手(4 利用QSqlTableModel和tableView 实现Todolist)_第1张图片

  1. 第一行为筛选查询字段,实现查询功能:

日期范围为comboBox,预设为全部、本日、本周、上周、本月、上月、本年、本年之前。

程度为comboBox,根据重要和紧急程度分为:

  • 重要紧急,该部分任务优先处理
  • 不重要紧急,次之
  • 重要不紧急,再次之
  • 不重要不紧急 ,最后处理

事项为lineEdit,支持通过输入文本模糊匹配查询。

  1. 第二行为tableview控件,展示查询结果和支持直接修改数据库。
  2. 第三行为toolButton,分别实现新增记录、删除记录和导出任务功能。

2、实现todolist查询

  1. 新建QSqlTableModel实例todomodel。QSqlTableModel类提供了一个可读写单张SQL表的可编辑数据模型。支持修改,插入,删除,查询,和排序。EditStrategy使用OnFiledChange策略实现编辑功能。
self.todomodel = QSqlTableModel()
self.todomodel.setTable("todolist")       self.todomodel.setEditStrategy(QSqlTableModel.OnFieldChange)

setEditStrategy各取值含义如下:
QSqlTableModel.OnFieldChange,一改动马上提交数据库
QSqlTableModel.OnRowChange,当前行号变化再提交数据库
QSqlTableModel.OnManualSubmit,默认值,手动提交submitAll()修改才生效。

  1. 默认情况下,QSqlTableModel查询返回所有记录。可通过setFilter()实现sql中where语句的功能,即设置查询过滤条件。查询条件要转化为Sqlite3数据库所能识别的过滤语句,特别是要处理各类日期字典。

本日:date(pdate) = date(‘now’)
本周:date(pdate) >= date(‘now’,‘weekday 1’,’-7 day’))
上周:(date(pdate) >= date(‘now’,‘weekday 1’,’-14 day’) and date(pdate) < date(‘now’,‘weekday 1’,’-7 day’))
本月:(date(pdate) >= date(‘now’,‘start of month’))
上月:(date(pdate) >= date(‘now’,‘start of month’,’-1 month’) and date(pdate) < date(‘now’,‘start of month’))
本年:(date(pdate) >= date(‘now’,‘start of year’))
本年以前:(date(pdate) < date(‘now’,‘start of year’))

        # 2、业务条件转换为查询过滤语句。
        ##2.1文本模糊匹配
        sql1 = "(content like '%{}%')".format(scontent)
        filterlist = sql1
        ##2.2待办事项建立日期范围。
        if sdaterange in [1, 2, 3, 4, 5, 6, 7]:
            if sdaterange == 1:  # 本日
                sql2 = "(date(pdate) = date('now'))"
            elif sdaterange == 2:  # 本周
                sql2 = "(date(pdate) >= date('now','weekday 1','-7 day'))"
            elif sdaterange == 3:  # 上周
                sql2 = "(date(pdate) >= date('now','weekday 1','-14 day') and date(pdate) < date('now','weekday 1','-7 day'))"
            elif sdaterange == 4:  # 本月
                sql2 = "(date(pdate) >= date('now','start of month'))"
            elif sdaterange == 5:  # 上月
                sql2 = "(date(pdate) >= date('now','start of month','-1 month') and date(pdate) < date('now','start of month'))"
            elif sdaterange == 6:  # 本年
                sql2 = "(date(pdate) >= date('now','start of year'))"
            elif sdaterange == 7:  # 去年及以前
                sql2 = "(date(pdate) < date('now','start of year'))"
            filterlist = filterlist + " and " + sql2
        else:
            sql2 = ''
        ##2.3待办事项状态。
        if sfinstatus in [1, 2]:
            sql3 = "(finstatus={})".format(sfinstatus)
            filterlist = filterlist + " and " + sql3
        else:
            sql3 = ''
        ##2.4待办事项分类条件。
        if scatalog in [1, 2, 3, 4]:
            sql4 = "(catalog={})".format(scatalog)
            filterlist = filterlist + " and " + sql4
        else:
            sql4 = ''
  1. 获取数据库数据,设置表头显示内容
		self.todomodel.setFilter(filterlist)
        self.todomodel.select()
        
        self.todomodel.setHeaderData(0, Qt.Horizontal, '编号')
        self.todomodel.setHeaderData(1, Qt.Horizontal, '重要紧急')
        self.todomodel.setHeaderData(2, Qt.Horizontal, '事项')
        self.todomodel.setHeaderData(3, Qt.Horizontal, '状态')
        self.todomodel.setHeaderData(4, Qt.Horizontal, '建立日期')
        self.todomodel.setHeaderData(5, Qt.Horizontal, '完成日期')
        self.todomodel.setHeaderData(6, Qt.Horizontal, '完成情况')
        self.todomodel.setHeaderData(7, Qt.Horizontal, '下一步计划')
  1. 设置tableview各列属性,包括columnwidth,autoscroll,行交叉颜色变化等
		self.todo_un.setModel(self.todomodel)
        # 设置todo tableview格式
        self.todo_un.setColumnWidth(0, 50)
        self.todo_un.setColumnWidth(1, 100)
        self.todo_un.setColumnWidth(2, 300)
        self.todo_un.setColumnWidth(3, 80)
        self.todo_un.setColumnWidth(4, 100)
        self.todo_un.setColumnWidth(5, 100)
        self.todo_un.setColumnWidth(6, 300)
        self.todo_un.setColumnWidth(7, 300)
        self.todo_un.setAutoScroll(True)
        self.todo_un.setAlternatingRowColors(True)  # 行交叉变化颜色
        self.todo_un.resizeRowsToContents()
        self.todo_un.horizontalHeader().setStyleSheet("QHeaderView::section{background:grey;}")
        self.todo_un.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.todo_un.setColumnHidden(0, True)
        self.todo_un.setItemDelegate(listDelegate(self))

3、利用delegate实现tableview数据的个性化显示

tableview默认使用QItemDelegate,本项目中由于涉及到comboBox,需重写delegate代理listDelegate,实现数据库中字典项index显示为对应的字典项名称。

  1. 重写paint函数,使用drawDisplay()显示字典项目名称。
  2. 重写createEditor函数,实现tableview中使用comboBox编辑数字
  3. 重写setModelData函数,实现字典选择后,data取值字典index
  4. 重写setEditorData函数,实现字典数据选择。
class listDelegate(QItemDelegate):  # 设置todo代理
    def __init__(self, parent):
        super(listDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        '''缺少将重要紧急任务标注颜色功能'''
        myoption = option
        myoption.displayAlignment = Qt.AlignCenter
        if index.column() == 1:#comboBox显示为字典文本
            value = index.model().data(index, role=Qt.DisplayRole)
            text = todocatalog[value]
            self.drawDisplay(painter, myoption, myoption.rect, text)
        elif index.column() == 3:#comboBox显示为字典文本
            value = index.model().data(index, role=Qt.DisplayRole)
            text = finstatus[value]
            self.drawDisplay(painter, myoption, myoption.rect, text)
        else:
            QItemDelegate.paint(self, painter, myoption, index)

    def createEditor(self, parent, option, index):
        if index.column() == 0:  # 不允许编辑
            return None
        elif index.column() == 1:
            combox = QComboBox(parent)
            combox.addItems(todocatalog)
            combox.setEditable(True)
            return combox
        elif index.column() == 3:
            combox = QComboBox(parent)
            combox.addItems(finstatus)
            # combox.setCurrentText(QModelIndex.value)
            combox.setEditable(True)
            return combox
        elif index.column() in [4, 5]:
            dateedit = QDateEdit(parent)
            dateedit.setDate(QDate.currentDate())
            dateedit.setCalendarPopup(True)
            return dateedit
        elif index.column() in [2, 6, 7]:
            plaintextedit = QPlainTextEdit(parent)
            return plaintextedit
        else:
            return QItemDelegate.createEditor(self, parent, option,
                                              index)

    def setModelData(self, editor, model, index):
        if index.column() == 1:
            model.setData(index, QVariant(editor.currentIndex()))
        elif index.column() == 3:
            model.setData(index, QVariant(editor.currentIndex()))
        else:
            QItemDelegate.setModelData(self, editor, model, index)

    def setEditorData(self, editor, index):
        text = index.model().data(index, Qt.DisplayRole)
        # print(text)
        if index.column() == 1:
            editor.setCurrentIndex(text)
        elif index.column() == 3:
            editor.setCurrentIndex(text)
        else:
            QItemDelegate.setEditorData(self, editor, index)

3、实现新增功能

  1. model.insertRow()新增行
  2. 设置点击新增后部分字段的默认取值,setData()
  3. submitAll()提交
# 1.2计划新增
    def todo_add(self):
        self.todomodel.insertRow(0)  # 在第一行新增,避免翻页
        self.todomodel.setData(self.todomodel.index(0, 1), 1)  # 默认初始分类为重要紧急
        self.todomodel.setData(self.todomodel.index(0, 3), 1)  # 默认初始状态未完成
        self.todomodel.setData(self.todomodel.index(0, 4), QDate.currentDate())  # 默认建立日期为当天
        self.todomodel.submitAll()

4、实现删除功能

  1. 获取当前行。index=tableview.currentIndex(),结果为QItemIndex,row=index.row()
  2. 利用SqlTableModel.removeRow(row)实现删除某一行功能。
  3. 重新查询,让结果立即呈现。
 # 1.3计划删除
    def todo_del(self):
        row = self.todo_un.currentIndex().row()
        self.todomodel.removeRow(row)
        self.todo_query()

5、导出功能

利用xlwt库实现导出modeldata为xls。

  1. 获取导出文件夹和文件名QFileDialog().getSaveFileName()
  2. 判断filename是否为空
  3. 获取数据的行数和列数,
  4. 利用xlwt.XFStyle设置导出文件格式
  5. 利用循环实现表头的写入
  6. 利用行列嵌套循环,实现所有数据的写入,特别注意将字典项数字转为字典项名称输出。
  7. 写入成功后,利用QMessageBox弹出结果窗口。
# 1.4计划导出
    def todo_export(self):
        filename, filetype = QFileDialog().getSaveFileName(self, '请选择保存文件', './Data/', 'Text Files (*.xls)')
        if filename != '':
            row = self.todomodel.rowCount()
            col = self.todomodel.columnCount()
            f = xlwt.Workbook(encoding='utf-8')
            sheet1 = f.add_sheet('sheet1', cell_overwrite_ok=True)
            style = xlwt.XFStyle()
            al = xlwt.Alignment()
            al.horz = 0x02  # 设置水平居中
            al.vert = 0x01  # 设置垂直居中
            style.alignment = al
            for h in range(col):
                sheet1.write(0, h, self.todomodel.headerData(h, Qt.Horizontal, Qt.DisplayRole), style)
            for i in range(row):
                for j in range(col):
                    index = self.todomodel.index(i, j)
                    data = self.todomodel.data(index)
                    if j == 1:
                        data = todocatalog[data]
                    if j == 3:
                        data = finstatus[data]
                    sheet1.write(i + 1, j, data, style)
            f.save(filename)
            QMessageBox.information(self, "保存结果", "数据导出成功,共计{}条数据导出!".format(row), QMessageBox.Yes)
        else:
            QMessageBox.warning(self, "警告", "文件打开错误,数据导出失败", QMessageBox.Ok)

6、界面各Button点击事件和槽函数的链接

        self.pushButton_todo_query.clicked.connect(self.todo_query)  # 待办事项查询
        self.toolButton__task_add.clicked.connect(self.todo_add)  # x新增待办事项
        self.toolButton__task_export.clicked.connect(self.todo_export)  # 导出待办事项
        self.toolButton__task_del.clicked.connect(self.todo_del)  # 删除待办事项

你可能感兴趣的:(python学习)