YASB Notes 便签小组件配置与实现指南:从状态栏随手记到 JSON 持久化

发布时间:2026/10/12 3:03:31
YASB Notes 便签小组件配置与实现指南:从状态栏随手记到 JSON 持久化 桌面应用【免费下载链接】yasbA highly configurable Windows status bar written in Python.项目地址https://gitcode.com/gh_mirrors/yas/yasb点击查看免费下载导读Notes是 YASBYet Another Status Bar一款基于 Python/PyQt6 的高可配置 Windows 状态栏内置的速记工具小组件点击状态栏上的便签图标即可弹出一个悬浮草稿本让你随时写下、保存、复制和删除快速笔记并在标签上实时显示当前笔记数量。本文以官方文档 docs/widgets/(Widget)-Notes.md-Notes.md) 为骨架结合 源码实现 与 配置校验模型完整讲解其全部配置项、样式体系、JSON 数据持久化机制以及浮动窗口等底层原理读完后你可以把 Notes 组件直接接入自己的config.yaml并按喜好完成深度定制。一、功能概览状态栏里的速记草稿本从 NotesWidget 源码 可以看出该组件本质是一个继承自BaseWidget的状态栏控件核心能力包括随时弹出输入框点击小组件即可打开一个带输入框的弹出菜单Popup输入内容后点击 “Add Note” 或按回车即可保存笔记列表展示菜单内以列表形式展示所有笔记每条显示标题首行文本与时间戳并提供复制、删除按钮点击即编辑单击某条笔记会将其内容回填到输入框进入编辑模式按钮变为 “Save Changes”标签实时计数状态栏标签中的{count}占位符会被替换为当前笔记总数浮动窗口模式菜单可以切换为无边框的浮动窗口拖拽标题栏即可移动到屏幕任意位置并支持按显示器居中JSON 持久化所有笔记以 JSON 数组格式存储在~/.config/yasb/notes.json可随意备份、迁移。源码层面组件把职责拆分为三个部分类文件职责NotesWidgetsrc/core/widgets/yasb/notes.py主控件标签渲染、菜单生命周期、笔记增删改查、JSON 读写NotesPopupsrc/core/widgets/services/notes/utils.py弹出菜单窗口无边框、置顶、失焦自动关闭、浮动模式切换NoteTextEditsrc/core/widgets/services/notes/utils.py自定义文本输入框回车提交、Shift回车换行、Tab 缩进、粘贴策略FloatingWindowControllersrc/core/widgets/services/notes/utils.py浮动模式控制器切换浮动/停靠、标题栏拖拽、屏幕居中二、配置总览与完整示例在config.yaml中Notes 组件的标准写法如下与文档示例一致可直接复制使用notes: type: yasb.notes.NotesWidget options: label: span\ue70b/span {count} label_alt: {count} notes # data_path: ~/Documents/my-notes.json # Optional: custom JSON file path menu: blur: true round_corners: true round_corners_type: normal border_color: System alignment: right direction: down offset_top: 6 offset_left: 0 show_date_time: true icons: note: \ue70b delete: \ue74d copy: \ue8c8 float_on: \ue922 float_off: \ue923 close: \ue8bb callbacks: on_left: toggle_menu on_middle: do_nothing on_right: toggle_label其中type字段yasb.notes.NotesWidget与 widgets 注册机制 中按模块名.类名生成的注册键完全对应options下的每个字段都会经过 pydantic 配置模型 严格校验——未知字段会被extraforbid直接拒绝见 base_model.py这保证了配置错误能尽早暴露。三、顶层配置项详解以下表格完整继承自官方文档并补充了源码层的实现细节OptionType默认值说明labelStringspan\udb82\udd0c/span {count}主标签模板支持{count}占位符动态替换为笔记数量label_altString{count} notes切换小组件显示模式时使用的备用标签格式class_nameString附加 CSS 类名用于个性化样式定制data_pathString笔记 JSON 文件的自定义路径留空使用默认位置~/.config/yasb/notes.json支持~展开start_floatingBooleanfalse菜单是否以浮动模式启动paste_plain_textBooleanfalse为true时默认以纯文本粘贴ShiftCtrlV粘贴富文本为false时行为反转enter_to_add_noteBooleantrue为true时输入框内按 Enter 添加新笔记、ShiftEnter 换行为false时反转menuDict见下文弹出菜单设置iconsDict见下文组件内使用的图标callbacksDict{ on_left: toggle_menu, on_middle: do_nothing, on_right: toggle_label }鼠标动作到组件函数的映射keybindingsList[]键盘快捷键绑定可选见下文“源码扩展”3.1label与label_alt动态计数标签标签的渲染逻辑位于 notes.py 的_update_label标签内容会被正则(span.*?.*?/span)拆分成若干片段span包裹的部分渲染为图标对应 CSS 类.icon其余文本渲染为文字标签文本片段中的{count}会被替换为len(self.notes)即当前笔记总数label_alt仅在切换显示模式时显示——切换本身由toggle_label回调驱动内部通过 BaseWidget 的双标签机制_widgets与_widgets_alt两组 QLabel 的显隐切换实现。例如label: span\ue70b/span {count}会显示“ 3”而切换模式后显示label_alt的“3 notes”。3.2data_path笔记文件位置data_path为空时代码通过os.path.join(HOME_CONFIGURATION_DIR, notes.json)确定默认存储位置notes.py 第 70-75 行其中HOME_CONFIGURATION_DIR定义于 src/core/config.py即~/.config/yasb/目录。若指定了路径则通过os.path.expanduser()展开~因此你可以写data_path: ~/Documents/my-notes.json # Linux 风格 data_path: C:/Users/YourName/my-notes.json # Windows 风格[!IMPORTANT] 所有笔记都以 JSON 格式保存在.config/yasb/notes.json中。你只需备份这一个文件即可随时恢复全部笔记。3.3enter_to_add_note与paste_plain_text输入行为这两个选项都在 NoteTextEdit 中实现回车行为keyPressEvent中判断enter_to_add_note ! bool(Shift 修饰键)相等才调用add_note_from_input()提交笔记否则插入换行——这正是“Enter 提交 / ShiftEnter 换行”可反转的底层逻辑粘贴行为普通CtrlV走insertFromMimeData()根据paste_plain_text决定是insertPlainText()纯文本插入还是保留 HTML 富文本并自动剥离粘贴内容中的背景色/bgcolor内联样式避免污染深色界面ShiftCtrlV则强制反转策略。输入框还内置了复制按钮input-copy-button和带缩进感知的 Tab/ShiftTab 处理。四、menu弹出菜单设置menu子配置项控制弹出菜单的外观与定位OptionType默认值说明blurBooleantrue菜单是否启用模糊背景效果round_cornersBooleantrue菜单是否显示圆角round_corners_typeStringnormal圆角样式允许值为normal和smallborder_colorStringSystem菜单边框颜色alignmentStringright菜单相对小组件的水平对齐方式left/right/centerdirectionStringdown菜单展开方向down/upoffset_topInteger6垂直方向微调偏移像素offset_leftInteger0水平方向微调偏移像素show_date_timeBooleantrue是否显示笔记的时间戳定位逻辑的核心在 PopupWidget.setPosition菜单以小组件自身为锚点结合alignmentleft/right/center、directionup/down以及offset_left/offset_top计算全局坐标并自动夹紧在当前屏幕范围内防止弹出菜单超出显示器边界。blur、round_corners、round_corners_type、border_color则透传给 NotesPopup 的无边框置顶窗口。时间戳的显示由show_date_time控制每条笔记在渲染时其timestamp字段会被datetime.datetime.fromisoformat解析并格式化为%Y-%m-%d %H:%M见 notes.py 第 533-541 行。五、icons图标设置组件内部使用 Segoe Fluent Icons-Notes.md) 等图标字体的码点icons子配置定义如下OptionType默认值说明noteString\ue70b笔记条目左侧的图标deleteString\ue74d删除笔记按钮图标copyString\ue8c8复制文本按钮图标float_onString\ue922可启用浮动模式时的图标float_offString\ue923可禁用浮动模式时的图标closeString\ue8bb标题栏关闭按钮图标在 配置模型 中copy字段通过 pydantic 的alias映射到内部字段copy_icon确保文档层与代码层的命名各自清晰。float_on/float_off会在浮动状态切换时互换见 FloatingWindowController.toggle_floatingclose按钮则只在浮动模式下显示因为停靠模式下点击菜单外部即可关闭。六、callbacks鼠标回调callbacks将鼠标动作映射为组件函数实现于 BaseWidget._handle_mouse_events即左键/中键/右键分别触发callback_left/callback_middle/callback_rightOption默认值说明on_lefttoggle_menu左键点击打开/关闭笔记菜单on_middledo_nothing中键点击无动作on_righttoggle_label右键点击在主标签与备用标签间切换组件在初始化时注册了三个可回调动作notes.py 第 80-82 行toggle_menu菜单不存在或不可见时打开否则关闭_show_menu/_close_menutoggle_label切换label与label_alt的显示update_label刷新标签内容同时被注册为定时回调callback_timer。七、样式定制Available Styles组件所有界面元素都挂载了稳定的 CSS 类可以直接在 YASB 的样式文件中覆盖。以下类名完整继承自官方文档/* 主组件容器 */ .notes-widget {} .notes-widget.your_class {} /* 使用了 class_name 选项时 */ /* 标签与图标 */ .notes-widget .label {} .notes-widget .icon {} /* 弹出菜单 */ .notes-menu {} /* 浮动状态下的弹出菜单 */ .notes-menu.floating {} /* 菜单标题栏 */ .notes-menu .notes-header {} .notes-menu .notes-header .header-title {} .notes-menu .notes-header .float-button {} .notes-menu .notes-header .close-button {} /* 菜单内的笔记条目 */ .notes-menu .note-item {} .notes-menu .note-item .title {} .notes-menu .note-item .date {} /* 无笔记时的提示 */ .notes-menu .empty-list {} /* 添加 / 取消按钮 */ .notes-menu .add-button, .notes-menu .cancel-button {} /* 笔记滚动区域 */ .notes-menu .scroll-area {} /* 笔记输入框 */ .notes-menu .note-input {} .notes-menu .note-input:focus {} /* 输入框内复制按钮 */ .notes-menu .input-copy-button {} .notes-menu .input-copy-button:hover {} .notes-menu .input-copy-button:pressed {} /* 删除按钮 */ .notes-menu .delete-button {} .notes-menu .delete-button:hover {} .notes-menu .delete-button:pressed {} /* 复制按钮 */ .notes-menu .copy-button {} .notes-menu .copy-button:hover {} .notes-menu .copy-button:pressed {}八、完整样式示例Example Style官方文档提供了一套可直接落地的深色主题样式包含关键细节常规模式菜单固定400 × 500浮动模式放宽到700 × 500且输入框可扩展到 100px 高按钮使用透明底 悬停高亮所有图标指定Segoe Fluent Icons字体族.notes-widget { padding: 0; } .notes-widget .label { font-size: 14px; color: #dbfeb4; } .notes-widget .icon { font-size: 16px; color: #dbfeb4; font-family: Segoe Fluent Icons; } /* Notes Widget Menu */ .notes-menu { min-width: 400px; max-width: 400px; min-height: 500px; background-color: rgba(27, 27, 27, 0.8); } /* Floating state - can have different size */ .notes-menu.floating { min-width: 700px; max-width: 700px; min-height: 500px; max-height: 500px; } /* Notes Widget Menu Header */ .notes-menu .notes-header { background-color: rgba(0, 0, 0, 0); padding: 4px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .notes-menu .notes-header .header-title { font-size: 16px; font-weight: 800; color: white; } .notes-menu .notes-header .float-button, .notes-menu .notes-header .close-button { background-color: transparent; border: none; color: #cfcfcf; font-size: 14px; min-height: 32px; max-height: 32px; min-width: 32px; max-width: 32px; font-family: Segoe Fluent Icons; } .notes-menu .notes-header .float-button:hover, .notes-menu .notes-header .close-button:hover { background-color: rgba(255, 255, 255, 0.1); border-radius: 4px; } .notes-menu .notes-header .close-button { margin-left: 8px; } .notes-menu .note-item { background-color: transparent; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .notes-menu .note-item:hover { background-color: rgba(255, 255, 255, 0.1); } .notes-menu .note-item .icon { font-size: 16px; padding: 0 4px; font-family: Segoe Fluent Icons; } .notes-menu .delete-button { color: #ff6b6b; background: transparent; border: none; font-size: 12px; min-height: 24px; max-height: 24px; min-width: 24px; max-width: 24px; border-radius: 4px; font-family: Segoe Fluent Icons; } .notes-menu .delete-button:hover { background-color: rgba(128, 128, 128, 0.5); } .notes-menu .copy-button { color: #babfd3; background: transparent; border: none; font-size: 14px; min-height: 24px; max-height: 24px; min-width: 24px; max-width: 24px; border-radius: 4px; margin-bottom: 4px; font-family: Segoe Fluent Icons; } .notes-menu .copy-button:hover { background-color: rgba(128, 128, 128, 0.5); } .notes-menu .copy-button:pressed { color: #ffffff; } .notes-menu .note-item .title { font-size: 13px; font-family: Segoe UI } .notes-menu .note-item .date { font-size: 12px; font-family: Segoe UI; color: rgba(255, 255, 255, 0.4); } .notes-menu .empty-list { font-family: Segoe UI; color: rgba(255, 255, 255, 0.2); font-size: 24px; font-weight: 600; padding: 10px 0 20px 0; } .notes-menu .add-button, .notes-menu .cancel-button { padding: 8px; background-color: rgba(255, 255, 255, 0.1); border: none; border-radius: 4px; color: white; font-family: Segoe UI } .notes-menu .cancel-button { margin-left: 4px; } .notes-menu .add-button:hover, .notes-menu .cancel-button:hover { background-color: rgba(255, 255, 255, 0.2); } .notes-menu .scroll-area { background: transparent; border: none; border-radius: 0; } .notes-menu .note-input { background-color: rgba(48, 48, 48, 0.2); border: 1px solid rgba(255, 255, 255, 0.2); font-family: Segoe UI; font-size: 14px; max-height: 30px; padding: 4px; border-radius: 6px; } .notes-menu.floating .note-input { max-height: 100px; } .notes-menu .note-input:focus { border: 1px solid #4c90fd; } .notes-menu .input-copy-button { color: #babfd3; background: transparent; border: none; font-size: 14px; min-height: 24px; max-height: 24px; min-width: 24px; max-width: 24px; border-radius: 4px; margin-top: 2px; margin-right: 2px; font-family: Segoe Fluent Icons; } .notes-menu .input-copy-button:hover { background-color: rgba(255, 255, 255, 0.1); } .notes-menu .input-copy-button:pressed { color: #ffffff; }九、源码纵深数据存储、浮动窗口与多实例同步9.1 JSON 数据结构与读写流程笔记文件是一个 JSON 数组每个元素包含三个字段见 add_note_from_input[ { title: 购物清单, html: p牛奶、鸡蛋、面包/p, timestamp: 2026-10-11T22:30:00.123456 } ]title纯文本首行用于列表标题显示与复制html富文本 HTML用于编辑时完整还原格式timestampISO 8601 时间戳由datetime.datetime.now().isoformat()生成。写入时使用json.dump(self.notes, f, indent2, ensure_asciiFalse)notes.py 第 631-638 行UTF-8 编码、保留非 ASCII 字符、缩进美观便于手工编辑或备份。新增的笔记通过self.notes.insert(0, note_data)插入到列表头部因此新笔记总是显示在最上方。读取失败如文件损坏不会导致崩溃而是记录错误日志并返回空列表notes.py 第 619-629 行。9.2 浮动窗口从停靠菜单到自由窗口浮动模式由FloatingWindowController驱动切换toggle_floating()记录菜单停靠时的原始位置original_position切换窗口标志后调用get_target_screen()确定目标显示器并把窗口居中到该屏幕的availableGeometry()中央拖拽仅在浮动状态下标题栏的mousePressEvent/mouseMoveEvent被接管实现按住标题栏拖动窗口差异样式NotesPopup.set_floating()会把窗口的class属性在notes-menu与notes-menu floating之间切换这正是上文 CSS 中.notes-menu.floating尺寸差异生效的原因关闭策略停靠模式下NotesPopup.event()监听WindowDeactivate窗口失焦并触发hide_animated()淡出关闭浮动模式下则忽略失焦事件必须点击关闭按钮。恢复停靠时还会用setPosition()回到锚点位置。9.3 屏幕定位与快捷键扩展菜单默认锚定在小组件所在屏幕。若你配置了keybindings组件会读取其中action toggle_menu的条目来决定菜单落在哪块屏幕get_target_screen支持三种模式keybindings: - keys: altn action: toggle_menu screen: cursor # 光标所在屏幕默认可选 active / primaryKeybindingConfig中screen字段的合法值为active、cursor、primary见 base_model.py。该机制由 BaseWidget 的快捷键事件处理 与全局热键系统配合完成。9.4 多实例同步Notes 组件通过类级注册表_instances维护所有实例任何一次增删改都会调用NotesWidget.update_all()notes.py 第 98-105 行重新从磁盘加载笔记、刷新所有实例的标签计数若某实例的菜单正打开着则同步刷新列表——这意味着即使你在多条状态栏多显示器上都放置了 Notes数据也始终保持一致。十、运行效果一览上图展示了浮动模式下的界面菜单右上角出现关闭按钮停靠模式下该按钮隐藏输入框自动获得焦点笔记列表底部显示时间戳输入框旁有悬浮的复制按钮删除/复制操作按钮竖排在每条笔记右侧。十一、小结与使用建议最小接入只需在config.yaml中加入一段notes配置块见第二节并重启 YASB 即可使用数据安全notes.json是唯一的数据载体定期备份即可完整迁移笔记多显示器配合keybindings的screen选项可精确控制弹窗出现的位置深度定制所有界面元素均可通过.notes-widget/.notes-menu系列 CSS 类覆盖浮动与停靠两种状态可以拥有完全不同的尺寸与配色。相关阅读组件基类与回调机制、弹出窗口定位基类、配置校验与弃用字段处理。赞分享桌面应用【免费下载链接】yasbA highly configurable Windows status bar written in Python.项目地址https://gitcode.com/gh_mirrors/yas/yasb点击查看免费下载相关推荐yasb GPU 小组件配置指南在 Windows 状态栏实时监控显卡占用、显存与温度yasb GPU 小组件配置指南在 Windows 状态栏实时监控显卡占用、显存与温度 导读 本文面向 yasb一款基于 Python 的 Windows桌面应用YASB 的 Do Not Disturb 组件DndWidget配置指南在状态栏监控与切换 Windows 专注助手YASB 的 Do Not Disturb 组件DndWidget配置指南在状态栏监控与切换 Windows 专注助手 本文基于 YASB 官方组件文档桌面应用LibChecker工具栏状态saveToolbarMenuState与配置持久化LibChecker工具栏状态saveToolbarMenuState与配置持久化 1. 引言工具栏状态管理的重要性 在现代Android应用开发中用户界移动开发开发工具逆向工程上一篇【亲测免费】 AI代码审查器基于OpenAI GPT-4的智能代码评审助手下一篇HappyPanda X开发者指南如何为项目贡献代码创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询