combobox5.items中的按时间排序_使用wxPython打造印象笔记(17)笔记排序和重构管理笔记本功能...

8afd20e94b6bc5488bce3fbc0ca25240.png

这篇文章我们来实现笔记列表的排序和笔记本编辑删除功能,最终实现效果如下:

04809ac085ed12d1c10a3f33f3abe33b.gif
笔记排序

46d0ce188935c0fedf4fea05eb48b88d.gif
笔记本重命名(编辑)

4295c8f674757f50c628d031106385f0.gif
删除笔记本

笔记排序功能

用户从排序菜单中点击一个排序选项之后,笔记列表将清空,然后列表中的笔记执行排序操作,最后笔记列表会加载已排序的笔记。

需要注意的地方:

  1. 如果排序前笔记A高亮(预览面板的背景色加深),那么排序之后,笔记A依然需要高亮,并且文本编辑器不发生变化
  2. 用户选择的排序选项需要记录下来,如果用户选择了按字母排序,那么当用户再次点击排序按钮时,按字母排序选项应该是勾选状态。并且切换笔记本时,笔记列表也需要按字母排序。

构造排序菜单

e6f07291a27c91c4bbc8cfedb296a7b6.png

修改 views / header_panel.py,初始化的时候添加几个成员变量:

from models import Note

# 修改 __init__
self._sort_menu_ids = wx.NewIdRef(6)
self._checked_menu_id = self._sort_menu_ids[0]
self.sort_option = Note.updated_at.desc()

如果需要将全部笔记按更新时间逆序排列,则代码如下:

Note.select().order_by(Note.updated_at.desc())

sort_option 就是排序选项,同理按标题顺序排列时,sort_option 就等于 Note.title.asc()。

接下来定义一个创建排序菜单的方法:

def _build_sort_menu(self):
    menu = wx.Menu()

    sub_menu1 = wx.Menu()
    sub_menu1.AppendCheckItem(self._sort_menu_ids[0], '最新到最旧')
    sub_menu1.AppendCheckItem(self._sort_menu_ids[1], '最旧到最新')
    menu.AppendSubMenu(sub_menu1, '按更新时间')

    sub_menu2 = wx.Menu()
    sub_menu2.AppendCheckItem(self._sort_menu_ids[2], '最新到最旧')
    sub_menu2.AppendCheckItem(self._sort_menu_ids[3], '最旧到最新')
    menu.AppendSubMenu(sub_menu2, '按创建时间')

    sub_menu3 = wx.Menu()
    sub_menu3.AppendCheckItem(self._sort_menu_ids[4], '逆字母排序')
    sub_menu3.AppendCheckItem(self._sort_menu_ids[5], '字母排序')
    menu.AppendSubMenu(sub_menu3, '按标题')

    return menu

定义一个 _init_event 方法,用来处理事件绑定;定义 _show_sort_menu 来显示排序菜单。

def _init_event(self):
    self.btn_display_order_options.Bind(wx.EVT_BUTTON, self._show_sort_menu)

def _show_sort_menu(self, _):
    menu = self._build_sort_menu()
    menu.Check(self._checked_menu_id, True)
    self.PopupMenu(menu)
    menu.Destroy()

运行主程序,点击排序按钮,可以看到排序菜单了。

实现排序逻辑

排序菜单可以正常显示了,接下来在菜单上添加事件绑定,可以看到,不同的排序选项菜单实际上对应不同的排序参数,所以事件处理方法中需要接收排序参数和必要的事件对象。

修改 header_panel.py:

from functools import partial
from pubsub import pub

def _on_note_sorting(self, e, sort_param):
    if self._checked_menu_id != e.GetId():
        self._checked_menu_id = e.GetId()
        self.sort_option = sort_param
        pub.sendMessage('note.sorting', sort_param=sort_param)

# 修改 _init_event
def _init_event(self):
    # ....
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.updated_at.desc()), id=self._sort_menu_ids[0])
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.updated_at.asc()), id=self._sort_menu_ids[1])
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.created_at.desc()), id=self._sort_menu_ids[2])
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.created_at.asc()), id=self._sort_menu_ids[3])
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.title.desc()), id=self._sort_menu_ids[4])
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.title.asc()), id=self._sort_menu_ids[5])
    self.Bind(wx.EVT_MENU, partial(self._on_note_sorting, sort_param=Note.title.asc()), id=self._sort_menu_ids[5])

点击排序选项时,将传进来的排序参数保存下来,然后发送 note.sorting 消息。为了让代码简洁,我们使用了partial高阶函数。

现在点击排序菜单时,我们可以得到对应的排序参数了,编辑 list_panel.py,订阅 note.sorting :

# 编辑 __init__
pub.subscribe(self._on_note_sorting, 'note.sorting')

def _on_note_sorting(self, sort_param):
    notes = list(Note.select().where(Note.id.in_(self._note_ids)).order_by(sort_param))
    self._load(notes)

运行主程序,测试之后发现了一个问题,如下图所示:

6b53bef86830fd8cd8401b000cffb9e9.gif
排序操作存在的问题

可以看到,排序之前笔记 11111 选中,排序之后却是笔记 test 被选中了,并且文本编辑器也随之变化了。预期效果应该是:选中的笔记和文本编辑器都不会发生变化。

排序操作不影响已选中的笔记

ListPanel 中的 _load 方法实际上调用了 NoteListPanel 的 replace 方法,默认会选中第一条笔记,所以我们需要将 replace 方法重构一下,让它能够保存已选中的笔记。

编辑 note_list_panel.py,作如下修改:

e3c73c56e7c07a6d0189135e20eb968d.png

编辑 list_panel.py,给 _load 方法添加 preserve_select 参数:

def _load(self, notes, preserve_select=False):
    if len(notes):
        self.note_list_panel.replace(notes, preserve_select)
    # ...

def _on_note_sorting(self, sort_param):
    # ...
    self._load(notes, True)

再来测试一下,和预期一致,在排序前后,选中的都是同一条笔记。

排序选项全局范围起作用

修改 list_panel.py,应用已经选中的排序选项:

def _on_notebook_selected(self, notebook):
    # ...
    notes = list(notebook.notes.order_by(self.header_panel.sort_option))
    # ...

def _on_root_selected(self):
    # ...
    notes = list(Note.select().order_by(self.header_panel.sort_option))
    # ...

笔记本编辑和删除功能

构造菜单

修改 header_panel.py,和上面的排序菜单构造方法类似:

# 修改 __init__
self._rename_notebook_menu_id = wx.NewIdRef()
self._delete_notebook_menu_id = wx.NewIdRef()

def _show_action_menu(self, _):
    menu = self._build_action_menu()
    self.PopupMenu(menu)
    menu.Destroy()

def _init_event(self):
    # ...
    self.btn_display_notebook_options.Bind(wx.EVT_BUTTON, self._show_action_menu)
    self.Bind(wx.EVT_MENU, lambda _: pub.sendMessage('notebook.editing'), id=self._rename_notebook_menu_id)
    self.Bind(wx.EVT_MENU, lambda _: pub.sendMessage('notebook.deleting'), id=self._delete_notebook_menu_id)

实现编辑笔记本功能

编辑和删除笔记本功能之前已经实现过了,当时相关逻辑放在了 NoteTree 组件中,参考:

ac2190:使用wxPython打造印象笔记(14)笔记本管理​zhuanlan.zhihu.com
342b5de942889ca940fea8cbf90ead67.png

所以我们只需要复用这部分逻辑就行了,关键点在于让笔记列表和笔记本导航栏数据同步:笔记本重命名之后,笔记本导航栏的节点文字会变化,笔记列表的顶部文字也需要变化。

最好是将这类逻辑放在主窗体 MainFrame 中,便于代码复用。

修改 note_tree.py:

def _edit_notebook(self, _):
    pub.sendMessage('notebook.editing')

def set_text(self, text):
    self.SetItemText(self.GetSelection(), text)

修改 main_frame.py:

from pubsub import pub
from .notebook_dialog import NotebookDialog

def _register_listeners(self):
    # ...
    pub.subscribe(self._on_notebook_editing, 'notebook.editing')

def _on_notebook_editing(self):
    notebook = self.nav_panel.note_tree.notebook
    with NotebookDialog(self, notebook) as dialog:
        if dialog.ShowModal() == wx.ID_OK:
            notebook.name = dialog.get_name()
            notebook.description = dialog.get_description()
            notebook.save()

            self.nav_panel.note_tree.set_text(notebook.name)
            self.list_panel.header_panel.set_title(notebook.name)

实现删除笔记本功能

和上面的方法类似,将 NoteTree 里面的删除笔记本逻辑转移到 MainFrame 中,并提供一个删除节点的方法。

修改 note_tree.py:

def _delete_notebook(self, _):
    pub.sendMessage('notebook.deleting')

def delete_selection(self):
    self.GetSelection().GetData().delete_instance()
    self.Delete(self.GetSelection())

修改 main_frame.py:

def _register_listeners(self):
    # ...       
    pub.subscribe(self._on_notebook_deleting, 'notebook.deleting')

def _on_notebook_deleting(self):
    dialog = wx.MessageDialog(self, '此笔记本中的任何笔记都将被删除,这个操作不能恢复。', '确定要删除吗?',style=wx.OK|wx.CANCEL|wx.CANCEL_DEFAULT)
    dialog.SetOKCancelLabels('确定', '取消')

    if dialog.ShowModal() == wx.ID_OK:
        self.nav_panel.note_tree.delete_selection()

总结

笔记列表顶部的两个右键菜单功能已经实现,后面的文章中将开发笔记搜索功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值