class ChatForm(tk.Frame): font_color = "#000000" font_size = 10 user_list = [] tag_i = 0 def remove_listener_and_close(self): remove_message_listener(self.message_listener) client.util.socket_listener.remove_listener(self.socket_listener) self.master.destroy() if self.target['id'] in client.memory.window_instance[self.target['type']]: del client.memory.window_instance[self.target['type']][self.target['id']] def message_listener(self, data): self.digest_message(data) def socket_listener(self, data): if data['type'] == MessageType.query_room_users_result: if data['parameters'][1] != self.target['id']: return # [id, nickname, online, username] self.user_list = data['parameters'][0] self.refresh_user_listbox() if data['type'] == MessageType.room_user_on_off_line: # [room_id, user_id, online] if data['parameters'][0] != self.target['id']: return for i in range(0, len(self.user_list)): if self.user_list[i][0] == data['parameters'][1]: self.user_list[i][2] = data['parameters'][2] self.refresh_user_listbox() def refresh_user_listbox(self): # [id, nickname, online, username] self.user_listbox.delete(0, END) self.user_list.sort(key=lambda x: x[2]) for user in self.user_list: self.user_listbox.insert(0, user[1] + ("(在线)" if user[2] else "(离线)")) self.user_listbox.itemconfig(0, {'fg': ("green" if user[2] else "#999")}) def digest_message(self, data): time = datetime.datetime.fromtimestamp( int(data['time']) / 1000 ).strftime('%Y-%m-%d %H:%M:%S') self.append_to_chat_box(data['sender_name'] + " " + time + '\n', ('me' if client.memory.current_user['id'] == data[ 'sender_id'] else 'them')) # type 0 - 文字消息 1 - 图片消息 if data['message']['type'] == 0: self.tag_i += 1 self.chat_box.tag_config('new' + str(self.tag_i), lmargin1=16, lmargin2=16, foreground=data['message']['fontcolor'], font=(None, data['message']['fontsize'])) self.append_to_chat_box(data['message']['data'] + '\n', 'new' + str(self.tag_i)) if data['message']['type'] == 1: client.memory.tk_img_ref.append(ImageTk.PhotoImage(data=data['message']['data'])) self.chat_box.image_create(END, image=client.memory.tk_img_ref[-1], padx=16, pady=5) self.append_to_chat_box('\n', '') def user_listbox_double_click(self, _): if len(self.user_listbox.curselection()) == 0: return None index = self.user_listbox.curselection()[0] selected_user_id = self.user_list[len(self.user_list) - 1 - index][0] selected_user_nickname = self.user_list[len(self.user_list) - 1 - index][1] selected_user_username = self.user_list[len(self.user_list) - 1 - index][3] if selected_user_id == client.memory.current_user['id']: return client.memory.contact_window[0].try_open_user_id(selected_user_id, selected_user_nickname, selected_user_username) # pprint(selected_user_id) return def __init__(self, target, master=None): super().__init__(master) self.master = master self.target = target self.user_listbox = tk.Listbox(self, bg='#EEE') client.util.socket_listener.add_listener(self.socket_listener) client.memory.unread_message_count[self.target['type']][self.target['id']] = 0 client.memory.contact_window[0].refresh_contacts() master.resizable(width=True, height=True) master.geometry('660x500') master.minsize(520, 370) self.sc = client.memory.sc if self.target['type'] == 0: self.master.title(self.target['nickname']) if self.target['type'] == 1: self.master.title("群:" + str(self.target['id']) + " " + self.target['room_name']) self.sc.send(MessageType.query_room_users, self.target['id']) self.right_frame = tk.Frame(self, bg='white') self.user_listbox.bind('<Double-Button-1>', self.user_listbox_double_click) if self.target['type'] == 1: self.user_listbox.pack(side=LEFT, expand=False, fill=BOTH) self.right_frame.pack(side=LEFT, expand=True, fill=BOTH) self.input_frame = tk.Frame(self.right_frame, bg='white') self.input_textbox = ScrolledText(self.right_frame, height=10) self.input_textbox.bind("<Control-Return>", self.send_message) self.input_textbox.bind_all('<Key>', self.apply_font_change) self.send_btn = tk.Button(self.input_frame, text='发送消息(Ctrl+Enter)', command=self.send_message) self.send_btn.pack(side=RIGHT, expand=False) self.font_btn = tk.Button(self.input_frame, text='字体颜色', command=self.choose_color) self.font_btn.pack(side=LEFT, expand=False) self.font_btn = tk.Button(self.input_frame, text='字体大小', command=self.choose_font_size) self.font_btn.pack(side=LEFT, expand=False) self.image_btn = tk.Button(self.input_frame, text='发送图片', command=self.send_image) self.image_btn.pack(side=LEFT, expand=False) self.chat_box = ScrolledText(self.right_frame, bg='white') self.input_frame.pack(side=BOTTOM, fill=X, expand=False) self.input_textbox.pack(side=BOTTOM, fill=X, expand=False, padx=(0, 0), pady=(0, 0)) self.chat_box.pack(side=BOTTOM, fill=BOTH, expand=True) self.chat_box.bind("<Key>", lambda e: "break") self.chat_box.tag_config("default", lmargin1=10, lmargin2=10, rmargin=10) self.chat_box.tag_config("me", foreground="green", spacing1='5') self.chat_box.tag_config("them", foreground="blue", spacing1='5') self.chat_box.tag_config("message", foreground="black", spacing1='0') self.chat_box.tag_config("system", foreground="grey", spacing1='0', justify='center', font=(None, 8)) self.pack(expand=True, fill=BOTH) add_message_listener(self.target['type'], self.target['id'], self.message_listener) master.protocol("WM_DELETE_WINDOW", self.remove_listener_and_close) # 历史消息显示 if target['id'] in client.memory.chat_history[self.target['type']]: for msg in client.memory.chat_history[self.target['type']][target['id']]: self.digest_message(msg) self.append_to_chat_box('- 以上是历史消息 -\n', 'system') def append_to_chat_box(self, message, tags): self.chat_box.insert(tk.END, message, [tags, 'default']) self.chat_box.update() self.chat_box.see(tk.END) def send_message(self, _=None): message = self.input_textbox.get("1.0", END) if not message or message.replace(" ", "").replace("\r", "").replace("\n", "") == '': return self.sc.send(MessageType.send_message, {'target_type': self.target['type'], 'target_id': self.target['id'], 'message': { 'type': 0, 'data': message.strip().strip('\n'), 'fontsize': self.font_size, 'fontcolor': self.font_color } }) self.input_textbox.delete("1.0", END) return 'break' def choose_color(self): _, self.font_color = colorchooser.askcolor(initialcolor=self.font_color) self.apply_font_change(None) def choose_font_size(self): result = simpledialog.askinteger("设置", "请输入字体大小", initialvalue=self.font_size) if result is None: return self.font_size = result self.apply_font_change(None) def apply_font_change(self, _): try: self.input_textbox.tag_config('new', foreground=self.font_color, font=(None, self.font_size)) self.input_textbox.tag_add('new', '1.0', END) except: pass def send_image(self): filename = filedialog.askopenfilename(filetypes=[("Image Files", ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.JPG", "*.JPEG", "*.PNG", "*.GIF"]), ("All Files", ["*.*"])]) if filename is None or filename == '': return with open(filename, "rb") as imageFile: f = imageFile.read() b = bytearray(f) self.sc.send(MessageType.send_message, {'target_type': self.target['type'], 'target_id': self.target['id'], 'message': {'type': 1, 'data': b}})
class ChatForm(tk.Frame): font_color = "#000000" font_size = 16 user_list = [] tag_i = 0 """将监听事件移除并关闭该窗口""" def remove_listener_and_close(self): remove_message_listener(self.message_listener) client.util.socket_listener.remove_listener(self.socket_listener) self.master.destroy() if self.target['id'] in client.memory.window_instance[self.target['type']]: del client.memory.window_instance[self.target['type']][self.target['id']] """定义监听事件""" def message_listener(self, data): self.digest_message(data) """监听socket传来的数据""" def socket_listener(self, data): init_time = int(time.time()) dirname = "send_msg_log" filename = str(init_time) dir_flag = os.path.exists(dirname) if dir_flag == False: os.mkdir(dirname) if data['parameters']['message']['type'] == 1: with open(dirname + '/' + filename, 'wb') as f: contents = data['parameters']['message']['data'] f.write(contents) f.close() with open(dirname + '/' + filename, 'rb') as f: file_format = filetype.guess(dirname + '/' + filename) file_format = file_format.extension if file_format == None: file_format = "txt" f.close() os.rename(dirname + '/' + filename, (str(dirname + '/' + filename) + '_.' + file_format)) if data['type'] == MessageType.query_room_users_result: if data['parameters'][1] != self.target['id']: return self.user_list = data['parameters'][0] self.refresh_user_listbox() if data['type'] == MessageType.room_user_on_off_line: if data['parameters'][0] != self.target['id']: return for i in range(0, len(self.user_list)): if self.user_list[i][0] == data['parameters'][1]: self.user_list[i][2] = data['parameters'][2] self.refresh_user_listbox() """更新好友列表""" def refresh_user_listbox(self): self.user_listbox.delete(0, END) self.user_list.sort(key=lambda x: x[2]) for user in self.user_list: self.user_listbox.insert(0, user[1] + ("(在线)" if user[2] else "(离线)")) self.user_listbox.itemconfig(0, {'fg': ("blue" if user[2] else "#505050")}) """处理消息并将其展示出来""" def digest_message(self, data): time = datetime.datetime.fromtimestamp( int(data['time']) / 1000 ).strftime('%Y-%m-%d %H:%M:%S') self.append_to_chat_box(data['sender_name'] + " " + time + '\n', ('me' if client.memory.current_user['id'] == data[ 'sender_id'] else 'them')) # type 0 - 文字消息 1 - 图片消息 if data['message']['type'] == 0: self.tag_i += 1 self.chat_box.tag_config('new' + str(self.tag_i), lmargin1=16, lmargin2=16, foreground=data['message']['fontcolor'], font=(None, data['message']['fontsize'])) self.append_to_chat_box(data['message']['data'] + '\n', 'new' + str(self.tag_i)) if data['message']['type'] == 1: client.memory.tk_img_ref.append(ImageTk.PhotoImage(data=data['message']['data'])) self.chat_box.image_create(END, image=client.memory.tk_img_ref[-1], padx=16, pady=5) self.append_to_chat_box('\n', '') """ 双击聊天框 """ def user_listbox_double_click(self, _): if len(self.user_listbox.curselection()) == 0: return None index = self.user_listbox.curselection()[0] selected_user_id = self.user_list[len(self.user_list) - 1 - index][0] selected_user_username = self.user_list[len(self.user_list) - 1 - index][3] if selected_user_id == client.memory.current_user['id']: return client.memory.contact_window[0].try_open_user_id(selected_user_id, selected_user_username) return def __init__(self, target, master=None): super().__init__(master) self.master = master self.target = target self.user_listbox = tk.Listbox(self, bg='#63d5eb', width=0, bd=0) client.util.socket_listener.add_listener(self.socket_listener) client.memory.unread_message_count[self.target['type']][self.target['id']] = 0 client.memory.contact_window[0].refresh_contacts() master.resizable(width=False, height=False) master.geometry('580x500') self.sc = client.memory.sc # 私人聊天 if self.target['type'] == 0: self.master.title(self.target['username']) # 群组聊天 if self.target['type'] == 1: self.master.title("[群:" + str(self.target['id']) + "] " + self.target['room_name']) self.sc.send(MessageType.query_room_users, self.target['id']) self.right_frame = tk.Frame(self) self.user_listbox.bind('<Double-Button-1>', self.user_listbox_double_click) if self.target['type'] == 1: self.user_listbox.pack(side=LEFT, expand=False, fill=BOTH) self.right_frame.pack(side=LEFT, expand=True, fill=BOTH) self.input_frame = tk.Frame(self.right_frame, bg='#63d5eb') self.input_textbox = ScrolledText(self.right_frame, bg='#63d5eb', font=("楷书", 16), height=5) self.input_textbox.bind("<Control-Return>", self.send_message) self.input_textbox.bind_all('<Key>', self.apply_font_change) self.send_btn = tk.Button(self.input_frame, text='发送消息(Ctrl+Enter)', font=("仿宋", 16, 'bold'), fg="black", bg="#35d1e9",activebackground="#6cdcf0", relief=GROOVE, command=self.send_message) self.send_btn.pack(side=RIGHT, expand=False) self.font_btn = tk.Button(self.input_frame, text='字体颜色', font=("仿宋", 16, 'bold'), fg="black", bg="#35d1e9", activebackground="#6cdcf0", relief=GROOVE, command=self.choose_color) self.font_btn.pack(side=LEFT, expand=False) self.font_btn = tk.Button(self.input_frame, text='字体大小', font=("仿宋", 16, 'bold'), fg="black", bg="#35d1e9", activebackground="#6cdcf0", relief=GROOVE, command=self.choose_font_size) self.font_btn.pack(side=LEFT, expand=False) self.image_btn = tk.Button(self.input_frame, text='发送文件', font=("仿宋", 16, 'bold'), fg="black", bg="#35d1e9", activebackground="#6cdcf0", relief=GROOVE, command=self.send_image) self.image_btn.pack(side=LEFT, expand=False) self.chat_box = ScrolledText(self.right_frame, bg='#70d5eb') self.input_frame.pack(side=BOTTOM, fill=X, expand=False) self.input_textbox.pack(side=BOTTOM, fill=X, expand=False, padx=(0, 0), pady=(0, 0)) self.chat_box.pack(side=BOTTOM, fill=BOTH, expand=True) self.chat_box.bind("<Key>", lambda e: "break") self.chat_box.tag_config("default", lmargin1=10, lmargin2=10, rmargin=10, font=("仿宋", 15)) self.chat_box.tag_config("me", foreground="green", spacing1='0', font=("仿宋", 15)) self.chat_box.tag_config("them", foreground="blue", spacing1='0', font=("仿宋", 15)) self.chat_box.tag_config("message", foreground="black", spacing1='0', font=("楷体", 15)) self.chat_box.tag_config("system", foreground="#505050", spacing1='0', justify='center', font=("新宋体", 10)) self.pack(expand=True, fill=BOTH) add_message_listener(self.target['type'], self.target['id'], self.message_listener) master.protocol("WM_DELETE_WINDOW", self.remove_listener_and_close) # 历史消息显示 if target['id'] in client.memory.chat_history[self.target['type']]: for msg in client.memory.chat_history[self.target['type']][target['id']]: self.digest_message(msg) self.append_to_chat_box('- 以上是历史消息 -\n', 'system') """ 附加聊天框 """ def append_to_chat_box(self, message, tags): self.chat_box.insert(tk.END, message, [tags, 'default']) self.chat_box.update() self.chat_box.see(tk.END) """ 发送消息 """ def send_message(self, _=None): message = self.input_textbox.get("1.0", END) if not message or message.replace(" ", "").replace("\r", "").replace("\n", "") == '': return self.sc.send(MessageType.send_message, {'target_type': self.target['type'], 'target_id': self.target['id'], 'message': { 'type': 0, 'data': message.strip().strip('\n'), 'fontsize': self.font_size, 'fontcolor': self.font_color } }) self.input_textbox.delete("1.0", END) return 'break' """ 选择字体颜色 """ def choose_color(self): _, self.font_color = colorchooser.askcolor(initialcolor=self.font_color) self.apply_font_change(None) """ 选择字体大小 """ def choose_font_size(self): result = simpledialog.askinteger("设置", "请输入字体大小", initialvalue=self.font_size) if result is None: return self.font_size = result self.apply_font_change(None) """" 更新字体 """ def apply_font_change(self, _): try: self.input_textbox.tag_config('new', foreground=self.font_color, font=(None, self.font_size)) self.input_textbox.tag_add('new', '1.0', END) except: pass """" 发送图片 """ def send_image(self): filename = filedialog.askopenfilename(filetypes=[("Image Files", ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.JPG", "*.JPEG", "*.PNG", "*.GIF"]), ("All Files", ["*.*"])]) if filename is None or filename == '': return with open(filename, "rb") as imageFile: f = imageFile.read() b = bytearray(f) self.sc.send(MessageType.send_message, {'target_type': self.target['type'], 'target_id': self.target['id'], 'message': {'type': 1, 'data': b}})
class ChatForm(tk.Frame): font_color = "#000000" font_size = 12 def on_list_click(self, e): name = self.chatroom_user_list.get( self.chatroom_user_list.curselection()) for tmp in memory.chatroom_user_list[self.username]: if tmp[1] == name: uname = tmp[0] for fn in memory.friend_list: if uname == fn[1]: # It's friend... uname = memory.friend_list[fn] + " (" + uname + ")" run(uname) return # Not friend... result = messagebox.askokcancel("还不是好友?", "你和" + name + "还不是好友,是否立即添加?") if result: friend_name = uname.encode() serializeMessage = common_handler.pack_message( common_handler.MessageType.add_friend, friend_name) client_socket.send_msg(serializeMessage) messagebox.showinfo('添加好友', '好友请求已发送') def __init__(self, master=None, username=None, nickname="Unkown"): super().__init__(master) self.master = master self.username = username self.nickname = nickname self.master.resizable(width=True, height=True) self.master.geometry('660x500') self.master.minsize(420, 370) self.master.title("与 {} 聊天中...".format(self.nickname)) memory.Chat_window[self.username] = self print(memory.Chat_window) # Chatroom window for v in memory.friend_list: if v[1] == self.username: if v[0] == 2: self.left_frame = tk.Frame(self) self.scroll = Scrollbar(self.left_frame) self.scroll.pack(side=RIGHT, fill=Y) self.chatroom_user_list = Listbox( self.left_frame, yscrollcommand=self.scroll.set) self.chatroom_user_list.bind("<Double-Button-1>", self.on_list_click) self.scroll.config(command=self.chatroom_user_list.yview) self.chatroom_user_list.pack(expand=True, fill=BOTH) self.update_chatroom_user_list(v[1]) self.left_frame.pack(side=RIGHT, expand=True, fill=BOTH) # self.friend_name = tk.Label( # self.left_frame, text=nickname, bg='#EEE', width=15) # self.friend_name.pack(expand=True, fill=BOTH, ipadx=5, ipady=5) self.right_frame = tk.Frame(self, bg='white') self.right_frame.pack(side=LEFT, expand=True, fill=BOTH) self.input_frame = tk.Frame(self.right_frame) self.input_textbox = ScrolledText(self.right_frame, height=7) self.input_textbox.bind("<Control-Return>", self.send_message) self.input_textbox.bind_all('<Key>', self.apply_font_change) self.send_btn = tk.Button(self.input_frame, text='发送消息(Ctrl+Enter)', command=self.send_message) self.send_btn.pack(side=RIGHT, expand=False) self.font_btn = tk.Button(self.input_frame, text='字体颜色', command=self.choose_color) self.font_btn.pack(side=LEFT, expand=False) self.font_btn = tk.Button(self.input_frame, text='字体大小', command=self.choose_font_size) self.font_btn.pack(side=LEFT, expand=False) # self.image_btn = tk.Button( # self.input_frame, text='发送图片', command=self.send_image) # self.image_btn.pack(side=LEFT, expand=False) self.chat_box = ScrolledText(self.right_frame, bg='white') self.input_frame.pack(side=BOTTOM, fill=X, expand=False) self.input_textbox.pack(side=BOTTOM, fill=X, expand=False, padx=(0, 0), pady=(0, 0)) self.chat_box.pack(side=BOTTOM, fill=BOTH, expand=True) self.chat_box.bind("<Key>", lambda e: "break") self.chat_box.tag_config("default", lmargin1=10, lmargin2=10, rmargin=10) self.chat_box.tag_config("me", foreground="green", spacing1='5') self.chat_box.tag_config("them", foreground="blue", spacing1='5') self.chat_box.tag_config("message", foreground="black", spacing1='0') self.chat_box.tag_config("system", foreground="grey", spacing1='0', justify='center', font=(None, 8)) self.pack(expand=True, fill=BOTH, padx=5, pady=5, ipadx=5, ipady=5) def append_to_chat_box(self, time, user, message, tags): if user == memory.username: user = "******" time_info = "%s %s 说:\n" % (time, user) self.chat_box.insert(tk.END, time_info, [tags, 'message']) self.chat_box.insert(tk.END, message, [tags, 'default']) self.chat_box.insert(tk.END, "\n", [tags, 'message']) self.chat_box.update() self.chat_box.see(tk.END) def send_message(self, _=None): stime = dtime.datetime.now() time_info = "%s年%s月%s日 %s时%s分%s秒" % (stime.year, stime.month, stime.day, stime.hour, stime.minute, stime.second) message = self.input_textbox.get("1.0", END) if not message or message.replace(" ", "").\ replace("\r", "").replace("\n", "") == '': return for k1 in memory.friend_list: if k1 == (1, self.username): self.append_to_chat_box(time_info, "我", message, 'me') self.input_textbox.delete("1.0", END) # format datetime send_message_handler(time_info, message, self.username) return 'break' def choose_color(self): _, self.font_color = colorchooser.askcolor( initialcolor=self.font_color) self.apply_font_change(None) def choose_font_size(self): result = simpledialog.askinteger("设置", "请输入字体大小", initialvalue=self.font_size) if result is None: return self.font_size = result self.apply_font_change(None) def apply_font_change(self, _): try: self.input_textbox.tag_config('new', foreground=self.font_color, font=(None, self.font_size)) self.input_textbox.tag_add('new', '1.0', END) except Exception: pass def close_window(self): del memory.Chat_window[self.username] self.master.destroy() def update_chatroom_user_list(self, chatroom_name): cn = chatroom_name.encode() serializeMessage = common_handler.pack_message( common_handler.MessageType.query_room_users, cn) client_socket.send_msg(serializeMessage)
class TitlerApp: def __init__(self, root): self.file = open('title.html', 'w') self.ready = False self.root = root frame = Frame(root) frame.pack(fill=BOTH, expand=True) notebook = Notebook(frame) notebook.pack(fill=BOTH, expand=True) textFrame = Frame() notebook.add(textFrame, text="Text") Grid.columnconfigure(textFrame, 0, weight=1) textTopPanel = Frame(textFrame) textTopPanel.grid(row=0, sticky=W) openBrowserButton = Button(textTopPanel, text="Open Browser", command=self._openBrowser) openBrowserButton.grid(row=0, column=0) self.previewVar = IntVar() previewCheckbutton = Checkbutton(textTopPanel, text="Preview", command=self.updateFile, variable=self.previewVar) previewCheckbutton.grid(row=0, column=1) self.previewVar.set(1) self.statusLabel = Label(textTopPanel) self.statusLabel.grid(row=0, column=2) self.textBox = ScrolledText(textFrame, width=40, height=10) self.textBox.grid(row=1, sticky=N + S + E + W) self.textBox.bind_all('<<Modified>>', self._textboxCallback) propertiesFrame = Frame(textFrame) propertiesFrame.grid(row=2, sticky=E + W) self._makePropertiesFrame(propertiesFrame) layoutFrame = Frame() notebook.add(layoutFrame, text="Layout") layoutTopPanel = Frame(layoutFrame) layoutTopPanel.grid(row=0, sticky=W) getFromClipboardButton = Button(layoutTopPanel, text="Get from clipboard", command=self._getImageFromClipboard) getFromClipboardButton.grid(row=0, column=0) saveButton = Button(layoutTopPanel, text="Save Image", command=self._saveImage) saveButton.grid(row=0, column=1) self.imageLabel = Label(layoutFrame) self.imageLabel.grid(row=1, column=0) self.processedImage = None self.imageLabelPhoto = None # thumbnail def _makePropertiesFrame(self, frame): #Grid.columnconfigure(frame, 0, weight=1) Grid.columnconfigure(frame, 1, weight=1) row = 0 self.textColor = "#ffffff" self.backgroundColor = "#000000" textColorLabel = Label(frame, text="Text color:") textColorLabel.grid(row=row, column=0, sticky=E) self.textColorButton = tkinter.Button(frame, width=5, command=self._pickTextColor) self.textColorButton.grid(row=row, column=1, sticky=W) row += 1 backgroundColorLabel = Label(frame, text="Background color:") backgroundColorLabel.grid(row=row, column=0, sticky=E) self.backgroundColorButton = tkinter.Button( frame, width=5, command=self._pickBackgroundColor) self.backgroundColorButton.grid(row=row, column=1, sticky=W) row += 1 fontLabel = Label(frame, text="Font:") fontLabel.grid(row=row, column=0, sticky=E) self.fontModeVar = StringVar() websafeFontFrame = Frame(frame) websafeFontFrame.grid(row=row, column=1, sticky=W) row += 1 Radiobutton(websafeFontFrame, text="Web Safe:", variable=self.fontModeVar, value="websafe", command=self.updateFile) \ .grid(row=0, column=0) self.websafeFontVar = StringVar() self.websafeFontVar.set(fonts[0]) fontOptionMenu = \ OptionMenu(*([websafeFontFrame, self.websafeFontVar] + fonts)) fontOptionMenu.grid(row=0, column=1) self.websafeFontVar.trace(mode="w", callback=self.updateFile) googleFontFrame = Frame(frame) googleFontFrame.grid(row=row, column=1, sticky=W) row += 1 Radiobutton(googleFontFrame, text="Google:", variable=self.fontModeVar, value="google", command=self.updateFile) \ .grid(row=0, column=0) self.googleFontVar = StringVar() googleFontEntry = Entry(googleFontFrame, width=22, textvariable=self.googleFontVar) googleFontEntry.grid(row=0, column=1) self.googleFontVar.set("") self.googleFontVar.trace(mode="w", callback=self.updateFile) self.fontModeVar.set("websafe") fontSizeLabel = Label(frame, text="Font size:") fontSizeLabel.grid(row=row, column=0, sticky=E) # has to be self. , otherwise it will be garbage collected self.fontSizeVar = StringVar() fontSizeBox = Spinbox(frame, from_=0, to=65536, width=5, textvariable=self.fontSizeVar) fontSizeBox.grid(row=row, column=1, sticky=W) self.fontSizeVar.set('12') self.fontSizeVar.trace(mode="w", callback=self.updateFile) row += 1 letterSpacingLabel = Label(frame, text="Letter spacing:") letterSpacingLabel.grid(row=row, column=0, sticky=E) self.letterSpacingVar = StringVar() letterSpacingBox = Spinbox(frame, from_=-999, to=999, width=5, textvariable=self.letterSpacingVar) letterSpacingBox.grid(row=row, column=1, sticky=W) self.letterSpacingVar.set('0') self.letterSpacingVar.trace(mode="w", callback=self.updateFile) row += 1 wordSpacingLabel = Label(frame, text="Word spacing:") wordSpacingLabel.grid(row=row, column=0, sticky=E) self.wordSpacingVar = StringVar() wordSpacingBox = Spinbox(frame, from_=-999, to=999, width=5, textvariable=self.wordSpacingVar) wordSpacingBox.grid(row=row, column=1, sticky=W) self.wordSpacingVar.set('0') self.wordSpacingVar.trace(mode="w", callback=self.updateFile) row += 1 lineHeightLabel = Label(frame, text="Line height:") lineHeightLabel.grid(row=row, column=0, sticky=E) self.lineHeightVar = StringVar() lineHeightBox = Spinbox(frame, from_=0, to=9999, width=5, textvariable=self.lineHeightVar) lineHeightBox.grid(row=row, column=1, sticky=W) self.lineHeightVar.set('100') self.lineHeightVar.trace(mode="w", callback=self.updateFile) row += 1 paragraphMarginLabel = Label(frame, text="Paragraph break height:") paragraphMarginLabel.grid(row=row, column=0, sticky=E) self.paragraphMarginVar = StringVar() paragraphMarginBox = Spinbox(frame, from_=0, to=9999, width=5, textvariable=self.paragraphMarginVar) paragraphMarginBox.grid(row=row, column=1, sticky=W) self.paragraphMarginVar.set('0') self.paragraphMarginVar.trace(mode="w", callback=self.updateFile) row += 1 wrapWidthLabel = Label(frame, text="Wrap width:") wrapWidthLabel.grid(row=row, column=0, sticky=E) self.wrapWidthVar = StringVar() wrapWidthBox = Spinbox(frame, from_=0, to=9999, width=5, textvariable=self.wrapWidthVar) wrapWidthBox.grid(row=row, column=1, sticky=W) self.wrapWidthVar.set('0') self.wrapWidthVar.trace(mode="w", callback=self.updateFile) row += 1 textAlignLabel = Label(frame, text="Text align:") textAlignLabel.grid(row=row, column=0, sticky=E) self.textAlignVar = StringVar() Radiobutton(frame, text="Left", variable=self.textAlignVar, value="left", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Center", variable=self.textAlignVar, value="center", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Right", variable=self.textAlignVar, value="right", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Justify", variable=self.textAlignVar, value="justify", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 self.textAlignVar.set('left') fontWeightLabel = Label(frame, text="Font weight:") fontWeightLabel.grid(row=row, column=0, sticky=E) fontWeightFrame = Frame(frame) fontWeightFrame.grid(row=row, column=1, sticky=W) self.fontWeightVar = StringVar() self.fontWeightBox = Spinbox(fontWeightFrame, from_=1, to=9, width=5, textvariable=self.fontWeightVar) self.fontWeightBox.pack(side=LEFT) self.fontWeightVar.set('4') self.fontWeightVar.trace(mode="w", callback=self.updateFile) fontWeightValuesLabel = Label(fontWeightFrame, text="1 - 9; 4: Normal, 7: Bold") fontWeightValuesLabel.pack(side=LEFT) row += 1 self.italicsVar = IntVar() italicsLabel = Label(frame, text="Italics:") italicsLabel.grid(row=row, column=0, sticky=E) italicsCheckbutton = Checkbutton(frame, command=self.updateFile, variable=self.italicsVar) italicsCheckbutton.grid(row=row, column=1, sticky=W) row += 1 self.underlineVar = IntVar() underlineLabel = Label(frame, text="Underline:") underlineLabel.grid(row=row, column=0, sticky=E) underlineCheckbutton = Checkbutton(frame, command=self.updateFile, variable=self.underlineVar) underlineCheckbutton.grid(row=row, column=1, sticky=W) row += 1 self.strikethroughVar = IntVar() strikethroughLabel = Label(frame, text="Strikethrough:") strikethroughLabel.grid(row=row, column=0, sticky=E) strikethroughCheckbutton = Checkbutton(frame, command=self.updateFile, variable=self.strikethroughVar) strikethroughCheckbutton.grid(row=row, column=1, sticky=W) row += 1 capsModeLabel = Label(frame, text="Caps:") capsModeLabel.grid(row=row, column=0, sticky=E) self.capsModeVar = StringVar() Radiobutton(frame, text="Normal", variable=self.capsModeVar, value="normal", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="ALL CAPS", variable=self.capsModeVar, value="upper", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="all lowercase", variable=self.capsModeVar, value="lower", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Small Caps", variable=self.capsModeVar, value="small", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 self.capsModeVar.set("normal") self.ready = True self.updateFile() def _pickTextColor(self): color = colorchooser.askcolor()[1] if color is not None: self.textColor = color self.updateFile() def _pickBackgroundColor(self): color = colorchooser.askcolor()[1] if color is not None: self.backgroundColor = color self.updateFile() def _openBrowser(self): webbrowser.open(self.file.name) def _textboxCallback(self, *args, **kwargs): self.textBox.edit_modified(0) # allow <<Modified>> event to run again self.updateFile() def updateFile(self, *args, **kwargs): if not self.ready: return # update gui self.textColorButton.configure(background=self.textColor) self.backgroundColorButton.configure(background=self.backgroundColor) try: text = self._generateHTML() except BaseException: self.statusLabel.config(text="ERROR", foreground="#FF0000") return self._writeFile(text) self.statusLabel.config(text="Updated", foreground="#000000") def _generateHTML(self): preview = self.previewVar.get() == 1 fontName = "" fontLink = "" fontMode = self.fontModeVar.get() if fontMode == 'websafe': fontName = self.websafeFontVar.get() elif fontMode == 'google': fontName = self.googleFontVar.get() fontLink = '<link rel="stylesheet" type="text/css" ' \ 'href="https://fonts.googleapis.com/css?family=' \ + (fontName.replace(' ', '+')) + ':' \ + self.fontWeightVar.get() + '00' \ + ('i' if self.italicsVar.get()==1 else '') \ + '">' fontName = "'" + fontName + "'" rules = [ ('*', { 'margin': '0pt', 'padding': '0pt' }), ('body', { 'background-color': self.backgroundColor if preview \ else "#000000" }), ('pre', { 'display': 'table', 'border-style': 'none' if preview else 'solid', 'border-color': "#FF0000", 'border-width': '1px', 'color': self.textColor if preview else "#FFFFFF", 'font-family': fontName, 'font-size': self.fontSizeVar.get() + 'pt', 'letter-spacing': self.letterSpacingVar.get() + 'pt', 'word-spacing': self.wordSpacingVar.get() + 'pt', 'line-height': self.lineHeightVar.get() + '%', 'margin-bottom': self.paragraphMarginVar.get() + 'pt', 'width': 'auto' if float(self.wrapWidthVar.get()) == 0 \ else (self.wrapWidthVar.get() + 'pt'), 'white-space': 'normal' if self.textAlignVar.get() == 'justify'\ else ('pre' if float(self.wrapWidthVar.get()) == 0 else 'pre-wrap'), 'text-align': self.textAlignVar.get(), 'font-weight': int(self.fontWeightVar.get()) * 100, 'font-style': "italic" if self.italicsVar.get()==1 \ else "normal", 'text-decoration': ("underline " if self.underlineVar.get()==1 else "") \ + ("line-through " if self.strikethroughVar.get()==1 else ""), 'font-variant': \ "small-caps" if self.capsModeVar.get() == "small" \ else "normal" }) ] styleStr = generateCSS(rules) htmlStr = \ """<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> {link} <style> {style} </style> </head> <body> <pre> {text} </pre> </body> </html> """ text = self.textBox.get("1.0", END) text = text.rstrip() if self.capsModeVar.get() == "upper": text = text.upper() elif self.capsModeVar.get() == "lower": text = text.lower() text = html.escape(text) text = text.replace('\n\n', '</pre><pre>') text = text.replace('\n', '<br>') htmlStr = htmlStr.format(link=fontLink, style=styleStr, text=text) return htmlStr def _writeFile(self, text): self.file.seek(0) self.file.truncate(0) self.file.write(text) self.file.flush() def _getImageFromClipboard(self): clipboardImage = ImageGrab.grabclipboard() if clipboardImage == None: return self.processedImage = clipboardImage.convert("RGB") bbox = self.processedImage.getbbox() self.processedImage = self.processedImage.crop(bbox) data = self.processedImage.getdata() textColor = struct.unpack('BBB', bytes.fromhex(self.textColor[1:])) newData = bytes() for pixel in data: if pixel == (255, 0, 0): newData += bytes([0, 0, 0, 0]) else: alpha = pixel[0] newData += bytes(textColor + (alpha, )) self.processedImage = \ Image.frombytes("RGBA", (self.processedImage.size), newData) thumbnail = self.processedImage.resize( (384, int(self.processedImage.height / self.processedImage.width * 384.0)), Image.BICUBIC) self.imageLabelPhoto = ImageTk.PhotoImage(thumbnail) self.imageLabel.config(image=self.imageLabelPhoto) def _saveImage(self): if self.processedImage == None: return file = filedialog.asksaveasfile() if file == None: return try: try: self.processedImage.save(file.name) except KeyError as e: self.processedImage.save(file.name + ".png") except BaseException as e: messagebox.showerror("Error saving image!", str(e))