Reputation: 649
I'm currently working on an HTML editor application with Python tkinter. When you create a new project or open an existing file, a text widget is displayed on the screen, along with a Run
button to run your HTML code. When you type any HTML start tag, the script will immediately add an end tag to that element (autocomplete). I'm using a function called get_stringvar
that is bound by any key release. That function is in charge of the autocomplete. When I type my first start tag, the script autocompletes the end tag. But when I type my second start tag, the end tag isn't being autocompleted. Can someone help me fix that? Some of my code:
import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename
from tkinter import messagebox
import webbrowser
import os
window = tk.Tk()
window.title("HTML Editor")
window.configure(bg="grey")
window.state("zoomed")
title = tk.Label(window, text="HTML Editor", font=("Arial Rounded MT Bold", 40, "underline"), bg="grey")
title.place(x=400, y=20)
def get_stringvar(event):
content = text_box.get("1.0", tk.END)
keys = ["Return", "Up", "Down", "Left", "Right"]
if event.keysym in keys:
return
line = content.splitlines()[-1]
if "/" not in line and line != "<!DOCTYPE html>":
if ("<" in line and ">" in line) and line.index(">") + 1 == len(line):
index = line.index("<")
index2 = line.index(">") + 1
new_line = "<" + "/" + line[index + 1:index2 - 1] + ">"
text_box.insert(tk.END, new_line)
line2 = content.splitlines().index(line) + 1
text_box.mark_set("insert", "%d.%d" % (line2, index2))
create = tk.Button(window, text="Create a new file", width=17, height=3, font=("Arial Rounded MT Bold", 20),
command=save_file)
create.place(x=420, y=200)
open_e = tk.Button(window, text="Open an existing file", width=17, height=3, font=("Arial Rounded MT Bold", 20),
command=open_file)
open_e.place(x=420, y=350)
window.protocol("WM_DELETE_WINDOW", on_closing)
frame = tk.Frame(window, bd=2, relief="raised")
text_box = tk.Text(window, font=("Courier New", 10), fg="black")
text_box.bind("<KeyRelease>", get_stringvar)
scroll_bar = tk.Scrollbar(window, command=text_box.yview)
run_b = tk.Button(frame, text="Run", width=6, height=2, bg="white", command=run_code)
text_box.configure(yscrollcommand=scroll_bar.set)
window.mainloop()
Updated code (Thank you so much, @TheLizzard):
import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename
from tkinter import messagebox
import webbrowser
import os
window = tk.Tk()
window.title("HTML Editor")
window.configure(bg="grey")
window.state("zoomed")
title = tk.Label(window, text="HTML Editor", font=("Arial Rounded MT Bold", 40, "underline"), bg="grey")
title.place(x=400, y=20)
def get_stringvar(event):
line = text_box.get("insert linestart", "insert")
if (line[-1] == ">") and ("<" in line):
new_line = "</" + line[line.rindex("<") + 1:-1] + ">"
text_box.insert("insert", new_line)
text_box.mark_set("insert", f"insert-{len(new_line)}c")
return "break"
create = tk.Button(window, text="Create a new file", width=17, height=3, font=("Arial Rounded MT Bold", 20),
command=save_file)
create.place(x=420, y=200)
open_e = tk.Button(window, text="Open an existing file", width=17, height=3, font=("Arial Rounded MT Bold", 20),
command=open_file)
open_e.place(x=420, y=350)
window.protocol("WM_DELETE_WINDOW", on_closing)
frame = tk.Frame(window, bd=2, relief="raised")
text_box = tk.Text(window, font=("Courier New", 10), fg="black")
text_box.bind("<Tab>", get_stringvar)
scroll_bar = tk.Scrollbar(window, command=text_box.yview)
run_b = tk.Button(frame, text="Run", width=6, height=2, bg="white", command=run_code)
text_box.configure(yscrollcommand=scroll_bar.set)
window.mainloop()
Upvotes: 0
Views: 147
Reputation: 7680
Try this:
import tkinter as tk
def tab_pressed(event):
line = text_box.get("insert linestart", "insert")
if (line[-1:] == ">") and ("<" in line):
new_line = "</" + line[line.rindex("<")+1:-1] + ">"
text_box.insert("insert", new_line)
text_box.mark_set("insert", f"insert-{len(new_line)}c")
# Stop the tab from being added
return "break"
# Remove these 2 lines if you like tabs over spaces
text_box.insert("insert", " "*4)
return "break"
window = tk.Tk()
text_box = tk.Text(window)
text_box.bind("<Tab>", tab_pressed)
text_box.pack(side="left", fill="both", expand=True)
scroll_bar = tk.Scrollbar(window, command=text_box.yview)
scroll_bar.pack(side="left", fill="y")
text_box.configure(yscrollcommand=scroll_bar.set)
window.mainloop()
Instead of binding to "<KeyPress>"
or "<KeyRelease>"
, it will me more user friendly if you bind to "<Tab>"
. Also your code only works if it's the user is writing on the last line. Instead of using "end"
, you should use "insert"
. Also please look at this it will help you a lot. Also my code uses line.rindex("<")
to get the index of the right most "<"
in the line
.
The code above autocompletes the html tag only if the user presses "<Tab>"
. To test it just type in <aaa>
then press Tab
(works only if the cursor is after the >
).
Upvotes: 1