Skip to content

Commit 11c0be5

Browse files
committed
add markdown editor tkinter tutorial
1 parent 1d88bb1 commit 11c0be5

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,5 +226,6 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
226226
- [How to Make a Calculator with Tkinter in Python](https://www.thepythoncode.com/article/make-a-calculator-app-using-tkinter-in-python). ([code](gui-programming/calculator-app))
227227
- [How to Make a Typing Speed Tester with Tkinter in Python](https://www.thepythoncode.com/article/how-to-make-typing-speed-tester-in-python-using-tkinter). ([code](gui-programming/type-speed-tester))
228228
- [How to Make a Planet Simulator with PyGame in Python](https://www.thepythoncode.com/article/make-a-planet-simulator-using-pygame-in-python). ([code](gui-programming/planet-simulator))
229+
- [How to Make a Markdown Editor using Tkinter in Python](https://www.thepythoncode.com/article/markdown-editor-with-tkinter-in-python). ([code](gui-programming/markdown-editor))
229230

230231
For any feedback, please consider pulling requests.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [How to Make a Markdown Editor using Tkinter in Python](https://www.thepythoncode.com/article/markdown-editor-with-tkinter-in-python)
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Imports
2+
from tkinter import *
3+
import ctypes
4+
import re
5+
6+
# Increas Dots Per inch so it looks sharper
7+
ctypes.windll.shcore.SetProcessDpiAwareness(True)
8+
9+
# Setup
10+
root = Tk()
11+
root.title('Markdown Editor')
12+
root.geometry('1000x600')
13+
14+
# Setting the Font globaly
15+
root.option_add('*Font', 'Courier 15')
16+
17+
18+
def changes(event=None):
19+
display['state'] = NORMAL
20+
21+
# Clear the Display Area
22+
display.delete(1.0, END)
23+
24+
# Insert the content of the Edit Area into the Display Area
25+
text = editor.get('1.0', END)
26+
27+
# Save Raw Text for later
28+
textRaw = text
29+
30+
# Remove Unwanted Characters
31+
text = ''.join(text.split('#'))
32+
text = ''.join(text.split('*'))
33+
34+
display.insert(1.0, text)
35+
36+
# Loop through each replacement, unpacking it fully
37+
for pattern, name, fontData, colorData, offset in replacements:
38+
39+
# Get the location indices of the given pattern
40+
locations = search_re(pattern, textRaw, offset)
41+
42+
print(f'{name} at {locations}')
43+
44+
# Add tags where the search_re function found the pattern
45+
for start, end in locations:
46+
display.tag_add(name, start, end)
47+
48+
# Configure the tag to use the specified font and color
49+
# to this every time to delete the previous tags
50+
display.tag_config(name, font=fontData, foreground=colorData)
51+
52+
display['state'] = DISABLED
53+
54+
def search_re(pattern, text, offset):
55+
matches = []
56+
text = text.splitlines()
57+
for i, line in enumerate(text):
58+
for match in re.finditer(pattern, line):
59+
matches.append(
60+
(f"{i + 1}.{match.start()}", f"{i + 1}.{match.end() - offset}")
61+
)
62+
63+
return matches
64+
65+
# Convert an RGB tuple to a HEX string using the % Operator
66+
# 02 means print 2 characters
67+
# x means hexadecimal
68+
def rgbToHex(rgb):
69+
return "#%02x%02x%02x" % rgb
70+
71+
# Style Setup
72+
editorBackground = rgbToHex((40, 40, 40))
73+
editorTextColor = rgbToHex((230, 230, 230))
74+
displayBackground = rgbToHex((60, 60, 60))
75+
displayTextColor = rgbToHex((200, 200, 200))
76+
77+
caretColor = rgbToHex((255, 255, 255))
78+
79+
# Width of the Textareas in characters
80+
width = 10
81+
82+
# Fonts
83+
editorfontName = 'Courier'
84+
displayFontName = 'Calibri'
85+
86+
# Font Sizes
87+
normalSize = 15
88+
h1Size = 40
89+
h2Size = 30
90+
h3Size = 20
91+
92+
# font Colors
93+
h1Color = rgbToHex((240, 240, 240))
94+
h2Color = rgbToHex((200, 200, 200))
95+
h3Color = rgbToHex((160, 160, 160))
96+
97+
# Replacements tell us were to insert tags with the font and colors given
98+
replacements = [
99+
[
100+
'^#[a-zA-Z\s\d\?\!\.]+$',
101+
'Header 1',
102+
f'{displayFontName} {h1Size}',
103+
h1Color,
104+
0
105+
], [
106+
'^##[a-zA-Z\s\d\?\!\.]+$',
107+
'Header 2',
108+
f'{displayFontName} {h2Size}',
109+
h2Color,
110+
0
111+
], [
112+
'^###[a-zA-Z\s\d\?\!\.]+$',
113+
'Header 3',
114+
f'{displayFontName} {h3Size}',
115+
h3Color,
116+
0
117+
], [
118+
'\*.+?\*',
119+
'Bold',
120+
f'{displayFontName} {normalSize} bold',
121+
displayTextColor,
122+
2
123+
],
124+
]
125+
126+
# Making the Editor Area
127+
editor = Text(
128+
root,
129+
height=5,
130+
width=width,
131+
bg=editorBackground,
132+
fg=editorTextColor,
133+
border=30,
134+
relief=FLAT,
135+
insertbackground=caretColor
136+
)
137+
editor.pack(expand=1, fill=BOTH, side=LEFT)
138+
139+
# Bind <KeyReleas> so every change is registered
140+
editor.bind('<KeyRelease>', changes)
141+
editor.focus_set()
142+
143+
# Insert a starting text
144+
editor.insert(INSERT, """#Heading 1
145+
146+
##Heading 2
147+
148+
###Heading 3
149+
150+
This is a *bold* move!
151+
152+
153+
- Markdown Editor -
154+
155+
""")
156+
157+
# Making the Display Area
158+
display = Text(
159+
root,
160+
height=5,
161+
width=width,
162+
bg=displayBackground,
163+
fg=displayTextColor,
164+
border=30,
165+
relief=FLAT,
166+
font=f"{displayFontName} {normalSize}",
167+
)
168+
display.pack(expand=1, fill=BOTH, side=LEFT)
169+
170+
# Disable the Display Area so the user cant write in it
171+
# We will have to toggle it so we can insert text
172+
display['state'] = DISABLED
173+
174+
# Starting the Application
175+
changes()
176+
root.mainloop()

0 commit comments

Comments
 (0)