maroph

text_editor3.py

Dec 9th, 2019
314
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.76 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. # Tested with
  4. # Python 3.8.0 on Windows 10 (mainly)
  5. # Python 3.7.3 on Raspbian 10.2
  6. #
  7. # Known bug on Raspbian with Python 3.7.3
  8. # (works under Windows 10 with Python 3.8.0):
  9. # Start the app, click Help/About and than exit the app.
  10. # After closing the info box the app thinks, there is unsaved text
  11. # in the editor.
  12. # I have the same effect also in some other situations on Raspbian 10.2
  13. # and not on Windows 10
  14. # IMHO: this seems to be a problem in the underlying TK implementation.
  15.  
  16. from guizero import App, Box, Combo, MenuBar, Slider, Text, TextBox
  17. from pathlib import Path
  18.  
  19. app_name = 'Simple Text Editor'
  20. app_version = '3'
  21. app_verdate = '09-DEC-2019'
  22.  
  23. app_version_string = app_name + ' v' + app_version + ' (' + app_verdate + ')'
  24.  
  25. app = App(title=app_name, bg='slategray', width=800, height=600)
  26.  
  27. # remember the last folder in use, default: . - the current folder
  28. folder = '.'
  29. # True: no unsaved text in the editor
  30. text_saved = True
  31.  
  32.  
  33. # get the current folder ins use from the complete file path, stored in file_name_text_box.value
  34. def get_folder():
  35.     name = file_name_text_box.value
  36.     if name is None:
  37.         return '.'
  38.     elif len(name) == 0:
  39.         return '.'
  40.     else:
  41.         return Path(name).parent
  42.  
  43.  
  44. # show some version information
  45. def about_editor():
  46.     app.info('About', app_version_string + "\nA simple Python guizero based text editor")
  47.     return
  48.  
  49.  
  50. # open a file, selected in a file selector box, in the editor and
  51. # store the file name in file_name_text_box.value
  52. def open_file():
  53.     global text_saved
  54.  
  55.     if not text_saved:
  56.         resp = app.yesno('Warning', 'You have unsaved text in the editor - proceed?')
  57.         if not resp:
  58.             return
  59.  
  60.     f = get_folder()
  61.     name = app.select_file('Open file', folder=f, filetypes=[["Text files", "*.txt"], ["Markdown files", "*.md"]], save=False)
  62.     if name is None:
  63.         text_saved = True
  64.         return
  65.     if len(name) == 0:
  66.         text_saved = True
  67.         return
  68.  
  69.     try:
  70.         with open(name, "r") as f:
  71.             editor.value = f.read()
  72.     except Exception as e:
  73.         app.error('Read Error', 'Error in reading file: ' + str(e))
  74.         return
  75.  
  76.     file_name_text_box.value= name
  77.     text_saved = True
  78.  
  79.  
  80. # save the text in the editor the the file name, stored in file_name_text_box.value
  81. def save_file():
  82.     global text_saved
  83.  
  84.     name = file_name_text_box.value
  85.     if name is None:
  86.         save_as_file()
  87.         return
  88.     if len(name) == 0:
  89.         save_as_file()
  90.         return
  91.  
  92.     try:
  93.         with open(name, "w") as f:
  94.             f.write(editor.value)
  95.     except Exception as e:
  96.         app.error('Write Error', 'Error in reading file: ' + str(e))
  97.         return
  98.  
  99.     text_saved = True
  100.  
  101.  
  102. # save the text in the editor into  a file, selected in a file selector box and
  103. # store the name in file_name_text_box.value
  104. def save_as_file():
  105.     global text_saved
  106.  
  107.     f = get_folder()
  108.  
  109.     name = app.select_file('Save file', folder=f, filetypes=[["Text files", "*.txt"], ["Markdown files", "*.md"]], save=True)
  110.     if name is None:
  111.         return
  112.     if len(name) == 0:
  113.         return
  114.  
  115.     try:
  116.         with open(name, "w") as f:
  117.             f.write(editor.value)
  118.     except Exception as e:
  119.         app.error('Write Error', 'Error in reading file: ' + str(e))
  120.         return
  121.  
  122.     file_name_text_box.value = name
  123.     text_saved = True
  124.  
  125.  
  126. # remove all text from the editor and set the file name to '' in file_name_text_box.value
  127. def new_file():
  128.     global text_saved
  129.  
  130.     if not text_saved:
  131.         resp = app.yesno('Warning', 'You have unsaved text in the editor - proceed?')
  132.         if not resp:
  133.             return
  134.  
  135.     file_name_text_box.value = ''
  136.     editor.value = ''
  137.     char_count_text_box.value = '0'
  138.     text_saved = True
  139.  
  140.  
  141. # close the editor app
  142. def exit_app():
  143.     global text_saved
  144.  
  145.     if not text_saved:
  146.         resp = app.yesno('Warning', 'You have unsaved text in the editor - proceed?')
  147.         if not resp:
  148.             return
  149.     app.destroy()
  150.  
  151.  
  152. def change_font():
  153.     editor.font = font.value
  154.  
  155.  
  156. def change_text_color():
  157.     editor.text_color = text_color.value
  158.  
  159.  
  160. def change_text_size():
  161.     editor.text_size = size.value
  162.     editor.resize(1, 1)
  163.     editor.resize("fill", "fill")
  164.  
  165.  
  166. # get number of characters in the editor
  167. # observation: even if editor.value is '' the len(editor.value) is 1
  168. def get_number_of_text_chars():
  169.     chars = len(editor.value)
  170.     if chars > 0:
  171.         return chars -1
  172.     else:
  173.         return 0
  174.  
  175.  
  176. # wil be called by any change in the editor's text area
  177. def count_text_chars():
  178.     global text_saved
  179.     char_count_text_box.value = get_number_of_text_chars()
  180.     text_saved = False
  181.  
  182.  
  183. def toggle_status_line():
  184.     if status_box.visible:
  185.         status_box.visible = False
  186.     else:
  187.         status_box.visible = True
  188.  
  189.  
  190. def toggle_char_count():
  191.     if char_count_box.visible:
  192.         char_count_box.visible = False
  193.     else:
  194.         char_count_box.visible = True
  195.  
  196.  
  197. def toggle_preferences_controls():
  198.     if preferences_controls.visible:
  199.         preferences_controls.visible = False
  200.     else:
  201.         preferences_controls.visible = True
  202.  
  203.  
  204. # same handling as if clicked o 'File/Exit'
  205. app.when_closed = exit_app
  206.  
  207. # create the app's menu bar and the related menu items
  208. menubar = MenuBar(app,
  209.                   # menu bar
  210.                   toplevel=["File", "Options", "Help"],
  211.                   # menu items
  212.                   options=[
  213.                       # File
  214.                       [
  215.                           # items in File
  216.                           ["New", new_file],
  217.                           ["Open...", open_file],
  218.                           ["Save", save_file],
  219.                           ["Save as...", save_as_file],
  220.                           ["Exit", exit_app]
  221.                       ],
  222.                       # Options
  223.                       [
  224.                           # items in Options
  225.                           ["Toggle status line", toggle_status_line],
  226.                           ["Toggle char count", toggle_char_count],
  227.                           ["Toggle preferences", toggle_preferences_controls]
  228.                       ],
  229.                       # Help
  230.                       [
  231.                           # items in Help
  232.                           ["About", about_editor]
  233.                       ]
  234.                   ])
  235.  
  236.  
  237. # create the status line, copntains: file name and character count
  238. status_box = Box(app, width='fill', border=True)
  239. file_name_label = Text(status_box, text='File: ', align="left")
  240. file_name_text_box = TextBox(status_box, text='', width='fill', align="left", enabled=False)
  241. file_name_text_box.bg = 'white'
  242. char_count_box = Box(status_box, width='fill', border=True)
  243. char_count_text_box = TextBox(char_count_box, text='', width='20', align="right", enabled=False)
  244. char_count_label = Text(char_count_box, text='Chars: ', align="right")
  245. char_count_text_box.value = '0'
  246. text_saved = True
  247.  
  248.  
  249. # create the preferences line
  250. preferences_controls = Box(app, align="top", width="fill", border=True)
  251. font = Combo(preferences_controls, options=["Courier", "Times New Roman", "Verdana"], align="left", selected='Courier', command=change_font)
  252. size = Slider(preferences_controls,  align="left", command=change_text_size, start=10, end=18)
  253. size.value = 10
  254. text_color = Combo(preferences_controls, options=['black', 'blue', 'red', 'magenta'], align="left", selected='black', command=change_text_color)
  255.  
  256.  
  257. # create the editor
  258. editor = TextBox(app, multiline=True, height="fill", width="fill", text='', scrollbar=True)
  259. editor.bg = 'white'
  260. editor.font = font.value
  261. editor.text_size = size.value
  262. editor.text_color = text_color.value
  263. editor.update_command(count_text_chars)
  264. editor.focus()
  265.  
  266. app.display()
Advertisement
Add Comment
Please, Sign In to add comment