当前位置: 首页 > news >正文

pyqt写一个待办程序

ToDoApp

框架选择

一个简单的GUI程序,可以使用pyqt完成。pyqt是qt的python实现版本。

界面搭建

设计一个美观在这里插入图片描述
简洁的界面

class ToDoApp(QWidget):def __init__(self):super().__init__()# 设置窗口属性self.setWindowTitle("Daily To Do List")self.setGeometry(100, 100, 400, 400)# 初始化主布局self.main_layout = QVBoxLayout()# 创建输入和添加按钮self.input_layout = QGridLayout()# 标题输入self.title_label = QLabel("标题:")self.title_input = QLineEdit()self.input_layout.addWidget(self.title_label, 0, 0)self.input_layout.addWidget(self.title_input, 0, 1)# 描述输入self.description_label = QLabel("描述:")self.description_input = QLineEdit()self.input_layout.addWidget(self.description_label, 1, 0)self.input_layout.addWidget(self.description_input, 1, 1)# 水平按钮布局self.add_layout = QHBoxLayout()self.add_layout.setSpacing(20)# 导入self.import_button = QPushButton('批量导入')self.import_button.clicked.connect(self.import_item)self.add_layout.addWidget(self.import_button)self.add_button = QPushButton("添加")self.add_button.clicked.connect(self.add_item)self.add_layout.addWidget(self.add_button)# 任务列表self.to_do_list = QListWidget()self.to_do_list.setStyleSheet("padding: 10px;")self.to_do_list.setVerticalScrollMode(QListWidget.ScrollPerPixel)# 创建操作按钮self.buttons_layout = QHBoxLayout()self.mark_done_button = QPushButton("标记完成")self.mark_done_button.clicked.connect(self.mark_item_done)self.delete_button = QPushButton("删除")self.delete_button.clicked.connect(self.delete_item)self.buttons_layout.addWidget(self.mark_done_button)self.buttons_layout.addWidget(self.delete_button)# 将布局添加到主窗口self.main_layout.addLayout(self.input_layout)self.main_layout.addLayout(self.add_layout)self.main_layout.addWidget(self.to_do_list)self.main_layout.addLayout(self.buttons_layout)# 设置窗口布局self.setLayout(self.main_layout)
QGridLayout的使用

QGridLayout是网格布局,在添加子窗口时可以设定位置(行、列)和占据的大小(占几行几列)
CSDN文章

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QLabel, QPushButtonclass GridExample(QWidget):def __init__(self):super().__init__()self.init_ui()def init_ui(self):self.setWindowTitle("PyQt QGridLayout Example")self.setGeometry(100, 100, 400, 300)# 创建 QGridLayoutlayout = QGridLayout(self)# 创建一个标题标签title_label = QLabel("Header Label", self)title_label.setStyleSheet("font-size: 18px; font-weight: bold; color: blue;")# 将标题设置为占据第一行的所有列layout.addWidget(title_label, 0, 0, 1, 3)  # 行, 列, 占据行数, 占据列数# 创建一个 3x3 的按钮网格for i in range(3):for j in range(3):button = QPushButton(f"Button {i*3 + j +1}", self)layout.addWidget(button, i + 1, j)  # 按钮从行1开始# 创建一个右侧按钮占据一列right_button = QPushButton("Right Button", self)# 设置右侧按钮占据第3列的所有行layout.addWidget(right_button, 1, 3, 3, 1)  # 行1到3, 列3# 创建一个底部按钮占据一行bottom_button = QPushButton("Bottom Button", self)# 设置底部按钮占据第4行的所有列layout.addWidget(bottom_button, 4, 0, 1, 4)  # 行4, 列0-3self.setLayout(layout)if __name__ == "__main__":app = QApplication(sys.argv)window = GridExample()window.show()sys.exit(app.exec_())
强制子窗口独立

在 PyQt 中,当给窗口(QWidget 或子类)设置 parent 后窗口不显示,通常是因为 子窗口被嵌入到了父窗口的布局中,而非作为独立窗口显示。以下是常见原因和解决方案:


1. 根本原因:parent 的作用
  • parent 的作用:在 PyQt 中,parent 表示窗口的父控件。若设置 parent

    • 子窗口会嵌入到父窗口中,成为父窗口的一部分(类似按钮、文本框等控件)。
    • 子窗口的生命周期与父窗口绑定(父窗口销毁时,子窗口自动销毁)。
    • 子窗口默认不会作为独立窗口弹出,而是跟随父窗口的布局显示。
  • 关键区别

    # 独立窗口(无 parent)
    child_window = QWidget()
    child_window.show()# 嵌入父窗口(设置 parent)
    child_window = QWidget(parent=main_window)  # 不会独立显示,而是嵌入到 main_window 中
    

2. 常见场景和解决方法

场景 1:希望子窗口作为独立窗口弹出

  • 错误写法

    parent_window = QWidget()
    child_window = QWidget(parent=parent_window)  # 设置 parent
    child_window.show()  # ❌ 不会显示独立窗口!
    
  • 原因child_window 已成为 parent_window 的子控件,必须通过父窗口的布局显示(例如将 child_window 添加到父窗口的 QVBoxLayout 中)。

  • 解决方法不要设置 parent,让子窗口独立:

    parent_window = QWidget()
    child_window = QWidget()  # 无 parent
    child_window.show()       # ✅ 作为独立窗口显示
    

场景 2:希望子窗口作为模态对话框弹出

  • 错误写法

    parent_window = QWidget()
    child_window = QWidget(parent=parent_window)
    child_window.setWindowModality(Qt.ApplicationModal)  # 设置为模态
    child_window.show()  # ❌ 仍然不显示!
    
  • 原因child_windowparent_window 的子控件,必须通过父窗口布局显示,或明确设置为独立窗口。

  • 解决方法:使用 Qt.Window 标志强制子窗口成为独立窗口:

    child_window = QWidget(parent=parent_window)
    child_window.setWindowFlags(Qt.Window)  # 关键:强制为独立窗口
    child_window.setWindowModality(Qt.ApplicationModal)
    child_window.show()  # ✅ 作为模态对话框弹出
    

场景 3:子窗口被正确添加到父窗口布局但仍不显示

  • 错误写法

    parent_window = QWidget()
    child_window = QWidget(parent=parent_window)
    parent_window.show()  # ❌ 只显示 parent_window,但 child_window 未添加到布局中
    
  • 原因child_window 需要被添加到父窗口的布局管理器(如 QVBoxLayout),或手动设置其位置。

  • 解决方法:将子窗口添加到父窗口布局:

    parent_window = QWidget()
    layout = QVBoxLayout(parent_window)  # 父窗口设置布局
    child_window = QWidget()
    layout.addWidget(child_window)       # 添加到布局
    parent_window.show()  # ✅ 父窗口和子控件均显示
    

3. 通用检查列表

如果子窗口不显示,按以下步骤排查:

  1. 是否设置 parent
    • 若设置 parent,子窗口需要添加到父窗口的布局中。
  2. 父窗口是否已显示
    • 父窗口调用 show() 后,子控件才会显示。
  3. 窗口标志是否正确
    • 使用 setWindowFlags(Qt.Window) 强制子窗口独立。
  4. 布局是否正确
    • 确保子窗口被添加到父窗口的布局管理器(如 addWidget(child))。
  5. 生命周期问题
    • 确保父窗口未被提前销毁(例如在局部作用域中被垃圾回收)。

4. 完整示例对比

示例 1:子窗口嵌入父窗口(正确写法)

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QApplicationapp = QApplication([])# 父窗口
parent = QWidget()
layout = QVBoxLayout(parent)# 子窗口(作为控件嵌入父窗口)
child = QPushButton("我是子控件", parent=parent)
layout.addWidget(child)parent.show()
app.exec_()

示例 2:子窗口作为独立窗口(正确写法)

from PyQt5.QtWidgets import QWidget, QApplicationapp = QApplication([])# 父窗口
parent = QWidget()
parent.show()# 子窗口(独立窗口,无 parent)
child = QWidget()
child.setWindowTitle("我是独立子窗口")
child.show()app.exec_()

5. 特殊场景:动态创建子窗口

若通过按钮点击动态创建子窗口,需确保子窗口的引用不被销毁:

from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, QApplicationapp = QApplication([])class MainWindow(QWidget):def __init__(self):super().__init__()self.button = QPushButton("打开子窗口", self)self.button.clicked.connect(self.open_child)self.setLayout(QVBoxLayout())self.layout().addWidget(self.button)def open_child(self):self.child = QWidget()  # 必须保存为成员变量,否则会被垃圾回收!self.child.setWindowTitle("子窗口")self.child.show()window = MainWindow()
window.show()
app.exec_()

通过理解 parent 的作用和布局机制,可以灵活控制窗口的显示方式。

模型设计

每一个待办事项有

  • 标题
  • 描述信息
  • 生成时间
  • 是否完成标识
  • 截止时间
class ToDoItem:def __init__(self, title, description,deadline_time=None,is_completed=False):self.title = titleself.description = descriptionself.deadline_time = deadline_timeself.is_completed = False

自定义信号

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QMessageBox
from PyQt5.QtCore import pyqtSignal
import sysclass MyWidget(QWidget):# 定义一个自定义信号custom_signal = pyqtSignal(str)def __init__(self):super().__init__()self.init_ui()def init_ui(self):self.setWindowTitle("PyQt Custom Signal Example")self.setGeometry(100, 100, 300, 200)# 创建一个按钮self.button = QPushButton("Click Me", self)self.button.clicked.connect(self.emit_custom_signal)# 设置布局layout = QVBoxLayout()layout.addWidget(self.button)self.setLayout(layout)# 连接自定义信号到槽self.custom_signal.connect(self.handle_custom_signal)def emit_custom_signal(self):"""发射自定义信号"""self.custom_signal.emit("Hello from custom signal!")def handle_custom_signal(self, message):"""处理自定义信号"""QMessageBox.information(self, "Custom Signal", message)if __name__ == "__main__":app = QApplication(sys.argv)widget = MyWidget()widget.show()sys.exit(app.exec_())

批量导入功能

使用json格式的字符串进行批量导入,大致格式如下

{"items": [{"title": "测试标题1","description": "测试1","deadline_time": "2024","is_completed": false},{"title": "测试标题2","description": "测试2","deadline_time": "2025","is_completed": true}]
}

大致就是新开一个窗口,创建一个QTextEdit输入对应的json数据,然后通过json.loads()方法解析对应数据,
逐个使用add_item()接口添加,这要求add_item()能够处理多种情况:按钮点击触发无需参数批量导入中需要传递参数

而在python中实现类似重载的效果可以给参数一个默认值None,再在函数内部分情况处理

class ImportWidget(QWidget):# 自定义信号import_finished = pyqtSignal(dict)def __init__(self,parent):super().__init__(parent)self.setFixedSize = (500,500)self.setWindowFlags(Qt.Window)  # 关键:强制为独立窗口self.input_field = QTextEdit()self.main_layout = QVBoxLayout()self.btn_layout = QHBoxLayout()self.confirm_button = QPushButton("导入")self.cancel_button = QPushButton("取消")self.btn_layout.addWidget(self.confirm_button)self.btn_layout.addWidget(self.cancel_button)self.confirm_button.clicked.connect(self.read_json_data)# 连接自定义信号到槽self.import_finished.connect(self.close)self.main_layout.addLayout(self.btn_layout)self.main_layout.addWidget(self.input_field)self.setLayout(self.main_layout)def read_json_data(self):text = self.input_field.toPlainText()  # 获取输入框的文本# print(f"原始文本内容: {text}")  # 调试:打印原始文本内容try:# 将输入的文本解析为 JSON 数据json_data = json.loads(text.strip())  # 使用 strip() 去除首尾空白字符# print(f"解析后的 JSON 数据: {json_data}")self.json_data = json_data   self.import_finished.emit(json_data)except json.JSONDecodeError as e:# 如果 JSON 格式不正确,打印错误信息print(f"JSON 解析失败: {e}")self.json_data =  None
class ToDoApp(QWidget):def batch_import(self,json_data):print(json_data['items'])items = json_data['items']for item in items:self.add_item(item['title'],item['description'])def add_item(self, checked,title=None, description=None):# 如果 title 和 description 是传入的参数if title is not None or description is not None:# 使用传入的参数title = title.strip() if title else ""description = description.strip() if description else ""else:# 获取输入框的文本title = self.title_input.text().strip()print(title, description)description = self.description_input.text().strip()# TODO 优化时间显示居右current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 创建 ToDoItem 实例todo_item = ToDoItem(title, description, current_time)# 创建新的列表项  创建自定义Widgetitem_widget = QWidget()layout = QHBoxLayout()# 标题部分title_label = QLabel(todo_item.title)title_label.setStyleSheet("QLabel{padding:0px}")title_label.setAlignment(Qt.AlignmentFlag.AlignLeft| Qt.AlignmentFlag.AlignVCenter)# 时间部分time_label = QLabel(todo_item.created_time)time_label.setStyleSheet("QLabel{padding:0px}") # 添加padding设置,Qlabel有默认padding,不设置话,会将文字截断time_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)# 添加控件到布局layout.addWidget(title_label)layout.addWidget(time_label)item_widget.setLayout(layout)# 创建ListWidgetItemitem = QListWidgetItem()item.setSizeHint(item_widget.sizeHint())  # 设置每一项的宽高item.setToolTip(todo_item.description) # 设置悬浮提示item.setData(Qt.UserRole, todo_item)  # 保存任务对象item.setFlags(item.flags() | Qt.ItemIsSelectable | Qt.ItemIsEnabled)  item.setCheckState(Qt.CheckState.Unchecked)self.to_do_list.addItem(item)self.to_do_list.setItemWidget(item, item_widget)# 清空输入框self.title_input.clear()self.description_input.clear()
bug解析
  • 使用按钮连接点击信号至槽函数,发现槽函数add_item接收到的title参数不是预期的输入值None(因为点击事件的槽函数一般不带参数),而是False。

  1. PyQt 的 clicked 信号默认会传递一个布尔值

    • QPushButtonclicked 信号默认会发送一个 checked 参数(表示按钮的选中状态)。
    • 如果你没有显式处理这个参数,它会传递到槽函数中,导致 title 参数被赋值为 False(因为默认未选中)。
  2. 槽函数定义与信号参数不匹配
    你定义的 add_item 方法有两个可选参数:

    def add_item(self, title=None, description=None):
    
    • 当通过 self.add_button.clicked.connect(self.add_item) 连接信号时,clicked 信号的 checked 参数(布尔值)会传递给 title 参数。
    • 因此,点击按钮时 title 实际接收到的是 False,而不是预期的 None

方法 1:显式接收并忽略 checked 参数

修改槽函数,增加一个参数接收 checked 值,但不在内部使用它:

def add_item(self, checked, title=None, description=None):  # 增加 checked 参数# 如果 title 和 description 是传入的参数if title is not None or description is not None:print("not null", title, description)title = title.strip() if title else ""description = description.strip() if description else ""else:# 获取输入框的文本title = self.title_input.text().strip()description = self.description_input.text().strip()# 其他逻辑...
方法 2:使用 lambda 阻止参数传递

在连接信号时,通过 lambda 屏蔽 clicked 信号的参数:

self.add_button.clicked.connect(lambda: self.add_item())  # 不传递任何参数

此时 titledescription 将保持 None,代码会从输入框中读取值。


关键点解释
  • 信号参数传递机制

    • clicked 信号默认发送 checked(布尔值),而 QPushButton 默认不可选中,因此总是发送 False
    • 如果槽函数参数数量不匹配,第一个参数会接收这个 False
  • 参数优先级问题

    • 如果调用 add_item 时传递了参数(如 add_item(title="测试")),title 会被正确赋值。
    • 若未传递参数,title 会被错误地赋值为 False(来自 checked 参数)。

导出

既然有批量导入功能,就有导出功能

剪切板 QClipboard

在 PyQt 中,可以使用 QApplication.clipboard() 来访问系统剪贴板,并通过 QClipboard 类的方法将数据复制到剪贴板

def export_to_clipboard(self):# 获取所有任务items = []for i in range(self.to_do_list.count()):item = self.to_do_list.item(i)if item:todo_item = item.data(Qt.UserRole)items.append({"title": todo_item.title,"description": todo_item.description,"deadline_time": todo_item.deadline_time,"is_completed": todo_item.is_completed})# 转换为 JSON 格式json_data = {"items": items}json_str = json.dumps(json_data, indent=4, ensure_ascii=False)  # 格式化 JSON 字符串# 复制到剪切板clipboard = QApplication.clipboard()clipboard.setText(json_str)# 弹出提示QMessageBox.information(self, "提示", "已复制到剪切板")
常用的 QClipboard 方法
  • setText(text): 将文本复制到剪贴板。
  • setPixmap(pixmap): 将图片复制到剪贴板。
  • setMimeData(mimeData): 将 MIME 数据(如 HTML)复制到剪贴板。
  • clear(): 清除剪贴板内容。

持久化存储

  • 数据库sqlite
  • 文件保存

直接写入文件,不使用数据库了,重写关闭事件,保存代办到文件,并在初始化的时候读取文件

    def init_from_file(self, file_path=None):# 默认初始化文件为当前目录下的 to_do.jsonif file_path is None:file_path = "./to_do.json"# 读取文件内容with open(file_path, "r", encoding="utf-8") as f:text = f.read()self.batch_import(json.loads(text))def closeEvent(self, event):# 关闭窗口时保存数据with open("./to_do.json", "w", encoding="utf-8") as f:self.export_to_clipboard(True)f.write(QApplication.clipboard().text())QApplication.clipboard().clear()event.accept()

排序功能

  • 截止时间ddl排序
def sort_by_ddl(self):if self.sort_value == "asc":self.sort_value = "desc"else:self.sort_value = "asc"# 按 DDL 排序items = []for i in range(self.to_do_list.count()):item = self.to_do_list.item(i)if item:todo_item = item.data(Qt.UserRole)items.append(todo_item)# 根据self.sort_value决定排序方向if self.sort_value == "asc":items.sort(key=self.sort_key)else:items.sort(key=self.sort_key, reverse=True)# 清空列表self.to_do_list.clear()# 重新添加排序后的任务for item in items:self.add_item(item.title, item.description, item.deadline_time, item.is_completed)def sort_key(self, item):item.deadline_time.replace(":",":")if item.deadline_time == "未知":return datetime.datetime.maxelse:return datetime.datetime.strptime(item.deadline_time.replace(":",":"), "%Y-%m-%d %H:%M")
自定义排序规则

在Python中自定义排序规则,你可以使用内置的sorted()函数或者列表对象的sort()方法,并通过key参数指定一个函数来定义排序规则。这个函数会对每个元素进行处理,并返回一个值,排序将根据这个返回值进行。

  1. 按字符串长度排序

    strings = ["apple", "banana", "cherry", "date"]
    sorted_strings = sorted(strings, key=len)
    print(sorted_strings)  # 输出: ['date', 'apple', 'banana', 'cherry']
    
  2. 使用lambda函数按字符串的最后一个字符排序

    strings = ["apple", "banana", "cherry", "date"]
    sorted_strings = sorted(strings, key=lambda x: x[-1])
    print(sorted_strings)  # 输出: ['banana', 'apple', 'date', 'cherry']
    
  3. 复杂排序规则,先按字符串长度排序,再按字母顺序排序

    strings = ["apple", "banana", "cherry", "date"]
    sorted_strings = sorted(strings, key=lambda x: (len(x), x))
    print(sorted_strings)  # 输出: ['date', 'apple', 'banana', 'cherry']
    
  4. 使用cmp_to_key将传统比较函数转换为key函数

    from functools import cmp_to_keydef compare(x, y):if x < y:return -1elif x > y:return 1else:return 0numbers = [3, 2, 5, 4, 1]
    sorted_numbers = sorted(numbers, key=cmp_to_key(compare))
    print(sorted_numbers)  # 输出: [1, 2, 3, 4, 5]
    

优化条目显示

添加一个标题布局,显示列表的标题 => 放一个水平布局在QListWidget上对齐就可以

在这里插入图片描述

分离显示与数据(QlistWidget):

  • 不再直接使用 QListWidgetItem(text),而是通过 setItemWidget 绑定自定义Widget
  • 数据仍存储在 ToDoItem 对象中,界面仅负责展示

自定义Widget布局控制:

  • 使用 QHBoxLayout 实现水平分列
  • setAlignment 控制对齐方向
  • setContentsMargins 调整内容间距
Bug解析
  1. 文字出现了上下截断的情况,尝试过设置延伸策略给item设置固定宽高都不能根治
    在这里插入图片描述

    发现随着高度的变大,显示的内容越来越多,所以猜测是QLabel有默认的padding,所以截断了文字
    最后设置QStyleSheet成功解决

# TODO 优化时间显示居右
# 创建 ToDoItem 实例
todo_item = ToDoItem(title, description,deadline_time,is_completed)
# 创建新的列表项  创建自定义Widget
item_widget = QWidget()
layout = QHBoxLayout()# 标题部分
title_label = QLabel(todo_item.title)
title_label.setStyleSheet("QLabel{padding:0px}")
title_label.setAlignment(Qt.AlignmentFlag.AlignLeft| Qt.AlignmentFlag.AlignVCenter)# 时间部分
time_label = QLabel(todo_item.deadline_time)
time_label.setStyleSheet("QLabel{padding:0px}") # 添加padding设置,Qlabel有默认padding,不设置话,会将文字截断
time_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)# 添加控件到布局
layout.addWidget(title_label)
layout.addWidget(time_label)
item_widget.setLayout(layout)# 创建ListWidgetItem
item = QListWidgetItem()
item.setSizeHint(item_widget.sizeHint())  # 设置每一项的宽高
item.setToolTip(todo_item.description) # 设置悬浮提示
item.setData(Qt.UserRole, todo_item)  # 保存任务对象
item.setFlags(item.flags() | Qt.ItemIsSelectable | Qt.ItemIsEnabled |Qt.ItemIsUserCheckable)
if todo_item.is_completed:item.setCheckState(Qt.CheckState.Checked)  
else:item.setCheckState(Qt.CheckState.Unchecked)self.to_do_list.addItem(item)self.to_do_list.setItemWidget(item, item_widget)# 清空输入框self.title_input.clear()self.description_input.clear()self.deadline_input.clear()
  1. 绑定自定义widget后,点击无法改变itemcheckState
    解决方法有很多种,这里采用连接父ListWidget的双击信号
self.to_do_list.doubleClicked.connect(self.on_double_clicked)def on_double_clicked(self, index: QModelIndex):print(index.row())  # 打印行号print(index.column())  # 打印列号(通常为 0)item = self.to_do_list.itemFromIndex(index)  # 获取 QListWidgetItemif item.checkState() == Qt.CheckState.Unchecked:item.setCheckState(Qt.CheckState.Checked)elif item.checkState() == Qt.CheckState.Checked :item.setCheckState(Qt.CheckState.Unchecked)print(item.text())  # 打印项的文本

添加动画效果

最终代码

https://github.com/0zxm/ToDoApp/tree/master

相关文章:

pyqt写一个待办程序

ToDoApp 框架选择 一个简单的GUI程序&#xff0c;可以使用pyqt完成。pyqt是qt的python实现版本。 界面搭建 设计一个美观 简洁的界面 class ToDoApp(QWidget):def __init__(self):super().__init__()# 设置窗口属性self.setWindowTitle("Daily To Do List")self…...

总结前端常用数据结构 之 数组篇【JavaScript -包含常用数组方法】

【亲爱的读者&#xff0c;爱博主记得一键三连噢噢ooo~~ 啾咪】 创建数组&#xff1a; 以字面量的形式创建新数组&#xff1a;let arr1 [1, 2, 3];通过 Array 构造函数并传入一组元素&#xff08;4,5,6&#xff09;来创建一个新数组&#xff1a;let arr2 new Array(4, 5, 6);…...

利率掉期(Interest Rate Swap):运作原理、收益模式及市场角色解析(中英双语)

利率掉期&#xff08;Interest Rate Swap&#xff09;&#xff1a;运作原理、收益模式及市场角色解析 引言 利率掉期&#xff08;Interest Rate Swap, IRS&#xff09; 是金融市场中最常见的衍生品之一&#xff0c;它允许两方交换固定利率和浮动利率&#xff0c;以优化融资成…...

Mac 开发工具推荐

Homebrew 软件安装管理必备神器&#xff0c;相当于 Linux 上的 yum&#xff0c;安装了homebrew之后&#xff0c;以下软件都可以通过brew cask install 和 brew install进行直接安装 IntelliJ IDEA Java开发ide 相关插件&#xff1a; 1&#xff09;lombok 2&#xff09;Aliba…...

NCHAR_CS和CHAR_CS,导致UNION ALL 时,提示SQL 错误 [12704] [72000]: ORA-12704: 字符集不匹配

检查涉及的数据表和列的字符集设置 -- 查询表的字符集 SELECT parameter, value FROM nls_database_parameters WHERE parameter LIKE NLS_CHARACTERSET;-- 查询列的字符集&#xff08;对于特定表&#xff09; SELECT column_name, character_set_name FROM all_tab_columns W…...

使用 Python paramiko 自动备份设备配置实验

一、实验拓扑&#xff1a; 要求&#xff1a;交换机 SW1 做为 SSH 服务端&#xff0c;桥接本地虚拟虚拟网卡&#xff1b;本地主机通过 python paramiko 库功能登录到 SW1 上进行配置备份&#xff1b;AR1 做为测试 SW1 的 SSH 客户端 二、实验环境搭建&#xff1a; 1、SW1 配置…...

goland2022.3.3 安装过程

到csdn下载安装包 开始安装 安装完后&#xff0c;安装中文包...

工业级推荐系统冷启动解决方案:基于元迁移学习与动态知识图谱的混合架构设计与实践

技术原理与数学模型 1. 元学习冷启动适配器&#xff08;MAML改进&#xff09; 数学原理&#xff1a; \min_\theta \sum_{\mathcal{T}_i\sim p(\mathcal{T})} \mathcal{L}_{\mathcal{T}_i}(U_i(\theta - \alpha\nabla_\theta\mathcal{L}_{\mathcal{T}_i}^{sup}(\theta))))其中…...

小小小病毒(3)(~_~|)

一分耕耘一分收获 声明&#xff1a; 仅供损害电脑&#xff0c;不得用于非法。损坏电脑&#xff0c;作者一律不负责。此作为作者原创&#xff0c;转载请经过同意。 欢迎来到小小小病毒&#xff08;3&#xff09; 感谢大家的支持 还是那句话&#xff1a;上代码&#xff01; …...

在 WSL上的 Ubuntu 中通过 Docker 来运行 Redis,并在微服务项目中使用redis

通过在 WSL&#xff08;Windows Subsystem for Linux&#xff09;上的 Ubuntu 虚拟机中通过 Docker 来运行 Redis&#xff0c;然后再微服务项目中使用redis 以下是步骤&#xff1a; 1. 安装 Docker&#xff08;如果还未安装&#xff09; 首先&#xff0c;确保你已经在 WSL 的…...

深入解析SVG图片原理:从基础到高级应用

文章目录 引言一、SVG基础概念1.1 什么是SVG&#xff1f;1.2 SVG的优势 二、SVG的基本结构2.1 SVG文档结构2.2 常用SVG元素 三、SVG的工作原理3.1 坐标系与变换3.2 路径与曲线3.3 渐变与滤镜 四、SVG的高级应用4.1 动画与交互4.2 数据可视化4.3 响应式设计 五、SVG的优化与性能…...

Python 中的一种调试工具 assert

assert 是 Python 中的一种调试工具&#xff0c;用于在代码中设置断言&#xff08;assertion&#xff09;。断言是一种声明&#xff0c;用于确保某个条件为真。如果条件为假&#xff0c;assert 会触发一个 AssertionError 异常&#xff0c;并可选地输出错误信息。 语法 asser…...

面基Spring Boot项目中实用注解一

在Spring Boot项目中&#xff0c;实用注解根据功能可以分为多个类别。以下是常见的注解分类、示例说明及对比分析&#xff1a; 1. 核心配置注解 SpringBootApplication 作用&#xff1a;标记主启动类&#xff0c;组合了Configuration、EnableAutoConfiguration和ComponentScan…...

【数据库维护】Clickhouse数据库维护关键系统表相关指标说明,支撑定位慢SQL及多实例场景下分析各实例运行情况

背景 当前使用环境上以Docker容器化部署Clickhouse服务8个实例&#xff0c;但在实际运行过程中&#xff0c;发现8个实例内存负载不均衡&#xff0c;ck-0实例在固定时间段内存会直线上升&#xff0c;直至服务报错memory exceeded max memory limit。 为排查ck-0节点内存直线上升…...

委托构造函数与继承构造函数

委托构造函数 允许同一类中的构造函数调用另一个构造函数&#xff0c;以复用初始化逻辑。 委托构造函数不能同时初始化成员变量&#xff0c;只能委托给其他构造函数。 避免循环委托&#xff08;如构造函数A委托给B&#xff0c;B又委托给A&#xff09;。 class MyClass { pu…...

DeepSeek操作Excel,实现图表自动化生成

案例 让DeepSeek操作Excel&#xff0c;实现图表自动化生成。我们只要用自然语言输入我们的需求&#xff08;根据哪块单元格区域做什么图表&#xff09;&#xff0c;就可以直接在Excel中自动生成图表。 操作主界面和图表效果 设置接入方式 这里提供了多种接入方式将DeepSeek接…...

3.5 企业级AI Agent运维体系构建:从容器化部署到智能监控的工业级实践指南

企业级AI Agent运维体系构建:从容器化部署到智能监控的工业级实践指南 引言:AI时代运维的范式革新 Gartner研究指出,AI Agent系统的运维复杂度是传统应用的3.2倍,但采用云原生架构可使故障恢复时间缩短82%。本文以GitHub Sentinel、LanguageMentor等企业级案例为蓝本,揭…...

基于51单片机的定时器实现LED闪烁控制(CT107D)

引言 在嵌入式开发中&#xff0c;定时器是一个非常重要的外设&#xff0c;它可以用于实现精确的时间控制。本文将介绍如何在CT107D单片机综合训练平台上&#xff0c;利用51单片机的定时器T0实现LED灯的定时闪烁控制。具体功能如下&#xff1a; L1指示灯&#xff1a;每隔1秒闪烁…...

【java】作业1

1.需求&#xff1a;&#xff08;1&#xff09;机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、原价、月份和头等舱或经济舱&#xff1b;&#xff08;2&#xff09;按照如下规则计算机票价格&#xff1a;旺季&#xff08;5-10月&#xff09;头等舱9折&#xff0c;经济…...

2025有哪些关键词优化工具好用

越来越多的企业和个人开始意识到搜索引擎优化&#xff08;SEO&#xff09;对于网站曝光和业务增长的重要性。在SEO优化的过程中&#xff0c;关键词优化占据着至关重要的地位。关键词是用户在搜索引擎中输入的词语&#xff0c;优化关键词有助于提高网站在搜索结果中的排名&#…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...