通过“待办事项列表项目”快速学习Pyqt5的一些特性

Pyqt5相关文章:
快速掌握Pyqt5的三种主窗口
快速掌握Pyqt5的2种弹簧
快速掌握Pyqt5的5种布局
快速弄懂Pyqt5的5种项目视图(Item View)
快速弄懂Pyqt5的4种项目部件(Item Widget)
快速掌握Pyqt5的6种按钮
快速掌握Pyqt5的10种容器(Containers)
快速掌握Pyqt5的20种输入控件(Input Widgets)
快速掌握Pyqt5的9种显示控件
详细学习Pyqt5中的5种布局方式
详细学习Pyqt5中的6种按钮
详细学习Pyqt5中的2种弹簧
详细学习Pyqt5的5种项目视图(Item View)
详细学习Pyqt5的4种项目部件(Item Widget)
详细学习Pyqt5的20种输入控件(Input Widgets)
详细学习Pyqt5的9种显示控件
详细学习Pyqt5的10种容器(Containers)
详细学习PyQt5与数据库交互
详细学习PyQt5中的多线程
快速学习PyQt5的动画和图形效果
快速学习PyQt5的高级自定义控件
快速学会绘制Pyqt5中的所有图(上)
快速学会绘制Pyqt5中的所有图(下)
待续。。。

项目软件最终效果图:

在这里插入图片描述

第一部分:项目概述

本项目的目标是创建一个简单而直观的待办事项列表应用程序。这个应用程序可以帮助用户有效地管理他们的日常任务,提供以下关键功能:

  1. 添加任务:允许用户输入并添加新任务到待办事项列表中。
  2. 删除任务:提供选项以从列表中删除不再需要的任务。
  3. 编辑任务:让用户能够修改现有任务的描述。
  4. 搜索和过滤:使用户能够通过关键词搜索任务,便于快速找到特定任务。
  5. 进度跟踪:通过进度条展示任务完成的总体进度,帮助用户了解他们完成任务的情况。

应用程序的用户界面(UI)设计注重简洁性和易用性,以确保用户能够轻松地进行日常任务管理。界面包括:

  1. 任务输入框:用于输入新任务的文本区域。
  2. 控制按钮:包括添加、删除和编辑任务的操作按钮。
  3. 任务显示区:展示任务列表,每个任务项包含一个复选框和任务描述。
  4. 搜索框:允许用户输入关键词以过滤任务列表。
  5. 进度指示器:动态显示完成的任务占总任务的百分比。

第二部分:环境搭建

准备PyQt5图形库

  • 打开命令提示符或终端,并运行以下命令:
    pip install PyQt5
    
  • 这个命令会从Python包索引(PyPI)下载并安装PyQt5及其依赖项。

第三部分:基础知识讲解

1. QApplication 对象

每个PyQt5应用程序的核心是QApplication对象。这个对象负责管理GUI应用程序的控制流和主要设置。在任何PyQt5程序中,QApplication对象是必须的。

app = QApplication([])

这段代码创建了一个QApplication实例,它是我们待办事项列表应用程序的起点。

2. QMainWindowQWidget

QMainWindow 是主窗口类,为应用程序提供了一个带有菜单栏、工具栏、状态栏和中心部件的框架。在我们的项目中,TodoList类继承自QMainWindow

class TodoList(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("待办事项列表")self.setGeometry(300, 300, 600, 500)self.setWindowIcon(QIcon('icon.png'))

QWidget 是所有用户界面对象的基类。在这里,我们创建了一个QWidget作为中心部件,并在其上布置其他控件。

central_widget = QWidget(self)
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
3. 布局管理

布局管理器,如QHBoxLayoutQVBoxLayout,是用来在窗口中组织控件的工具。在我们的项目中,我们使用了QVBoxLayout来垂直排列控件,并使用了QHBoxLayout来水平排列按钮。

layout = QVBoxLayout(central_widget)
buttons_layout = QHBoxLayout()
4. 控件和事件处理

在PyQt5中,控件是用户与应用程序交互的元素。我们的项目使用了多种控件,例如QLineEdit来输入任务,QPushButton来添加、删除和编辑任务。

self.task_input = QLineEdit(self)
add_button = QPushButton("添加任务", self)
delete_button = QPushButton("删除任务", self)

这些按钮通过点击事件触发相应的函数,如add_taskdelete_task

5. 自定义控件 - MovingTextProgressBar

在PyQt5中,我们还可以自定义控件。在此项目中,我们定义了MovingTextProgressBar,这是QProgressBar的一个子类,用来显示任务的完成进度。

class MovingTextProgressBar(QProgressBar):def __init__(self, parent=None):super().__init__(parent)def paintEvent(self, event):# Custom painting code here

这个自定义进度条在进度变化时显示百分比,并根据进度动态调整文本位置。

6. 数据存储和加载

最后,我们的项目还涉及到数据的保存和加载。使用Python的json模块,我们可以将任务列表保存到一个文件,并在应用程序启动时加载这些任务。

def save_tasks(self):tasks = []for i in range(self.task_list.count()):# 代码来保存任务with open('tasks.json', 'w') as file:json.dump(tasks, file)def load_tasks(self):try:with open('tasks.json', 'r') as file:# 代码来加载任务except Exception as e:print(f"Error loading tasks: {e}")

第四部分:逐步构建项目

1. 构建静态窗口方法(初始化__init__)详解

类定义和初始化
class TodoList(QMainWindow):def __init__(self):super().__init__()
  • TodoList 类继承自 PyQt5 的 QMainWindow 类,提供了一个主窗口框架。
  • __init__ 方法是类的构造函数,用于初始化这个窗口。
  • super().__init__() 调用基类的构造函数,是创建窗口的基本步骤。
设置窗口属性
self.setWindowTitle("待办事项列表")
self.setGeometry(300, 300, 600, 500)
self.setWindowIcon(QIcon('icon.png'))
  • setWindowTitle 设置窗口的标题。
  • setGeometry 设置窗口的位置和大小。这里窗口被放置在屏幕的 (300, 300) 位置,大小为 600x500 像素。
  • setWindowIcon 设置窗口的图标。图标文件应该是名为 ‘icon.png’ 的图像文件。
创建中心小部件和布局
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
  • 创建了一个QWidget作为窗口的中心小部件。
  • setCentralWidget 将这个小部件设置为主窗口的中心区域。
  • QVBoxLayout 创建了一个垂直布局,用于在中心小部件中垂直排列其他控件。
添加任务输入框
self.task_input = QLineEdit(self)
self.task_input.setMinimumHeight(30)
self.task_input.returnPressed.connect(self.add_task)
layout.addWidget(self.task_input)
  • QLineEdit 创建了一个文本输入框,用于输入任务。
  • setMinimumHeight 设置了输入框的最小高度。
  • returnPressed.connect 将输入框中的回车键事件连接到 add_task 方法;QLineEdit 控件有一个名为 returnPressed 的信号,当用户在该控件中按下回车键时,会触发去调用括号内的方法。
  • addWidget 将输入框添加到布局中。
添加控制按钮
buttons_layout = QHBoxLayout()
add_button = QPushButton("添加任务", self)
add_button.clicked.connect(self.add_task)
buttons_layout.addWidget(add_button)delete_button = QPushButton("删除任务", self)
delete_button.clicked.connect(self.delete_task)
buttons_layout.addWidget(delete_button)edit_button = QPushButton("编辑任务", self)
edit_button.clicked.connect(self.edit_task)
buttons_layout.addWidget(edit_button)layout.addLayout(buttons_layout)
  • QHBoxLayout 创建了一个水平布局。
  • QPushButton 创建了添加、删除和编辑任务的按钮。
  • clicked.connect 将按钮点击事件连接到相应的方法。
  • addWidget 将按钮添加到水平布局中。
  • addLayout 将水平布局添加到主垂直布局中。
添加任务列表、搜索框和进度条
self.task_list = QListWidget(self)
layout.addWidget(self.task_list)self.search_input = QLineEdit(self)
self.search_input.setPlaceholderText("搜索任务...")
self.search_input.textChanged.connect(self.search_tasks)
layout.addWidget(self.search_input)self.process_label = QLabel(self)
self.process_label.setText("任务进度:")
layout.addWidget(self.process_label)self.progress_bar = MovingTextProgressBar(self)
self.progress_bar.setMaximum(100)
layout.addWidget(self.progress_bar)
  • QListWidget 创建了一个任务列表。
  • QLineEdit 用作搜索框。
  • QLabel 显示了进度条的标签。
  • MovingTextProgressBar 是一个自定义的进度条类,用来展示任务完成进度。
加载任务和应用样式表
self.load_tasks()
self.update_progress()
self.apply_stylesheet()
  • load_tasks 加载保存的任务。
  • update_progress 更新进度条的状态。
  • apply_stylesheet 应用自定义样式来美化界面。

2. 自定义控件(自定义进度条MovingTextProgressBar)详解

这段代码定义了一个自定义的进度条控件 MovingTextProgressBar,它继承自PyQt5的 QProgressBar。这个自定义控件重写了进度条的绘制方法,使得进度条中可以显示带有百分比的文本。让我们逐步分析这段代码:

类定义和初始化
class MovingTextProgressBar(QProgressBar):def __init__(self, parent=None):super().__init__(parent)
  • MovingTextProgressBar 类继承自 QProgressBar,使用 QProgressBar 的所有功能并添加新的特性。
  • __init__ 方法是构造函数,用于初始化这个控件。parent 参数允许这个控件被嵌入到其他QWidget中。

绘制进度条

def paintEvent(self, event):painter = QPainter(self)# ... 绘制代码 ...
  • paintEvent 方法是Qt中用于绘制控件的事件处理器。
  • QPainter 对象用于所有绘图操作。
绘制背景
rect = self.rect()
painter.setBrush(self.palette().color(QPalette.Window))
painter.drawRect(rect)
  • self.rect() 获取控件的矩形区域。
  • setBrush 设置画笔的填充颜色,这里使用窗口的默认背景色。
  • drawRect 绘制进度条的背景矩形。
计算并绘制进度
progress_rect = QRect(rect)
progress_rect.setWidth(int(rect.width() * self.value() / self.maximum()))
painter.setBrush(self.palette().color(QPalette.Highlight))
painter.drawRect(progress_rect)
  • 计算进度条的宽度,基于进度条的当前值和最大值。
  • 设置画笔为高亮颜色(通常用于进度条的填充颜色)。
  • 绘制表示进度的矩形。
绘制文本
painter.setPen(self.palette().color(QPalette.Text))
text = f"{self.value():.2f}%"
text_rect = QRect(rect)
text_width = painter.fontMetrics().width(text)
# ... 文本位置计算和绘制 ...
  • 设置画笔颜色用于绘制文本。
  • 创建要显示的文本,显示当前进度的百分比。
  • fontMetrics().width(text) 用于计算文本的宽度,以便于定位。
计算文本位置并绘制
if self.value() > 0:text_position = max(0, progress_rect.width() - text_width - 5)
else:text_position = int((rect.width() - text_width) / 2)
text_rect.setLeft(text_position)
painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, text)
  • 根据进度条的填充情况计算文本的位置。
  • 如果有进度(值大于0),则确保文本位于进度条填充的右侧。
  • 如果没有进度,则将文本居中。
  • drawText 实际绘制文本。

总结

MovingTextProgressBar 类通过重写 paintEvent 方法自定义了进度条的绘制方式。这种自定义控件使得进度条不仅能够显示进度的可视化表示,还能在进度条内部显示具体的进度百分比,增强了用户界面的信息展示能力。这个自定义控件可以被重复使用在任何需要显示带文本的进度条的场景中。

3. 添加任务(add_task) 方法详解

获取任务文本

首先,我们从QLineEditself.task_input)获取用户输入的文本。这是用户希望添加到任务列表中的任务描述。

task_text = self.task_input.text()
if task_text:...

这段代码检查是否有文本输入。如果task_text不为空,那么接下来的代码就会执行,将这个新任务添加到任务列表中。

创建列表项

接下来,我们创建一个QListWidgetItem,这将是任务列表中的一个新项。

item = QListWidgetItem()
item.setSizeHint(QSize(0, 40))

这里,setSizeHint(QSize(0, 40))是为了确保列表项有足够的空间来展示任务,其中40是列表项的高度。

设计任务小部件

现在,我们创建一个小部件来展示任务的文本和一个复选框。这个小部件将被放置在任务列表项中。

task_widget = QWidget()
task_layout = QHBoxLayout()
task_layout.setContentsMargins(5, 0, 5, 0)

我们使用QHBoxLayout(水平布局)来放置复选框和任务标签。setContentsMargins方法用于设置布局边距。

添加复选框和标签

我们接着添加一个QCheckBox和一个QLabel到布局中。复选框用于标记任务是否完成,而标签显示任务的文本。

chkBox = QCheckBox()
chkBox.stateChanged.connect(self.update_progress)task_label = QLabel(task_text)
task_label.setMargin(5)task_layout.addWidget(chkBox)
task_layout.addWidget(task_label)

stateChanged信号连接到update_progress方法,这样当复选框的状态改变时,进度条会更新。

设置任务小部件的布局并添加到列表

最后,我们将这个布局应用到task_widget,然后将这个小部件设置为item的小部件。

task_layout.addStretch(1)
task_widget.setLayout(task_layout)self.task_list.addItem(item)
self.task_list.setItemWidget(item, task_widget)

addStretch(1)确保复选框和标签靠左排列,余下的空间被拉伸填充。

清除输入字段并更新进度

任务添加到列表后,输入框被清空,准备接受下一个任务的输入。同时,我们调用update_progress方法来更新进度条。

self.task_input.clear()
self.update_progress()
总结

add_task方法的核心是创建一个新的列表项,将用户输入的任务文本放入一个包含复选框和标签的小部件中,并将这个小部件添加到任务列表中。这个方法体现了PyQt5在处理用户界面和事件方面的灵活性和强大功能。通过这种方式,我们的待办事项列表应用程序能够动态地响应用户的输入,提供一个直观且互动的用户体验。

4. 删除任务(delete_task) 方法详解

循环遍历所选任务

delete_task方法首先遍历所有被用户选中的任务项。在PyQt5中,可以通过selectedItems()方法获取到QListWidget中所有被用户选中的项。

for item in self.task_list.selectedItems():...

这段代码遍历任务列表中的每个被选中的项(item)。

删除选中的任务

接下来,使用takeItem方法从列表中移除这些选中的项。takeItem需要一个索引参数,我们通过row(item)方法获取这个索引。

self.task_list.takeItem(self.task_list.row(item))

这里,row(item)返回被选中项的索引,然后takeItem根据这个索引删除相应的项。

更新进度条

删除任务后,进度条需要更新以反映当前任务的完成状态。

self.update_progress()

调用update_progress方法来重新计算并更新进度条。

编辑任务(edit_task) 方法详解

检查是否有任务被选中

在编辑任务前,首先检查是否有任务被选中。如果至少有一个任务被选中,我们将取第一个选中的任务进行编辑。

selected_items = self.task_list.selectedItems()
if selected_items:item = selected_items[0]...

这段代码确定是否有任务被选中,并将第一个选中的任务项赋值给item变量。

弹出对话框以编辑任务

使用QInputDialog.getText方法弹出一个对话框,允许用户编辑选中任务的文本。这个方法返回用户输入的新文本(new_text)和一个布尔值(ok),表示用户是否点击了对话框的确认按钮。

new_text, ok = QInputDialog.getText(self, "编辑任务", "任务描述:", QLineEdit.Normal, item.text())

这里的item.text()是当前任务的文本,用作对话框中的初始值。

更新任务文本

如果用户点击了确认并输入了新文本,则更新任务的文本。

if ok and new_text:item.setText(new_text)

setText方法用于更新列表项的文本为用户输入的新文本。

总结

delete_task方法通过遍历并移除选中的任务项来实现删除功能,而edit_task方法则通过弹出对话框并更新任务文本来实现编辑功能。这两个方法展示了如何在PyQt5应用程序中处理用户交互,如选择、删除和编辑列表项。通过这些方法,我们的待办事项列表应用变得更加灵活和用户友好,使用户能够轻松地管理他们的任务。

5. load_tasks 方法详解

尝试读取任务数据

load_tasks方法首先尝试打开一个名为tasks.json的文件,该文件包含以前保存的任务数据。

try:with open('tasks.json', 'r') as file:tasks = json.load(file)...
except Exception as e:print(f"Error loading tasks: {e}")

这里使用json.load(file)将文件中的JSON数据转换成Python对象。如果文件不存在或者文件格式不正确,会抛出异常,并打印错误信息。

遍历任务并添加到列表

接下来,遍历从文件中加载的每个任务,并将它们添加到任务列表中。

for task in tasks:item = QListWidgetItem()self.task_list.addItem(item)task_widget = QWidget()task_layout = QHBoxLayout()task_layout.setContentsMargins(5, 5, 5, 5)chkBox = QCheckBox()chkBox.setChecked(task['completed'])chkBox.stateChanged.connect(self.update_progress)task_label = QLabel(task['text'])task_layout.addWidget(chkBox)task_layout.addWidget(task_label)task_layout.addStretch(1)task_widget.setLayout(task_layout)item.setSizeHint(task_widget.sizeHint())self.task_list.setItemWidget(item, task_widget)

在这个循环中,每个任务被创建为一个QListWidgetItem,其中包含一个复选框(表示任务是否完成)和一个标签(显示任务文本)。这样做可以确保应用程序在启动时加载用户之前的任务。

6. save_tasks 方法详解

准备保存的任务数据

save_tasks方法中,首先创建一个空列表tasks,用于存放将要保存到文件的任务数据。

tasks = []
遍历任务列表并收集数据

接着,遍历任务列表中的每一项,收集任务的文本和完成状态。

for i in range(self.task_list.count()):item = self.task_list.item(i)widget = self.task_list.itemWidget(item)if widget:label = widget.findChild(QLabel)checkbox = widget.findChild(QCheckBox)tasks.append({'text': label.text(), 'completed': checkbox.isChecked()})

这里使用findChild方法来找到每个任务项中的QLabelQCheckBox,并获取它们的文本和勾选状态。

将任务数据保存到文件

最后,使用json.dump将任务数据以JSON格式保存到tasks.json文件中。

with open('tasks.json', 'w') as file:json.dump(tasks, file)

这样,当用户关闭应用程序时,他们的任务数据被保存,并且可以在下次打开应用时重新加载。

总结

load_taskssave_tasks方法是待办事项列表应用程序的关键部分,它们确保了任务数据的持久化。通过这些方法,用户的任务列表在应用程序关闭和重新打开之间保持一致,从而提供了更好的用户体验和数据的持久性。

总结

本文详细介绍了如何使用Python和PyQt5创建一个功能完备的待办事项列表应用程序。从项目概述到环境搭建,再到基础概念的讲解和实际构建过程,文章全面覆盖了应用程序开发的各个方面。通过复现这个项目,可以学习到以下知识:PyQt5的基本使用、事件处理和信号槽机制、自定义控件的创建、数据保存。

附录(全部代码)

import json
from PyQt5.QtWidgets import QLabel,QHBoxLayout,QApplication, QMainWindow, QListWidget, QListWidgetItem, QLineEdit, QPushButton, QVBoxLayout, QWidget, QCheckBox, QProgressBar, QInputDialog, QComboBox
from PyQt5.QtCore import QSize,QRect, Qt
from PyQt5.QtGui import QIcon,QPainter, QColor, QPaletteclass MovingTextProgressBar(QProgressBar):def __init__(self, parent=None):super().__init__(parent)def paintEvent(self, event):painter = QPainter(self)# Draw the progress bar's backgroundrect = self.rect()painter.setBrush(self.palette().color(QPalette.Window))  # Use 'Window' role for backgroundpainter.drawRect(rect)# Calculate the width of the progress barprogress_rect = QRect(rect)progress_rect.setWidth(int(rect.width() * self.value() / self.maximum()))painter.setBrush(self.palette().color(QPalette.Highlight))  # Use 'Highlight' role for progresspainter.drawRect(progress_rect)# Set the text colorpainter.setPen(self.palette().color(QPalette.Text))  # Use 'Text' role for text color# Calculate the text positiontext = f"{self.value():.2f}%"text_rect = QRect(rect)text_width = painter.fontMetrics().width(text)# Draw the textif self.value() > 0:# If there is progress, ensure the text is on the right side of the filled areatext_position = max(0, progress_rect.width() - text_width - 5)  # Use max to avoid negative positionelse:# If there is no progress, center the texttext_position = int((rect.width() - text_width) / 2)  # Cast to int to ensure correct argument typetext_rect.setLeft(text_position)painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, text)class TodoList(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("待办事项列表")self.setGeometry(300, 300, 600, 500)self.setWindowIcon(QIcon('icon.png'))  # 设置窗口图标,确保 'icon.png' 在您的文件夹中  central_widget = QWidget(self)self.setCentralWidget(central_widget)layout = QVBoxLayout(central_widget)layout.setSpacing(10)layout.setAlignment(Qt.AlignTop)self.task_input = QLineEdit(self)self.task_input.setMinimumHeight(30)self.task_input.returnPressed.connect(self.add_task)  # 连接信号layout.addWidget(self.task_input)# Create a horizontal layout for the buttonsbuttons_layout = QHBoxLayout()# Add Task Buttonadd_button = QPushButton("添加任务", self)add_button.clicked.connect(self.add_task)buttons_layout.addWidget(add_button)# Delete Task Buttondelete_button = QPushButton("删除任务", self)delete_button.clicked.connect(self.delete_task)buttons_layout.addWidget(delete_button)# Edit Task Buttonedit_button = QPushButton("编辑任务", self)edit_button.clicked.connect(self.edit_task)buttons_layout.addWidget(edit_button)# Add the horizontal layout to the main vertical layoutlayout.addLayout(buttons_layout)self.task_list = QListWidget(self)layout.addWidget(self.task_list)self.search_input = QLineEdit(self)self.search_input.setPlaceholderText("搜索任务...")self.search_input.textChanged.connect(self.search_tasks)layout.addWidget(self.search_input)self.process_label = QLabel(self)self.process_label.setText("任务进度:")layout.addWidget(self.process_label)self.progress_bar = MovingTextProgressBar(self)self.progress_bar.setMaximum(100)layout.addWidget(self.progress_bar)self.load_tasks()self.update_progress()  # Update the progress barself.apply_stylesheet()def apply_stylesheet(self):self.setStyleSheet("""  QListWidget, QLineEdit, QProgressBar, QComboBox {                font-size: 14px;                border: 1px solid #c0c0c0;                border-radius: 5px;                padding: 5px;            }            QPushButton {                background-color: #5cacee;                border-radius: 5px;                color: white;                padding: 6px;                margin: 5px 0;            }            QPushButton:hover {                background-color: #1e90ff;            }        """)def add_task(self):task_text = self.task_input.text()if task_text:# 创建一个新的QListWidgetItem并设置其大小提示item = QListWidgetItem()item.setSizeHint(QSize(0, 40))  # 根据需要调整高度# 创建包含复选框和标签的小部件task_widget = QWidget()task_layout = QHBoxLayout()task_layout.setContentsMargins(5, 0, 5, 0)  # 适当设置边距# 创建复选框并连接状态变化信号chkBox = QCheckBox()chkBox.stateChanged.connect(self.update_progress)# 创建标签显示文本task_label = QLabel(task_text)task_label.setMargin(5)  # 如果文本靠得太近,可以添加一些边距# 将复选框和标签添加到布局task_layout.addWidget(chkBox)task_layout.addWidget(task_label)task_layout.addStretch(1)  # 添加拉伸因子使得控件靠左排列# 设置任务小部件的布局task_widget.setLayout(task_layout)# 将任务小部件设置为列表项的小部件self.task_list.addItem(item)self.task_list.setItemWidget(item, task_widget)# 清除输入字段并更新进度self.task_input.clear()self.update_progress()def delete_task(self):for item in self.task_list.selectedItems():self.task_list.takeItem(self.task_list.row(item))self.update_progress()def update_progress(self):total_tasks = self.task_list.count()completed_tasks = sum(1 for i in range(total_tasks) ifself.task_list.itemWidget(self.task_list.item(i)).findChild(QCheckBox).isChecked())# Protect against division by zero if there are no tasksprogress = int((completed_tasks / total_tasks) * 100) if total_tasks > 0 else 0self.progress_bar.setValue(progress)self.progress_bar.setFormat(f"{progress:.2f}%" if progress >= 0 else "0.00%")self.save_tasks()def edit_task(self):selected_items = self.task_list.selectedItems()if selected_items:item = selected_items[0]new_text, ok = QInputDialog.getText(self, "编辑任务", "任务描述:", QLineEdit.Normal, item.text())if ok and new_text:item.setText(new_text)def closeEvent(self, event):tasks = []for i in range(self.task_list.count()):item = self.task_list.item(i)widget = self.task_list.itemWidget(item)if widget:checkbox = widget.findChild(QCheckBox)tasks.append({'text': item.text(), 'completed': checkbox.isChecked()})with open('tasks.json', 'w') as file:json.dump(tasks, file)event.accept()def load_tasks(self):try:with open('tasks.json', 'r') as file:tasks = json.load(file)for task in tasks:item = QListWidgetItem()self.task_list.addItem(item)task_widget = QWidget()task_layout = QHBoxLayout()task_layout.setContentsMargins(5, 5, 5, 5)chkBox = QCheckBox()# First, disconnect any existing connections to avoid duplicate signalstry:chkBox.stateChanged.disconnect()except TypeError:# If there is no connection, a TypeError is thrown, which is finepass# Then, set the checked statechkBox.setChecked(task['completed'])# Now, connect the signal to the slotchkBox.stateChanged.connect(self.update_progress)task_label = QLabel(task['text'])task_layout.addWidget(chkBox)task_layout.addWidget(task_label)task_layout.addStretch(1)task_widget.setLayout(task_layout)item.setSizeHint(task_widget.sizeHint())self.task_list.setItemWidget(item, task_widget)# After all tasks have been loaded, update the progress barself.update_progress()except Exception as e:print(f"Error loading tasks: {e}")# 新增 sort_tasks 方法def search_tasks(self, keyword):for i in range(self.task_list.count()):item = self.task_list.item(i)widget = self.task_list.itemWidget(item)if widget:label = widget.findChild(QLabel)# 确保我们找到了标签并且比较其文本if label and keyword.lower() in label.text().lower():item.setHidden(False)else:item.setHidden(True)# 程序结束时调用def closeEvent(self, event):self.save_tasks()super().closeEvent(event)# 新增保存和加载任务的方法def save_tasks(self):tasks = []for i in range(self.task_list.count()):item = self.task_list.item(i)widget = self.task_list.itemWidget(item)if widget:label = widget.findChild(QLabel)checkbox = widget.findChild(QCheckBox)task_text = label.text() if label else ""task_completed = checkbox.isChecked() if checkbox else Falsetasks.append({'text': task_text, 'completed': task_completed})with open('tasks.json', 'w') as file:json.dump(tasks, file)app = QApplication([])
window = TodoList()
window.show()
app.exec_()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/228486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache Flume(3):数据持久化

1 使用组件 File Channel 2 属性设置 属性名默认值说明type-filecheckpointDir~/.flume/file-channel/checkpoint检查点文件存放路径dataDirs~/.flume/file-channel/data日志存储路径,多个路径使用逗号分隔. 使用不同的磁盘上的多个路径能提高file channel的性能 …

SpringIOC之@Primary

博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

nodejs微信小程序+python+PHP技术下的音乐推送系统-计算机毕业设计推荐

音乐推送系统采取面对对象的开发模式进行软件的开发和硬体的架设,能很好的满足实际使用的需求,完善了对应的软体架设以及程序编码的工作,采取MySQL作为后台数据的主要存储单元,  本文设计了一款音乐推送系统,系统为人…

vue中2种取值的方式

1.url是这种方式的:http://localhost:3000/user/1 取得参数的方式为:this.$route.params.id 2.url为get方式用?拼接参数的:http://localhost:3000/user?phone131121123&companyId2ahttp://localhost:3000/ 取得参数值的方式…

freeRTOS使用

创建第一个FreeRTOS程序 1、官网源码下载 (1)进入FreeRTOS官网FreeRTOS professional services for application and RTOS development and consulting. FreeRTOS is an Open Source Code RTOS (2)点击下载FreeRTOS 2、处理目录 &…

基于多智能体系统一致性算法的电力系统分布式经济调度策略MATLAB程序

微❤关注“电气仔推送”获得资料(专享优惠) 参考文献: 主要内容: 应用多智能体系统中的一致性算法,以发电机组的增量成本和柔性负荷的增量效益作为一致性变量,设计一种用于电力系统经济调度的算法&#x…

openwrt中taiscale自动安装脚本详解

openwrt中taiscale自动安装脚本详解 一、代码仓库地址 https://github.com/adyanth/openwrt-tailscale-enabler 二、代码仓库中脚本文件详解 主要包含三个脚本分别是etc/init.d/tailscale、usr/bin/tailscale、usr/bin/tailscaled ,接下来逐个分析一下脚本中的具…

3.1【窗口】窗口简介与窗口组

一,窗口简介 Windows用于显示内容,并将不同生成的内容组合在一起。每个不同的呈现器都可以在同一个进程中,也可以在另一个或多个进程中。 Screen中的窗口概念与你在传统窗口系统中可能习惯的略有不同。在Screen中,当内容来自不同来源时,应用程序被分成几个窗口,当应用程…

Linux查看进程PID以及杀掉进程的方法

目录 参考链接 前言 查看进程PID PS命令 ps -le命令 查找父进程 杀死进程 参考链接 【Linux 】 ps命令详解,查看进程pid_linux查看pid 对应的程序-CSDN博客 Linux查看进程PID的方法(linux查进程的pid)附带自动kill 掉_linux查看pid 对…

DDA 算法

CAD 算法是计算机辅助设计的算法,几何算法是解决几何问题的算法 CAD 算法是指在计算机辅助设计软件中使用的算法,用于实现各种设计和绘图功能,CAD 广泛应用于建筑、机械、电子等领域,可以大大提高设计效率和精度 绘图算法是 CAD…

机器学习算法---聚类

类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统计学检验箱…

大数据机器学习与深度学习——过拟合、欠拟合及机器学习算法分类

大数据机器学习与深度学习——过拟合、欠拟合及机器学习算法分类 过拟合,欠拟合 针对模型的拟合,这里引入两个概念:过拟合,欠拟合。 过拟合:在机器学习任务中,我们通常将数据集分为两部分:训…

03进程基础-学习笔记

Process 进程 进程为操作系统的基本调度单位,占用系统资源(cpu,内存)完成特定任务,所有说进程是操作系统的标准执行单元 进程与程序的差别 程序是静态资源,存储与电脑磁盘中(disk磁盘资源)程序执行后会创建进程,负责完成功能&a…

Python-flask 入门代码

python与pycharm安装 过程略,网上很多,记得为pycharm配置默认解释器 虚拟环境 pipenv # 全局安装虚拟环境 # 可加-U参数,明确全局安装,不加好像也可以? pip3 install pipenv #检查安装情况 pipenv --version # ---控制台输出…

机械硬盘和固态硬盘速度测试

利用ubuntu自带的disk磁盘管理软件对手头的三个硬盘做压力测试,disk软件挺好用的,再也不用命令了。 第一个是致态的1T固态硬盘,速度1.8GB/S。 ST机械硬盘,速度只有300多MB/S. 三星固态硬盘,速度1.4GB/s。

汽车发动机市场调研:预计2029年将达到642亿美元

过去汽车发动机行业快速发展,很多产品都出现供不应求,甚至加价销售的状况,而随着产能过剩、需求下滑,未来汽车发动机行业的价格竞争将愈发激烈,形成新的供需矛盾。根据动力源类型,汽车可分类为传统燃油汽车…

MATLAB2022安装下载教程

安装包需从夸克网盘自取: 链接:https://pan.quark.cn/s/373ffc9213a1 提取码:N7PW 1.将安装包解压 2.以管理员的身份运行文件夹中的setup文件 3.点击高级选项--->我有文件安装密钥 4. 选择【是】,进入下一步 5.输入密钥 0532…

【PHP入门】1.1-PHP初步语法

-PHP语法初步- PHP是一种运行在服务器端的脚本语言&#xff0c;可以嵌入到HTML中。 1.1.1PHP代码标记 在PHP历史发展中&#xff0c;可以使用多种标记来区分PHP脚本 ASP标记&#xff1a; <% php代码 %>短标记&#xff1a; <? Php代码 ?>&#xff0c;以上两种…

智能优化算法应用:基于供需算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于供需算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于供需算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.供需算法4.实验参数设定5.算法结果6.参考文献7.MA…

大模型自定义算子优化方案学习笔记:CUDA算子定义、算子编译、正反向梯度实现

01算子优化的意义 随着大模型应用的普及以及算力紧缺&#xff0c;下一步对于计算性能的追求一定是技术的核心方向。因为目前大模型的计算逻辑是由一个个独立的算子或者说OP正反向求导实现的&#xff0c;底层往往调用的是GPU提供的CUDA的驱动程序。如果不能对于整个计算过程学习…