May-03-2019, 10:59 PM
Similar to the other menu items, adding a edit menu with undo, cut, copy, paste and delete
Here are the event handlers for undo
The events for cut, copy and paste are similar to undo
For the delete events
The values for this are obtained by using text controls
Full Code
edit_menu = wx.Menu() self.menu_undo = edit_menu.Append(wx.ID_UNDO, '&Undo', 'Undo change') edit_menu.AppendSeparator() self.menu_cut = edit_menu.Append(wx.ID_CUT, 'Cu&t', 'Cut the selected text') self.menu_copy = edit_menu.Append(wx.ID_COPY, '&Copy', 'Copy the selected text') self.menu_paste = edit_menu.Append(wx.ID_PASTE, '&Paste', 'Paste from the clipboard') self.menu_delete = edit_menu.Append(wx.ID_DELETE, 'De&lete', 'Delete selected text') self.menubar.Append(edit_menu, '&Edit')binds for the new menu items
self.Bind(wx.EVT_MENU, self.on_menu_undo, self.menu_undo) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_undo_update, self.menu_undo) self.Bind(wx.EVT_MENU, self.on_menu_cut, self.menu_cut) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_cut_update, self.menu_cut) self.Bind(wx.EVT_MENU, self.on_menu_copy, self.menu_copy) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_copy_update, self.menu_copy) self.Bind(wx.EVT_MENU, self.on_menu_paste, self.menu_paste) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_paste_update, self.menu_paste) self.Bind(wx.EVT_MENU, self.on_menu_delete, self.menu_delete) self.Bind( wx.EVT_UPDATE_UI, self.on_menu_delete_update, self.menu_delete)These have a type of event that has not been used so far
wx.EVT_UPDATE_UI
https://wxpython.org/Phoenix/docs/html/w...Event.html Wrote:This class is used for pseudo-events which are called by wxWidgets to give an application the chance to update various user interface elements. .... see link for more details
Here are the event handlers for undo
def on_menu_undo(self, event): self.txt_ctrl.Undo() def on_menu_undo_update(self, event): event.Enable(self.txt_ctrl.CanUndo())
on_menu_undo
is straight forward, on_menu_undo_update
will enable or disable the menu item depending on if the text control can be undone or not.The events for cut, copy and paste are similar to undo
For the delete events
def on_menu_delete(self, event): self.txt_ctrl.Remove(*self.txt_ctrl.GetSelection()) def on_menu_delete_update(self, event): event.Enable(bool(self.txt_ctrl.GetStringSelection()))
on_menu_delete
uses the text controls remove
method which removes the text starting at the first given position up to (but not including) the character at the last position.The values for this are obtained by using text controls
GetSelection
method.on_menu_delete_update
enables or disables the delete menu item by using bool
to get a true or false from the result of method GetSelection
which gets the text currently selected in the control or if there is no selection, the returned string is empty.Full Code
from pathlib import Path import webbrowser import wx WILDCARD = 'Text Documents (*.txt)|*.txt|Python Documents (*.py)|*.py' UNTITLED = 'Untitled' HELP_URL = 'https://python-forum.io/Thread-WxPython-Tutorial-Notespad-W-I-P' class Notespad(wx.Frame): def __init__(self, *args, **kwargs): super(Notespad, self).__init__(*args, **kwargs) self.path = None self.frame_settings() self.create_menus() self.create_gui_items() self.create_sizers() self.add_binds() def frame_settings(self): self.update_title() self.CreateStatusBar() self.SetMinSize((600, 400)) self.CentreOnScreen() def create_menus(self): self.menubar = wx.MenuBar() self.SetMenuBar(self.menubar) self.create_file_menu() self.create_edit_menu() self.create_help_menu() def create_file_menu(self): file_menu = wx.Menu() self.menu_new = file_menu.Append(wx.ID_NEW, '&New', 'Creates a new document') self.menu_open = file_menu.Append(wx.ID_OPEN, '&Open', 'Open an existing file') self.menu_save = file_menu.Append(wx.ID_SAVE, '&Save', 'Saves the active document') self.menu_saveas = file_menu.Append(wx.ID_SAVEAS, 'Save &As', 'Saves the active document with a new name') file_menu.AppendSeparator() self.menu_exit = file_menu.Append(-1, 'E&xit', 'Exit the Application') self.menubar.Append(file_menu, '&File') def create_edit_menu(self): edit_menu = wx.Menu() self.menu_undo = edit_menu.Append(wx.ID_UNDO, '&Undo', 'Undo change') edit_menu.AppendSeparator() self.menu_cut = edit_menu.Append(wx.ID_CUT, 'Cu&t', 'Cut the selected text') self.menu_copy = edit_menu.Append(wx.ID_COPY, '&Copy', 'Copy the selected text') self.menu_paste = edit_menu.Append(wx.ID_PASTE, '&Paste', 'Paste from the clipboard') self.menu_delete = edit_menu.Append(wx.ID_DELETE, 'De&lete', 'Delete selected text') self.menubar.Append(edit_menu, '&Edit') def create_help_menu(self): help_menu = wx.Menu() self.menu_help = help_menu.Append(wx.ID_HELP, '&Help', 'Get Help from python-forum.io') self.menubar.Append(help_menu, '&Help') def create_gui_items(self): self.frame_panel = wx.Panel(self) self.txt_ctrl = wx.TextCtrl(self.frame_panel, style=wx.TE_MULTILINE | wx.BORDER_NONE) def create_sizers(self): sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.frame_panel, 1, wx.EXPAND) p_sizer = wx.BoxSizer(wx.VERTICAL) p_sizer.Add(self.txt_ctrl, 1, wx.EXPAND) self.frame_panel.SetSizer(p_sizer) self.SetSizer(sizer) self.Layout() def add_binds(self): self.add_frame_binds() self.add_fle_menu_binds() self.add_edit_menu_binds() self.add_help_menu_binds() def add_frame_binds(self): self.Bind(wx.EVT_CLOSE, self.on_close_evt) def add_fle_menu_binds(self): self.Bind(wx.EVT_MENU, self.on_menu_new, self.menu_new) self.Bind(wx.EVT_MENU, self.on_menu_open, self.menu_open) self.Bind(wx.EVT_MENU, self.on_menu_save, self.menu_save) self.Bind(wx.EVT_MENU, self.on_menu_saveas, self.menu_saveas) self.Bind(wx.EVT_MENU, self.on_menu_exit, self.menu_exit) def add_edit_menu_binds(self): self.Bind(wx.EVT_MENU, self.on_menu_undo, self.menu_undo) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_undo_update, self.menu_undo) self.Bind(wx.EVT_MENU, self.on_menu_cut, self.menu_cut) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_cut_update, self.menu_cut) self.Bind(wx.EVT_MENU, self.on_menu_copy, self.menu_copy) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_copy_update, self.menu_copy) self.Bind(wx.EVT_MENU, self.on_menu_paste, self.menu_paste) self.Bind(wx.EVT_UPDATE_UI, self.on_menu_paste_update, self.menu_paste) self.Bind(wx.EVT_MENU, self.on_menu_delete, self.menu_delete) self.Bind( wx.EVT_UPDATE_UI, self.on_menu_delete_update, self.menu_delete) def add_help_menu_binds(self): self.Bind(wx.EVT_MENU, self.on_menu_help, self.menu_help) def on_menu_exit(self, event): self.Close() def on_menu_new(self, event): if self.save_if_modified(): self.new() def on_menu_open(self, event): if self.save_if_modified(): self.open() def on_menu_save(self, event): self.save() def on_menu_saveas(self, event): self.save_as() def on_menu_undo(self, event): self.txt_ctrl.Undo() def on_menu_undo_update(self, event): event.Enable(self.txt_ctrl.CanUndo()) def on_menu_cut(self, event): self.txt_ctrl.Cut() def on_menu_cut_update(self, event): event.Enable(self.txt_ctrl.CanCut()) def on_menu_copy(self, event): self.txt_ctrl.Copy() def on_menu_copy_update(self, event): event.Enable(self.txt_ctrl.CanCopy()) def on_menu_paste(self, event): self.txt_ctrl.Paste() def on_menu_paste_update(self, event): event.Enable(self.txt_ctrl.CanPaste()) def on_menu_delete(self, event): self.txt_ctrl.Remove(*self.txt_ctrl.GetSelection()) def on_menu_delete_update(self, event): event.Enable(bool(self.txt_ctrl.GetStringSelection())) def on_menu_help(self, event): self.open_forum_page() def on_close_evt(self, event): if event.CanVeto(): if not self.save_if_modified(): event.Veto() return self.Destroy() def update_title(self): name = UNTITLED if self.path: name = self.path.name self.SetTitle(f'{name} - Notespad') def save_changes_msg_dialog(self): path = self.path or UNTITLED dlg = wx.MessageDialog( self, (f'Do you want to save changes to {path}?'), 'Notespad', wx.YES_NO | wx.CANCEL | wx.CENTER) dlg.SetYesNoLabels('Save', 'Don\'t Save') return dlg.ShowModal() def save_if_modified(self): saved_or_dont_save = True if self.txt_ctrl.IsModified(): dlg_result = self.save_changes_msg_dialog() if dlg_result == wx.ID_CANCEL: saved_or_dont_save = False elif dlg_result == wx.ID_YES: self.save() if not self.path: saved_or_dont_save = False return saved_or_dont_save def new(self): self.txt_ctrl.Clear() self.path = None self.update_title() def open(self): with wx.FileDialog(self, message='Open', wildcard=WILDCARD, style=wx.FD_OPEN) as dlg: if dlg.ShowModal() == wx.ID_OK: directory, filename = dlg.GetDirectory(), dlg.GetFilename() self.path = Path(directory).joinpath(filename) self.txt_ctrl.LoadFile(str(self.path)) self.update_title() def save(self): if not self.path: self.save_as() else: # self.txt_ctrl.SaveFile(str(self.path)) self.update_title() def save_as(self): with wx.FileDialog(self, message='Save as', wildcard=WILDCARD, style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as dlg: if dlg.ShowModal() == wx.ID_OK: directory, filename = dlg.GetDirectory(), dlg.GetFilename() self.path = Path(directory).joinpath(filename) self.save() def open_forum_page(self): webbrowser.open(HELP_URL, 2) if __name__ == '__main__': wx_app = wx.App(False) frame = Notespad(None) frame.Show() wx_app.MainLoop()