|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
代码如下(我等级太低了,不能发图片):
- from tkinter import *
- from tkinter import scrolledtext, filedialog, messagebox
- import re
- import tempfile
- import webbrowser
- import os
- import xml.etree.ElementTree as ET
- class HTMLCompiler:
- def __init__(self, root):
- self.root = root
- self.root.title("HTML 编译器 - 未命名")
- self.root.configure(bg='black')
- self.current_file = None
- self.last_error = None
-
- # 创建工具栏
- self.toolbar = Frame(root, bg='#333')
-
- self.new_btn = Button(self.toolbar, text="新建", command=self.new_file, bg='#333', fg='white')
- self.open_btn = Button(self.toolbar, text="打开", command=self.open_file, bg='#333', fg='white')
- self.save_btn = Button(self.toolbar, text="保存", command=self.save_file, bg='#333', fg='white')
- self.run_btn = Button(self.toolbar, text="运行", command=self.run_html, bg='#333', fg='white')
- self.help_btn = Button(self.toolbar, text='帮助', command=self.help_file, bg='#333', fg='white')
-
- self.new_btn.pack(side=LEFT, padx=2, pady=2)
- self.open_btn.pack(side=LEFT, padx=2, pady=2)
- self.save_btn.pack(side=LEFT, padx=2, pady=2)
- self.run_btn.pack(side=LEFT, padx=2, pady=2)
- self.help_btn.pack(side=LEFT, padx=2, pady=2)
-
- self.toolbar.pack(fill=X)
-
- # 创建文本编辑器
- self.text_area = scrolledtext.ScrolledText(
- root, wrap=WORD, bg='black', fg='white',
- insertbackground='white', font=('Consolas', 12)
- )
- self.text_area.pack(fill=BOTH, expand=True)
-
- # 绑定事件
- self.text_area.bind('<KeyRelease>', self.on_key_release)
- self.text_area.bind('<Tab>', self.handle_tab)
- self.text_area.bind('<Return>', self.handle_return)
-
- # 绑定快捷键
- self.root.bind('<Control-n>', lambda event: self.new_file())
- self.root.bind('<Control-o>', lambda event: self.open_file())
- self.root.bind('<Control-s>', lambda event: self.save_file())
- self.root.bind('<Control-r>', lambda event: self.run_html())
-
- # 语法高亮颜色配置
- self.tag_colors = {
- 'tag': '#569CD6',
- 'attribute': '#9CDCFE',
- 'value': '#CE9178',
- 'comment': '#6A9955',
- 'doctype': '#569CD6',
- 'string': '#CE9178',
- 'symbol': '#D4D4D4'
- }
-
- # 配置标签样式
- for tag, color in self.tag_colors.items():
- self.text_area.tag_config(tag, foreground=color)
-
- # 状态栏
- self.status_bar = Frame(root, bg='black')
- self.charn = Label(self.status_bar, text='字数:0', fg='white', bg='black')
- self.place = Label(self.status_bar, text='行:0;列:0', fg='white', bg='black')
- self.html_bool = Button(self.status_bar, text='✓', bg='black', fg='green', command=self.print_error)
-
- self.charn.pack(side=LEFT, padx=5)
- self.place.pack(side=LEFT, padx=5)
- self.html_bool.pack(side=LEFT, padx=5)
- self.status_bar.pack(fill=X, side=BOTTOM)
-
- # 初始内容
- self.text_area.insert(1.0, '''<!DOCTYPE html>
- <html>
- <head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta charset="UTF-8">
- </head>
- <body>
- <!--文档的内容......-->
- </body>
- </html>''')
-
- # 初始更新
- self.highlight()
- self.update_status()
- self.auto_update()
- def auto_update(self):
- self.update_status()
- self.root.after(100, self.auto_update)
-
- def update_status(self):
- self.len_char()
- self.label_place()
- self.test(self.text_area.get(1.0, END))
-
- def new_file(self, event=None):
- self.text_area.delete('1.0', END)
- self.current_file = None
- self.root.title("HTML 编译器 - 未命名")
-
- def open_file(self, event=None):
- file_path = filedialog.askopenfilename(
- filetypes=[("HTML 文件", "*.html"), ("所有文件", "*.*")]
- )
- if file_path:
- try:
- with open(file_path, 'r', encoding='utf-8') as file:
- content = file.read()
- self.text_area.delete('1.0', END)
- self.text_area.insert('1.0', content)
- self.current_file = file_path
- self.root.title(f"HTML 编译器 - {os.path.basename(file_path)}")
- self.highlight()
- except Exception as e:
- messagebox.showerror("错误", f"无法打开文件:\n{str(e)}")
-
- def save_file(self, event=None):
- if self.current_file:
- try:
- with open(self.current_file, 'w', encoding='utf-8') as file:
- file.write(self.text_area.get('1.0', END))
- messagebox.showinfo("保存", "文件保存成功!")
- except Exception as e:
- messagebox.showerror("错误", f"无法保存文件:\n{str(e)}")
- else:
- self.save_as_file()
-
- def save_as_file(self):
- file_path = filedialog.asksaveasfilename(
- defaultextension=".html",
- filetypes=[("HTML 文件", "*.html"), ("所有文件", "*.*")]
- )
- if file_path:
- try:
- with open(file_path, 'w', encoding='utf-8') as file:
- file.write(self.text_area.get('1.0', END))
- self.current_file = file_path
- self.root.title(f"HTML 编译器 - {os.path.basename(file_path)}")
- messagebox.showinfo("保存", "文件保存成功!")
- except Exception as e:
- messagebox.showerror("错误", f"无法保存文件:\n{str(e)}")
-
- def run_html(self, event=None):
- html_code = self.text_area.get("1.0", END)
-
- if not html_code.strip():
- messagebox.showwarning("警告", "没有内容可运行!")
- return
-
- try:
- # 使用临时目录
- temp_dir = tempfile.mkdtemp()
- temp_path = os.path.join(temp_dir, 'preview.html')
-
- with open(temp_path, 'w', encoding='utf-8') as f:
- f.write(html_code)
- # 尝试多种浏览器
- browsers = ['google-chrome', 'chrome', 'msedge', 'firefox']
- opened = False
- for browser in browsers:
- try:
- webb = webbrowser.get(browser)
- webb.open('file://' + os.path.abspath(temp_path))
- opened = True
- break
- except webbrowser.Error:
- continue
-
- if not opened:
- webbrowser.open('file://' + os.path.abspath(temp_path))
-
- except Exception as e:
- messagebox.showerror("错误", f"无法运行HTML:\n{str(e)}")
- def help_file(self):
- messagebox.showinfo('提示','''快捷键:
- Ctrl+N 新建文件
- Ctrl+O 打开文件
- Ctrl+S 保存文件
- Ctrl+R 运行HTML''')
-
- def on_key_release(self, event=None):
- self.highlight()
-
- def handle_tab(self, event):
- current_pos = self.text_area.index(INSERT)
- line, col = map(int, current_pos.split('.'))
-
- space_count = 4 - (col % 4)
- self.text_area.insert(INSERT, ' ' * space_count)
- return 'break'
-
- def handle_return(self, event):
- current_pos = self.text_area.index(INSERT)
- line, col = map(int, current_pos.split('.'))
- line_text = self.text_area.get(f'{line}.0', f'{line}.end')
-
- indent = 0
- while indent < len(line_text) and line_text[indent] == ' ':
- indent += 1
-
- self.text_area.insert(INSERT, '\n' + ' ' * indent)
-
- if line_text.strip().startswith('<') and not line_text.strip().startswith('</'):
- match = re.match(r'^\s*<([a-zA-Z]+)[^>]*>', line_text)
- if match and not line_text.strip().endswith('/>'):
- tag = match.group(1)
- self.text_area.insert(INSERT, f'\n{" " * indent}</{tag}>')
- self.text_area.mark_set(INSERT, f'{line+1}.{indent+1}')
-
- return 'break'
-
- def highlight(self):
- for tag in self.tag_colors.keys():
- self.text_area.tag_remove(tag, '1.0', END)
-
- text = self.text_area.get('1.0', END)
-
- # 高亮注释
- self.highlight_pattern(r'<!--.*?-->', 'comment')
-
- # 高亮DOCTYPE
- self.highlight_pattern(r'<!DOCTYPE.*?>', 'doctype')
-
- # 高亮标签
- self.highlight_pattern(r'<\/?[a-zA-Z]+', 'tag')
- self.highlight_pattern(r'<\/[a-zA-Z]+>', 'tag')
-
- # 高亮属性
- self.highlight_pattern(r'\s[a-zA-Z-]+=', 'attribute')
-
- # 高亮属性值
- self.highlight_pattern(r'"[^"]*"', 'value')
- self.highlight_pattern(r"'[^']*'", 'value')
-
- # 高亮符号
- self.highlight_pattern(r'[<>\/=]', 'symbol')
-
- def highlight_pattern(self, pattern, tag):
- start = '1.0'
- end = END
-
- self.text_area.mark_set('matchStart', start)
- self.text_area.mark_set('matchEnd', start)
-
- count = IntVar()
- while True:
- index = self.text_area.search(
- pattern, 'matchEnd', end,
- count=count, regexp=True
- )
- if index == '': break
-
- self.text_area.mark_set('matchStart', index)
- self.text_area.mark_set('matchEnd', f'{index}+{count.get()}c')
-
- self.text_area.tag_add(tag, 'matchStart', 'matchEnd')
-
- def len_char(self, event=None):
- self.char = len(self.text_area.get(1.0, END)) - 1
- self.charn.config(text=f'字数: {self.char}')
-
- def label_place(self):
- self.cursor_pos = self.text_area.index(INSERT)
- self.line, self.column = self.cursor_pos.split('.')
- self.place.config(text=f"行: {self.line}, 列: {self.column}")
- def test(self, code):
- try:
- # 包装成根节点,避免「文档多个根元素」报错
- wrapped_code = f"<root>{code}</root>"
- ET.fromstring(wrapped_code)
- self.html_bool.config(text='✓', fg='green')
- self.last_error = None
- except ET.ParseError as e:
- self.last_error = f"HTML 语法错误(需符合 XML 规范):\n{str(e)}"
- self.html_bool.config(text='✗',fg='red')
- def print_error(self):
- if self.last_error:
- messagebox.showerror('错误', self.last_error)
- else:
- messagebox.showinfo('提示', 'HTML 代码合法(符合 XML 标准)')
-
-
- if __name__ == '__main__':
- root = Tk()
- root.geometry('800x600')
- app = HTMLCompiler(root)
- root.mainloop()
复制代码
|
|