class GuiConsole(Frame): def __init__(self, master=None, cnf={}, **kw): super(GuiConsole, self).__init__(master, cnf, **kw) self.pack(fill=BOTH, expand=YES) self.console = ScrolledText(self, font=('Source Code Pro', 12, 'normal')) self.console.pack(side=TOP, fill=BOTH, expand=YES, padx=5, pady=5) self.console.focus() self.console.mark_set(INSERT, '1.0') def clear(self): self.console.delete('1.0', END) def write(self, text): text = '{}'.format(text) self.console.insert(INSERT, text) self.console.mark_set(INSERT, INSERT+'+{}c'.format(len(text))) def writeline(self, text): self.write('{}\n'.format(text)) def writelines(self, lines): for line in lines: self.writeline(line) def read(self): pass
class TextEditor(): # see PyEdit for more def __init__(self, parent=None): # TODO: 1226 why This can generate independent window ? #frm=Toplevel(Frame.__init__(self, parent)) frm=Toplevel() # TODO : assign title based on cmdline tag frm.title('New Text') # TODO , how to make button and Text in a better Layout format ? # grid() param to learn Button(frm, text='Save', command=self.onSave).grid(row=0,column=0) Button(frm, text='Cut', command=self.onCut).grid(row=0,column=1) Button(frm, text='Paste', command=self.onPaste).grid(row=0,column=2) Button(frm, text='Find', command=self.onFind).grid(row=0,column=3) self.text = ScrolledText(frm) self.text.grid(row=1,columnspan=4) #Button(self, text='Save', command=self.onSave).grid() #Button(self, text='Cut', command=self.onCut).grid() #Button(self, text='Paste', command=self.onPaste).grid() #Button(self, text='Find', command=self.onFind).grid() #self.text = ScrolledText(self) def gettext(self): # returns a string return self.text.get('1.0', END+'-1c') # first through last def onSave(self): filename = asksaveasfilename() #print(filename) if filename: alltext = self.gettext() # first through last open(filename, 'w').write(alltext) # store text in file def onCut(self): text = self.text.get(SEL_FIRST, SEL_LAST) # error if no select self.text.delete(SEL_FIRST, SEL_LAST) # should wrap in try self.text.clipboard_clear() self.text.clipboard_append(text) def onPaste(self): # add clipboard text try: text = self.text.selection_get(selection='CLIPBOARD') self.text.insert(INSERT, text) except TclError: pass # not to be pasted def onFind(self): target = askstring('SimpleEditor', 'Search String?') if target: where = self.text.search(target, INSERT, END) # from insert cursor if where: # returns an index print(where) pastit = where + ('+%dc' % len(target)) # index past target #self.text.tag_remove(SEL, '1.0', END) # remove selection self.text.tag_add(SEL, where, pastit) # select found target self.text.mark_set(INSERT, pastit) # set insert mark self.text.see(INSERT) # scroll display self.text.focus() # select text widget
class ConsoleUi: """Poll messages from a logging queue and display them in a scrolled text widget""" def __init__(self, frame): self.frame = frame self.input_start_idx = tk.END # Create a ScrolledText wdiget self.scrolled_text = ScrolledText(frame, state='disabled', height=12) self.scrolled_text.pack(expand=True, fill=tk.BOTH) self.scrolled_text.configure(font='TkFixedFont') self.scrolled_text.tag_config('INFO', foreground='black') self.scrolled_text.tag_config('DEBUG', foreground='gray') self.scrolled_text.tag_config('WARNING', foreground='dark orange') self.scrolled_text.tag_config('ERROR', foreground='red') self.scrolled_text.tag_config('CRITICAL', foreground='red', underline=1) self.scrolled_text.bind('<Key>', self.key_press) # Create a logging handler using a queue self.log_queue = queue.Queue() self.queue_handler = QueueHandler(self.log_queue) formatter = logging.Formatter('%(asctime)s:\t%(message)s', datefmt='%H:%M:%S') self.queue_handler.setFormatter(formatter) logger.addHandler(self.queue_handler) # Start polling messages from the queue self.frame.after(100, self.poll_log_queue) def display(self, record): msg = record.getMessage() self.scrolled_text.configure(state='normal') self.scrolled_text.insert(tk.END, msg + '\n', record.levelname) # self.scrolled_text.configure(state='disabled') # Autoscroll to the bottom self.scrolled_text.yview(tk.END) self.scrolled_text.mark_set('input_start', 'end-1c') self.scrolled_text.mark_gravity('input_start', tk.LEFT) def poll_log_queue(self): while True: try: record = self.log_queue.get(block=False) except queue.Empty: break else: self.display(record) # Check every 100ms if there is a new message in the queue to display self.frame.after(100, self.poll_log_queue) def key_press(self, event): """Function used to send any inputs to the input_queue when the return key is pressed""" if event.char == '\r': user_input = self.scrolled_text.get('input_start', 'end-1c').strip() input_queue.put(user_input) self.scrolled_text.mark_set('input_start', 'end-1c')
class SummaryFrame(Observer, FrameBase): def _init_frame(self): # ROW 0 self.title = tk.Label(self, text='Summary', font=self.root_frame.font_title) self.title.grid(column=0, row=0, columnspan=2, sticky='w', padx=4, pady=4) # ROW 1 self.receipt = ScrolledText(self) self.receipt.grid(column=0, row=1, columnspan=6, sticky='nsew', padx=2, pady=2) self.receipt.bind("<FocusIn>", self._select_all) self.receipt.bind("<Control-a>", self._select_all) self.assign_subject(OrderController().last_order) # ROW 2 self.clipboard_button = tk.Button(self, text='Copy to clipboard', command=self._copy_to_clipboard) self.clipboard_button.grid(column=0, row=2, sticky='e', padx=2, pady=2) self.save_button = tk.Button(self, text='Save receipt', command=self._save_receipt) self.save_button.grid(column=1, row=2, sticky='e', padx=2, pady=2) self.next_button = tk.Button(self, text='Finish', command=self.goto_home) self.next_button.grid(column=5, row=2, sticky='e', padx=2, pady=2) self.columnconfigure(2, weight=1) # self.columnconfigure(4, minsize=30) self.rowconfigure(1, weight=1) self.configure(padx=2, pady=2) def _select_all(self, event): self.receipt.tag_add('sel', '1.0', 'end') self.receipt.mark_set('insert', '1.0') self.receipt.see('insert') return 'break' def _copy_to_clipboard(self): self.root_win.clipboard_clear() self.root_win.clipboard_append(self.subject.get_receipt()) return 'break' def _save_receipt(self): filename = filedialog.asksaveasfilename( parent=self, title='Select where to save the receipt', filetypes=[('Plaintext file', '*.txt')], ) if filename: self.subject.save_receipt(filename) def update_content(self): receipt = self.subject.get_receipt() # self.receipt.insert('1.0', 'LMAO\nhehehehheeheh\nbruuuuuuuuuuuuuu\nkek') self.receipt['state'] = 'normal' self.receipt.delete('1.0', 'end') self.receipt.insert('1.0', receipt) self.receipt['state'] = 'disabled' # self.receipt.insert('1.1', 'WUTBRUH') def goto_home(self): pass def _on_frame_destroy(self): pass
class PyNote: def __init__(self,root): self.root = root self.root.title('Untitled - PyNote') self.root.configure( bg='lightgray') self.root.geometry('950x600') self.root.protocol("WM_DELETE_WINDOW", self.callback) self.root.minsize(width=700, height=400) # important stuffs ... self.font_style = ('arial',14) self.filename = None self.file_saved = True self.index=0 # widgets ,........ self.textarea = ScrolledText(self.root,font=self.font_style,undo=True, wrap = WORD) #self.textarea.bindtags(('Text','post-class-bindings', '.', 'all')) self.textarea.pack(fill=BOTH,expand=True) self.shortcut_binding() self.status = StringVar() self.pos = StringVar() self.status.set('PyNote - ({})'.format('Untitled File')) # important stuffs ... font_style = ('arial', 13) self.label = Label(self.root, textvariable=self.status, fg='black', bg='lightgray', anchor=SW, font=font_style) self.label.pack(side=LEFT,fill=BOTH) # cursor postion label... self.cursor_pos_lbl = Label(self.root, textvariable=self.pos, fg='black', bg='lightgray', anchor=NW, font=font_style) self.cursor_pos_lbl.pack(side=RIGHT) # code for popup menu bar .... # creating menu-bar ... self.m = Menu(root, tearoff=0) self.m.add_command(label="Refresh", command=self.refresh) self.m.add_command(label = "Select All",command=self.select_all) self.m.add_command(label="Cut", command=lambda: self.textarea.event_generate("<<Cut>>")) self.m.add_command(label="Copy", command=lambda: self.textarea.event_generate("<<Copy>>")) self.m.add_command(label = "Paste", command=lambda: self.textarea.event_generate("<<Paste>>")) self.m.add_command(label="Delete", command=lambda: self.textarea.delete(SEL_FIRST, SEL_LAST)) self.m.add_command(label="Add Date/Time", command=self.add_time_date) # Calling functions and other class methods or creating objects ...... self.menubar = Menubar(self) # function definations ................. def set_title(self,name= None): if name: self.root.title(name + " - PyNote") else: self.root.title('Untitled - PyNote') def new_file(self, event = None): self.textarea.delete(1.0, END) # call the save command if any text is written on text area .. self.filename = None self.set_title() self.update_status('PyNote - ({})'.format('Untitled File')) def open_file(self, *args): self.filename = filedialog.askopenfilename( defaultextension = ".txt", filetypes = [("All Files" , "*.*"), ("Text Files" , "*.txt"), ("Python Scripts" , "*.py"), ('HTML Docs.' , "*.html"), ("CSS Docs.","*.css")]) if self.filename: self.textarea.delete(1.0,END) with open(self.filename , "r") as f : self.textarea.insert(1.0,f.read()) self.update_status('File is Opened / ' + self.filename) self.set_title(self.filename) def save_file(self, *args): if self.filename: try: textarea_data = self.textarea.get(1.0,END) with open(self.filename, 'w') as f: f.write(textarea_data) self.update_status('File is Saved Again ') self.file_saved = True except Exception as e: messagebox.showerror('PyNote -Says ','Error Occurs '+ str(e)) else: self.save_as_file() def save_as_file(self, *args): try: new_file = filedialog.asksaveasfilename(initialfile = 'Untitled.txt', defaultextension=".txt", filetypes=[("All Files", "*.*"), ("Text Files", "*.txt"), ("Python Scripts", "*.py"), ('HTML Docs.', "*.html"), ("CSS Docs.", "*.css")] ) textarea_data = self.textarea.get(1.0,END) with open(new_file , 'w') as f: f.write(textarea_data) self.filename = new_file self.set_title(self.filename) self.file_saved = True self.update_status('File is Saved As '+ self.filename) except Exception as e: messagebox.showerror('PyNote -Says ','Error Occurs '+ str(e)) def about_us(self): messagebox.showinfo('About - Us',''' PyNote is a Text Editor which is looks like a Notepad \n PyNote is Build as a Demo Project for those Who are \n interested in building Awesome GUI Projects using Tkinter\n _________________________________________________________\n PyNote Developer : Yogesh Singh \n Build For : Dynamic Coding \n''') def about_pynote(self): messagebox.showinfo('About - PyNote',''' Current Version : 0.0 \n ''') def shortcut_binding(self): self.textarea.bind('<Control-n>',self.new_file) self.textarea.bind('<Control-Key-o>',self.open_file) self.textarea.bind('<Control-s>',self.save_file) self.textarea.bind('<Control-S>',self.save_as_file) self.textarea.bind('<Control-q>',self.close_App) self.textarea.bind('<Key>', self.text_area_cursor) #self.textarea.bind('<KeyPress>', self.cursor_pos) self.root.bind("<Button-3>", self.do_popup) def do_popup(self, event): try: self.m.tk_popup(event.x_root, event.y_root) finally: self.m.grab_release() def find_word_window(self): top = Toplevel(self.root) top.geometry('400x130') top.title('PyNote - Find Text ') top.resizable(0,0) # important stuffs ........... find_var = StringVar() self.total_var =StringVar() # --------------------------find window widgets ---------------------- self.find_entry = ttk.Entry(top,width=20,font=('times',12), textvariable = find_var) self.find_entry.focus_set() self.find_entry.bind('<Return>',self.find) self.find_entry.place(x=10,y=25) find_btn = Button(top,text='Find',width=10,bd=2,relief=RIDGE,command=self.find) find_btn.place(x=200,y=25) clear_btn = Button(top, text='Clear', width=10, bd=2, relief=RIDGE,command=lambda:find_var.set('')) clear_btn.place(x=300, y=25) self.total_world_count = Label(top,font=('arial',13,'bold')) self.total_world_count.place(x=20,y=80) top.mainloop() def find(self, *args): # remove tag 'found' from index 1 to END self.textarea.tag_remove('found', '1.0', END) # returns to widget currently in focus s = self.find_entry.get() if (s): idx = '1.0' self.count=0 while 1: # searches for desried string from index 1 idx = self.textarea.search(s, idx, nocase=1, stopindex=END) self.count +=1 if not idx: break # last index sum of current index and # length of text lastidx = '% s+% dc' % (idx, len(s)) # overwrite 'Found' at idx self.textarea.tag_add('found', idx, lastidx) idx = lastidx # mark located string as red self.textarea.tag_config('found', foreground='green', background='yellow') #self.textarea.focus_set() self.total_world_count['text'] = 'Total Word Count is : ' + str(self.count -1 ) def refresh(self): self.textarea.tag_delete("found") def find_replace_window(self): top = Toplevel(self.root) top.geometry('400x130') top.title('PyNote - Find Text ') top.focus_force() top.resizable(0, 0) # important stuffs ........... find_var = StringVar() replace_var = StringVar() # --------------------------find replace window widgets ---------------------- self.find_entry = ttk.Entry(top, width=20, font=('times', 12), textvariable=find_var) self.find_entry.focus_set() self.find_entry.bind('<Return>', self.find) self.find_entry.place(x=10, y=25) self.replace_entry = ttk.Entry(top, width=20, font=('times', 12), textvariable=replace_var) #self.replace_entry.focus_set() self.replace_entry.bind('<Return>', self.find_replace) self.replace_entry.place(x=10, y=60) find_btn = Button(top, text='Find', width=10, bd=2, relief=RIDGE, command=self.find) find_btn.place(x=200, y=25) replace_btn = Button(top, text='Replace', width=10, bd=2, relief=RIDGE, command=self.find_replace) replace_btn.place(x=200, y=60) clear_btn = Button(top, text='Clear All', width=10,height=3, bd=2, relief=RIDGE, command=lambda: [find_var.set(''),replace_var.set('')]) clear_btn.place(x=300, y=26) self.total_world_count = Label(top, text='',font=('arial', 13, 'bold')) self.total_world_count.place(x=20, y=100) top.mainloop() def find_replace(self, *args): find = self.find_entry.get() replace = self.replace_entry.get() if(find and replace): idx = '1.0' while 1: # searches for desired string from index 1 idx = self.textarea.search(find, idx, nocase=1, stopindex=END) print(idx) if not idx: break # last index sum of current index and # length of text lastidx = '% s+% dc' % (idx, len(find)) self.textarea.delete(idx, lastidx) self.textarea.insert(idx, replace) lastidx = '% s+% dc' % (idx, len(replace)) # overwrite 'Found' at idx self.textarea.tag_add('found', idx, lastidx) idx = lastidx self.total_world_count['text'] = '" {} " is replaced with " {} "'.format(find,replace) self.replace_entry.focus_set() def close_App(self, *args): print(self.textarea.get(1.0,END)) if self.textarea.get(1.0,END) != '' and self.file_saved == True: if messagebox.askyesno('PyNote Says','Do you really want to exit'): self.root.quit() else: val = messagebox.askyesnocancel('PyNote - Says', 'Save File Before Exit App. ') if val: self.save_file() self.root.destroy() elif val == False: self.root.destroy() def text_area_cursor(self, *args): #print('inside function ') self.file_saved = False if self.filename: self.update_status('PyNote - Currently Working on : ({})'.format(self.filename)) else: self.update_status('Untitled File') pos = self.textarea.index(INSERT) line , column = pos.split('.') column = int(column) + 1 #print('Current line is : ',line) #print('Current Column is : ', column) self.pos.set('Line : {} Column : {}'.format(line,column)) def cursor_pos(self, *args): pos = self.textarea.index(INSERT) line, column = pos.split('.') column = int(column) + 1 self.pos.set('Line : {} Column : {}'.format(line, column)) def update_status(self,data=''): self.status.set('PyNote - ({})'.format(data)) def select_font(self): font= askfont() # font is "" if the user has cancelled if font: # spaces in the family name need to be escaped font['family'] = font['family'].replace(' ', '\ ') font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font if font['underline']: font_str += ' underline' if font['overstrike']: font_str += ' overstrike' self.font_style = font_str self.textarea.configure(font=self.font_style) def add_time(self): now = datetime.datetime.now() now = now.strftime(' Time: %I:%M:%S:%p ') self.textarea.insert(END, now) def add_date(self): now = datetime.datetime.now() now = now.strftime(' %Y-%m-%d ') self.textarea.insert(END, now) def add_time_date(self): now = datetime.datetime.now() now = now.strftime(' Date: %Y-%m-%d Time: %I:%M:%S:%p ') self.textarea.insert(END,now) # Select all the text in textbox def select_all(self, *args): self.textarea.tag_add(SEL, "1.0", END) self.textarea.mark_set(INSERT, "1.0") self.textarea.see(INSERT) def callback(self): if(self.file_saved) and (self.textarea.get(1.0,END)) != '': if messagebox.askokcancel("Quit", "Do you really wish to quit?"): self.root.destroy() else: val = messagebox.askyesnocancel('PyNote - Says','Save File Before Exit App. ') if val: self.save_file() elif val== False: self.root.destroy()
class Application(Frame): def __init__(self, master=None): self.warning = '【封号防止】\n' + \ '请尽量在自己的日常刷魂时间使用\n' + \ '请不要长时间连续使用,任何使你看起来明显违背人类正常作息规律的行为,很容易会被鬼使黑盯上\n' + \ '当你离开了常在城市,请不要使用,这会被认为是找了代练\n' + \ '点到为止,贪婪是万恶之源\n' self.label = r'阴阳师-网易游戏' self.hwnd = None self.shell = None if not self.info_get(): self.scaling = 1 self.clear_time = 35 self.fight = None self.timing_value = None # 控件初始化 Frame.__init__(self, master) self.pack() self.frame1 = Frame(self) self.frame1.pack() self.frame2 = Frame(self) self.frame2.pack() self.label_scaling = Label(self.frame1) self.var_scaling = StringVar(self.frame1) self.entry_scaling = Entry(self.frame1) self.button_scaling_explain = Button(self.frame1) self.label_mode = Label(self.frame1) self.var_mode = StringVar(self.frame1) self.listbox_mode = ttk.Combobox(self.frame1) self.button_mode_explain = Button(self.frame1) self.label_member = Label(self.frame1) self.var_member = IntVar() self.radio1 = Radiobutton(self.frame1) self.radio2 = Radiobutton(self.frame1) self.label_clear_time = Label(self.frame1) self.var_clear_time = StringVar(self.frame1) self.entry_clear_time = Entry(self.frame1) self.button_clear_time_explain = Button(self.frame1) self.label_offer = Label(self.frame1) self.var_offer_mode = StringVar(self.frame1) self.listbox_offer_mode = ttk.Combobox(self.frame1) self.label_timing_mode = Label(self.frame1) self.var_timing_mode = StringVar(self.frame1) self.listbox_timing_mode = ttk.Combobox(self.frame1) self.var_timing_value = StringVar(self.frame1) self.entry_timing_value = Entry(self.frame1) self.entry_test = Entry(self.frame1) self.test_btn = Button(self.frame1) self.start_ctn = Button(self.frame2) self.stop_ctn = Button(self.frame2) self.info_box = ScrolledText(self.frame2) self.queue = Queue(maxsize=1) self._running = 1 self.create_main() @staticmethod def check_hwnd(label): # 获取游戏窗口句柄 hwnd = win32gui.FindWindow(None, label) if hwnd: return hwnd else: print('游戏没有运行') return False @staticmethod def init_window_place(root, x, y): screenwidth = root.winfo_screenwidth() screenheight = root.winfo_screenheight() root.resizable(False, False) root.update_idletasks() root.deiconify() width = root.winfo_width() height = root.winfo_height() size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / x, (screenheight - height) / y) root.geometry(size) def jump_window(self): # 跳转到游戏窗口 win32gui.SetForegroundWindow(self.hwnd) win32gui.PostMessage(self.hwnd, win32con.WM_SYSCOMMAND, win32con.SC_RESTORE, 0) def get_scaling(self): var = self.entry_scaling.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='缩放倍率只能为数字') return False if var > 2: messagebox.showinfo(title='提示', message='缩放倍率过高') return False return var def get_clear_time(self): var = self.var_clear_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='平均通关时间只能为数字') return False if var <= 5: messagebox.showinfo(title='提示', message='平均通关时间不能小于5') return False return var def get_timimg(self): if self.listbox_timing_mode.get() == '无': return True var = self.var_timing_value.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='预定结束只能填入数字') return False if var < 1: messagebox.showinfo(title='提示', message='数字过小,无法执行') return False return var @staticmethod def time_format(second): try: second = int(second) except ValueError: return second if second > 60: m, s = divmod(second, 60) h, m = divmod(m, 60) return ':'.join( (str(h).zfill(2), str(m).zfill(2), str(s).zfill(2))) else: return second def info_get(self): try: with shelve.open('mysetting.db') as data: setting_data = data['setting'] self.scaling = setting_data['scaling'] self.clear_time = setting_data['clear_time'] except KeyError: return False return True def info_save(self): with shelve.open('mysetting.db') as data: setting_data = dict() setting_data['scaling'] = self.var_scaling.get() setting_data['clear_time'] = self.var_clear_time.get() data['setting'] = setting_data def turn_radio_on(self, *args): type(args) var = self.listbox_mode.get() if var == '司机': self.radio1.configure(state='active') self.radio2.configure(state='active') else: self.radio1.configure(state='disabled') self.radio2.configure(state='disabled') def turn_entry_on(self, *args): type(args) var = self.listbox_timing_mode.get() if var == '定时[分钟]' or var == '场数': self.entry_timing_value.configure(state='normal') else: self.entry_timing_value.configure(state='disabled') def fight_start(self): self.scaling = self.get_scaling() if not self.scaling: return False self.clear_time = self.get_clear_time() if not self.clear_time: return False self.timing_value = self.get_timimg() if not self.timing_value: return False self.info_save() # 获取游戏窗口句柄 self.hwnd = self.check_hwnd(self.label) if not self.hwnd: messagebox.showinfo(title='提示', message='游戏没有运行') return False self.shell = win32com.client.Dispatch("WScript.Shell") # self.shell.SendKeys('%') self.jump_window() time.sleep(0.5) self.fight = GameController(self.hwnd, self.scaling) thread1 = threading.Thread(target=self.fight_thread, name='fight_thread') thread2 = threading.Thread(target=self.offer_thread, name='offer_thread') # 将线程状态、队列内容置为1 self._running = 1 if self.queue.empty(): self.queue.put(1) else: self.queue.get() self.queue.put(1) self.start_ctn.configure(state='disabled') self.stop_ctn.configure(state='active') thread1.start() thread2.start() def fight_thread(self): self.jump_window() if not self.queue.empty(): self.queue.get() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(self.warning) + '\n', 'RED') self.info_box.tag_config('RED', foreground='red') var = '[%s]挂机开始' % datetime.datetime.now().strftime("%H:%M:%S") self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) rounds = 0 total_time = 0 beginning_timg = time.clock() while True: if self._running == 1: fight_start_time = time.clock() self.fight.form_team_phase(self.listbox_mode.get(), self.var_member.get(), self.queue) self.fight.wait_fight_finish_phase(self.clear_time, self.queue) self.jump_window() self.fight.settle_phase(self.queue) if self._running == 1: fight_end_time = time.clock() fight_time = fight_end_time - fight_start_time # time.sleep(0.5) rounds = rounds + 1 total_time = total_time + fight_time elapsed_time = fight_end_time - beginning_timg var = '第 %s 场 耗时:%s 共计:%s' % \ (rounds, self.time_format(fight_time), self.time_format(elapsed_time)) self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) # 检查是否到达预定结束场数或时间 if (self.listbox_timing_mode.get() == '场数' and rounds >= self.timing_value) or \ (self.listbox_timing_mode.get() == '定时[分钟]' and elapsed_time / 60 >= self.timing_value): win32gui.PostMessage(self.hwnd, win32con.WM_CLOSE, 0, 0) self.fight_stop() var = '已到达预定目标,游戏窗口已关闭。下线15分钟后buff自动关闭' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) time.sleep(random.uniform(1, 2)) elif self._running == 0: return def fight_stop(self): # 将线程状态、队列内容置为0 self._running = 0 self.queue.put(0) self.start_ctn.configure(state='active') self.stop_ctn.configure(state='disabled') var = '[%s]挂机结束。记得关御魂buff' % datetime.datetime.now().strftime( "%H:%M:%S") self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) def offer_thread(self): while True: if self._running == 1: self.fight.check_offer(self.listbox_offer_mode.get(), self.queue) elif self._running == 0: return @staticmethod def resource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) return os.path.join(base_path, relative_path) def what_is_scaling_window(self): what_is_scaling = Toplevel(self) what_is_scaling.title('缩放倍率 - 不能自动获取,技术就是这么菜,不服憋着_(:3」∠)_') frame1 = Frame(what_is_scaling) frame1.pack() frame2 = Frame(what_is_scaling) frame2.pack() title = Label(frame1) title['text'] = '\n【 缩放倍率 】' title.pack() desc1 = Message(frame1) desc1['width'] = 600 desc1['text'] = '\n缩放倍率是指Windows系统在不改变分辨率的情况下,将窗口和图标放大以达到更加舒适的显示效果的功能\n' + \ '\n在某些分辨率下,Windows会自动设置一个超过100%的倍率。请确定自己系统当前的缩放倍率设置,并填入缩放倍率一栏中\n' + \ '\n不正确的缩放倍率设置,会导致坐标计算不准\n' + \ '\n若设置的缩放倍率是100%,则填入1,若是125%,则填1.25,依次类推\n' desc1.pack() label_win10 = Label(frame2) label_win10['text'] = 'Windows 10' label_win10.grid(row=0, column=0) label_win7 = Label(frame2) label_win7['text'] = 'Windows 7' label_win7.grid(row=0, column=1) ipath = self.resource_path('image/win10.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img_win10 = Label(frame2, image=render) img_win10.image = render img_win10.grid(row=1, column=0) ipath = self.resource_path('image/win7.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img_win7 = Label(frame2, image=render) img_win7.image = render img_win7.grid(row=1, column=1) self.init_window_place(what_is_scaling, 1.3, 3) def when_click_start_window(self): when_click_start = Toplevel(self) when_click_start.title('模式说明') var = self.listbox_mode.get() if var == '单刷': title = Label(when_click_start) title['text'] = '\n【 单刷模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n请把游戏调整至如图所示界面,再点START\n' desc['width'] = 300 desc.pack() ipath = self.resource_path('image/single.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '乘客': title = Label(when_click_start) title['text'] = '\n【 乘客模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议接受了司机的默认邀请,再点START\n' + \ '因为我不会在战斗里帮你点开始...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = self.resource_path('image/passenger_accept.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '司机': title = Label(when_click_start) title['text'] = '\n【 司机模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议对乘客发出默认邀请,回到组队界面再点START\n' + \ '因为自动发出邀请这个功能没写...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = self.resource_path('image/driver_invite.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img1 = Label(when_click_start, image=render) img1.image = render img1.pack() ipath = self.resource_path('image/driver_form.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img2 = Label(when_click_start, image=render) img2.image = render img2.pack() self.init_window_place(when_click_start, 1.3, 3) def what_is_clear_time(self): what_is_clear = Toplevel(self) what_is_clear.title('平均通关时间说明') title = Label(what_is_clear) title['text'] = '\n【 平均通关时间 】' title.pack() desc = Message(what_is_clear) desc['text'] = '\n平均通关时间是指在游戏中,从按下开始战斗到进入结算奖励界面所经过的时间(秒)\n' + \ '\n程序会在经过指定的时间后,再开始检测游戏画面是否进入了结算界面\n' + \ '\n如果设置一个较短的时间也可以,不过设置一个合理的时间,能节省你CPU资源\n(其实也没占多少_(:3」∠)_\n' desc['width'] = 300 desc.pack() self.init_window_place(what_is_clear, 1.3, 3) def create_main(self): self.label_scaling['text'] = '缩放倍率' self.var_scaling.set(self.scaling) self.entry_scaling['textvariable'] = self.var_scaling self.label_scaling.grid(row=0, column=0, sticky='E') self.entry_scaling.grid(row=0, column=1, sticky='W', columnspan=2) self.button_scaling_explain['text'] = '?' self.button_scaling_explain['command'] = self.what_is_scaling_window self.button_scaling_explain['relief'] = 'flat' self.button_scaling_explain.grid(row=0, column=2, sticky='E') self.label_mode['text'] = '模式' self.var_mode.set('单刷') self.listbox_mode['textvariable'] = self.var_mode self.listbox_mode['width'] = 10 self.listbox_mode['values'] = ["单刷", "乘客", "司机"] self.listbox_mode.bind("<<ComboboxSelected>>", self.turn_radio_on) self.label_mode.grid(row=1, column=0, sticky='E') self.listbox_mode.grid(row=1, column=1, sticky='W') self.button_mode_explain['text'] = '?' self.button_mode_explain['command'] = self.when_click_start_window self.button_mode_explain['relief'] = 'flat' self.button_mode_explain.grid(row=1, column=2, sticky='W') self.var_member.set(2) self.label_member['text'] = '车队人数' self.label_member.grid(row=2, column=0, sticky='E') self.radio1['text'] = '2人' self.radio1['variable'] = self.var_member self.radio1['value'] = 2 # self.radio1['command'] = self.test_val3 self.radio1.grid(row=2, column=1, sticky='W') self.radio1.configure(state='disabled') self.radio2['text'] = '3人' self.radio2['variable'] = self.var_member self.radio2['value'] = 3 # self.radio2['command'] = self.test_val3 self.radio2.grid(row=2, column=2, sticky='W') self.radio2.configure(state='disabled') self.label_clear_time['text'] = '平均通关时间' self.var_clear_time.set(self.clear_time) self.entry_clear_time['textvariable'] = self.var_clear_time self.label_clear_time.grid(row=3, column=0, sticky='E') self.entry_clear_time.grid(row=3, column=1, sticky='W', columnspan=2) self.button_clear_time_explain['text'] = '?' self.button_clear_time_explain['command'] = self.what_is_clear_time self.button_clear_time_explain['relief'] = 'flat' self.button_clear_time_explain.grid(row=3, column=2, sticky='E') self.label_offer['text'] = '好友发来悬赏' self.var_offer_mode.set('接受') self.listbox_offer_mode['textvariable'] = self.var_offer_mode self.listbox_offer_mode['width'] = 10 self.listbox_offer_mode['values'] = ["接受", "拒绝"] self.listbox_offer_mode.bind("<<ComboboxSelected>>", self.turn_radio_on) self.label_offer.grid(row=4, column=0, sticky='E') self.listbox_offer_mode.grid(row=4, column=1, sticky='W') self.label_timing_mode['text'] = '预定结束' self.var_timing_mode.set('无') self.listbox_timing_mode['textvariable'] = self.var_timing_mode self.listbox_timing_mode['width'] = 10 self.listbox_timing_mode['values'] = ["无", "定时[分钟]", "场数"] self.listbox_timing_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_timing_mode.grid(row=5, column=0, sticky='E') self.listbox_timing_mode.grid(row=5, column=1, sticky='W') self.var_timing_value.set('') self.entry_timing_value['textvariable'] = self.var_timing_value self.entry_timing_value['width'] = 5 self.entry_timing_value.configure(state='disabled') self.entry_timing_value.grid(row=5, column=2, sticky='W') self.start_ctn['text'] = 'START' self.start_ctn['width'] = 10 self.start_ctn['height'] = 2 self.start_ctn['command'] = self.fight_start self.start_ctn['relief'] = 'groove' self.start_ctn.grid(row=0, column=0, sticky='E') self.stop_ctn['text'] = 'STOP' self.stop_ctn['width'] = 10 self.stop_ctn['height'] = 2 self.stop_ctn['command'] = self.fight_stop self.stop_ctn['relief'] = 'groove' self.stop_ctn.grid(row=0, column=1, sticky='W') self.stop_ctn.configure(state='disabled') self.info_box['width'] = 40 self.info_box['height'] = 20 self.info_box.grid(row=1, column=0, columnspan=2) self.info_box.see(END) var = '请授予此程序管理员权限运行,否则在游戏窗口内鼠标无法被控制' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END)
class OptimizerMainWindow(): ''' classdocs ''' #TODO: change that name def reactToClick(self, event): a = AddRestrictionDialog(self) def __init__(self, optimizer): # always have a reference to model/controller self.optimizer = optimizer # setup main GUI and make stretchable self.guiRoot = Tk() self.guiRoot.title("OPTIMIZR") self.guiRoot.columnconfigure(1, weight=1) self.guiRoot.rowconfigure(0, weight=1) # left (settings) and right (sequences) part self.frameLeft = Frame(self.guiRoot) self.frameLeft.grid(row=0, column=0, sticky=W+E+N+S) self.frameLeft.columnconfigure(0, weight=1) self.frameRight = Frame(self.guiRoot) self.frameRight.grid(row=0, column=1, sticky=W+E+N+S) self.frameRight.columnconfigure(0, weight=1) self.frameRight.rowconfigure(0, weight=1) self.frameRight.rowconfigure(1, weight=1) self.frameSpeciesControll = LabelFrame(self.frameLeft, text="Species", pady=10, padx=10) self.frameSpeciesControll.columnconfigure(1, weight=1) self.frameOptimizationControll = LabelFrame(self.frameLeft, text="Optimization", pady=10, padx=10) self.frameRestrictionControll = LabelFrame(self.frameLeft, text="Restriction Enzymes", pady=10, padx=10) self.frameSpeciesControll.grid(row=0, column=0, sticky=W+E, padx=10, pady=10) self.frameOptimizationControll.grid(row=1, column=0, sticky=W+E, padx=10, pady=10) self.frameRestrictionControll.grid(row=2, column=0, sticky=W+E, padx=10, pady=10) # Species Controll Label(self.frameSpeciesControll, text="Source:").grid(row=0, column=0) Label(self.frameSpeciesControll, text="Target:").grid(row=1, column=0) self.comboSourceSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboSourceSpecies.grid(row=0, column=1, pady=5, sticky="ew") self.comboTargetSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboTargetSpecies.grid(row=1, column=1, pady=5, sticky="we") self.buttonSpeciesList = Button(self.frameSpeciesControll, text="Edit Species List") self.buttonSpeciesList.grid(row=2, column=1, pady=5, sticky="e") self.comboSourceSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) self.comboTargetSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Optimization Controll Label(self.frameOptimizationControll, text="Optimization Strategy:").grid(row=0, column=0) self.comboOptimizationStrategy = Combobox(self.frameOptimizationControll, state="readonly") self.comboOptimizationStrategy.grid(row=0, column=1) self.comboOptimizationStrategy["values"] = self.optimizer.possibleOptimizationStrategies self.comboOptimizationStrategy.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Restriction Enzymes self.listRestriction = Listbox(self.frameRestrictionControll) self.listRestriction.grid(row=0, column=0, columnspan=3, pady=5, sticky=W+E) self.frameRestrictionControll.columnconfigure(0, weight=1) self.buttonRestricionAdd = Button(self.frameRestrictionControll, text=" + ") self.buttonRestricionDel = Button(self.frameRestrictionControll, text=" - ") self.buttonRestricionAdd.grid(row=1, column=1, padx=5) self.buttonRestricionDel.grid(row=1, column=2, padx=5) # Source Sequence Frame self.frameSourceSequence = LabelFrame(self.frameRight, text="Source Sequence", padx=10, pady=10) self.frameResultSequence = LabelFrame(self.frameRight, text="Result Sequence", padx=10, pady=10) self.frameSourceSequence.grid(row=0, column=0, sticky="wens", padx=10, pady=10) self.frameResultSequence.grid(row=1, column=0, sticky="wens", padx=10, pady=10) self.buttonSourceLoad = Button(self.frameSourceSequence, text=" Load ") self.textSourceSeq = ScrolledText(self.frameSourceSequence, height=10) self.buttonSourceLoad.grid(row=0, column=1, sticky="e", pady=5) self.textSourceSeq.grid(row=1, column=0, columnspan=2, sticky="wens") self.frameSourceSequence.columnconfigure(0, weight=1) self.frameSourceSequence.rowconfigure(1, weight=1) self.textSourceSeq.frame.columnconfigure(1, weight=1) self.textSourceSeq.frame.rowconfigure(0, weight=1) self.buttonOptimize = Button(self.frameResultSequence, text=" OPTIMIZE! ") self.buttonOptimize.bind("<ButtonRelease>", self.actionOptimize) self.buttonRemoveRestriction = Button(self.frameResultSequence, text=" RESTRICTION-B-GONE! ") self.buttonRemoveRestriction.bind("<ButtonRelease>", self.actionRemoveRestricion) self.buttonSaveResult = Button(self.frameResultSequence, text=" Save ") self.textResultSequence = ScrolledText(self.frameResultSequence, height=10) self.buttonOptimize.grid(column=0, row=0, pady=5, sticky="w") self.buttonRemoveRestriction.grid(column=1, row=0, pady=5, padx=10, sticky="w") self.textResultSequence.grid(row=1, column=0, columnspan=4, sticky="wens") self.buttonSaveResult.grid(row=2, column=3, pady=5, sticky="e") self.frameResultSequence.columnconfigure(2, weight=1) self.frameResultSequence.rowconfigure(1, weight=1) self.textResultSequence.frame.columnconfigure(1, weight=1) self.textResultSequence.frame.rowconfigure(0, weight=1) self.textSourceSeq.bind("<<Modified>>", self.actionSequenceModified) self.textResultSequence.bind("<<Modified>>", self.actionSequenceModified) #generate color tags for textboxes for i in range(101): #green for normal codons (r,g,b) = colorsys.hsv_to_rgb(210/360, i/100, 1.0) colorHex = "#%02x%02x%02x" % (int(r*255), int(g*255), int(b*255)) self.textSourceSeq.tag_config("normal"+str(i), background=colorHex) self.textResultSequence.tag_config("normal"+str(i), background=colorHex) #red for codons with restriction sites (r,g,b) = colorsys.hsv_to_rgb(5/360, i/100, 1.0) colorHex = "#%02x%02x%02x" % (int(r*255), int(g*255), int(b*255)) self.textSourceSeq.tag_config("restrict"+str(i), background=colorHex) self.textResultSequence.tag_config("restrict"+str(i), background=colorHex) # Set (minimum + max) Window size self.guiRoot.update() self.guiRoot.minsize(self.guiRoot.winfo_width(), self.guiRoot.winfo_height()) self.buttonRestricionAdd.bind("<ButtonRelease>", self.reactToClick) self.buttonRestricionDel.bind("<ButtonRelease>", self.actionRestrictionEnzymeDelete) self.buttonSpeciesList.bind("<ButtonRelease>", self.actionEditSpeciesButton) self.buttonSourceLoad.bind("<ButtonRelease>", self.actionLoadSequence) self.buttonSaveResult.bind("<ButtonRelease>", self.actionSaveSequence) # TEST # self.listRestriction.insert("end", "EcoRI") # self.listRestriction.insert("end", "BamHI") # # dummy event to manually trigger update self.guiRoot.bind("<<Update>>", self.actionUpdate) self.actionUpdate(None) self.guiRoot.mainloop() def actionRestrictionEnzymeDelete(self, event): try: selectedEnzyme = self.listRestriction.selection_get() self.optimizer.restrictionEnzymeList.remove(selectedEnzyme) self.guiRoot.event_generate("<<Update>>") except tkinter.TclError : # no selection pass def actionUpdate(self, event): # print("update called") # clear list of restriction enzymes self.listRestriction.delete(0, "end") for r in self.optimizer.restrictionEnzymeList: self.listRestriction.insert("end", r) self.comboSourceSpecies.delete(0, "end") self.comboTargetSpecies.delete(0, "end") speciesValues = list() for (taxid, name) in self.optimizer.speciesList: speciesValues.append(taxid + ": " + name) self.comboSourceSpecies["values"] = speciesValues self.comboTargetSpecies["values"] = speciesValues if self.comboSourceSpecies.get() not in speciesValues: self.comboSourceSpecies.set("") if self.comboTargetSpecies.get() not in speciesValues: self.comboTargetSpecies.set("") self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) self.optimizer.saveConfig("config.ini") def actionEditSpeciesButton(self, event): speciesListDialog = SpeciesListDialog(self) def actionOptimizerSettingsChanged(self, event=None): # print("Something happened") strategy = self.comboOptimizationStrategy.get() sourceString = self.comboSourceSpecies.get() targetString = self.comboTargetSpecies.get() if not (strategy and sourceString and targetString): return sourceTaxid = sourceString.split(":")[0] targetTaxid = targetString.split(":")[0] self.optimizer.setOptimizer(sourceTaxid, targetTaxid, strategy) self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) # self.optimizer.testPrint() def actionOptimize(self, event=None): self.optimizer.runOptimization() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionRemoveRestricion(self, event=None): self.optimizer.runRestricionRemoval() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionSequenceModified(self, event=None): # necessary if, otherwise -> infinite loop if self.textSourceSeq.edit_modified(): seq = self.textSourceSeq.get("1.0", "end").strip() seq = stripCharsNotInList(seq.upper(), ['A', 'C', 'G', 'T']) self.optimizer.setSourceSeq(seq) oldInsert = self.textSourceSeq.index("insert") self.textSourceSeq.delete("1.0", "end") sourceCodons = self.optimizer.getCodonsForPrint(True) if not sourceCodons: self.textSourceSeq.insert("end", self.optimizer.sourceSequence) else: for (co, sc, r) in sourceCodons: if sc: if not r: self.textSourceSeq.insert("end", co, "normal"+str(int(sc*100))) #print("normal"+str(int(sc*100))) else: self.textSourceSeq.insert("end", co, "restrict"+str(int(sc*100))) else: # remainder without color self.textSourceSeq.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) # reset the modified status at the very end self.textSourceSeq.edit_modified(False) if self.textResultSequence.edit_modified(): seq = self.textResultSequence.get("1.0", "end").strip() # self.optimizer.setOptimizedSeq(seq) oldInsert = self.textResultSequence.index("insert") self.textResultSequence.delete("1.0", "end") targetCodons = self.optimizer.getCodonsForPrint(False) if not targetCodons: self.textSourceSeq.insert("end", self.optimizer.optimizedSequence) else: for (co, sc, r) in targetCodons: if sc: if not r: self.textResultSequence.insert("end", co, "normal"+str(int(sc*100))) #print("normal"+str(int(sc*100))) else: self.textResultSequence.insert("end", co, "restrict"+str(int(sc*100))) else: # remainder without color self.textResultSequence.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) self.textResultSequence.edit_modified(False) def actionLoadSequence(self, event=None): filename = tkinter.filedialog.askopenfilename() if filename: seq = sequenceIO.readFile(filename) self.textSourceSeq.delete("1.0", "end") self.textSourceSeq.insert("end", seq) self.textSourceSeq.edit_modified(True) def actionSaveSequence(self, event=None): filename = tkinter.filedialog.asksaveasfilename() if filename: # print("file is " + filename) with open(filename, mode='w') as fd: fd.write(self.optimizer.optimizedSequence)
class App(Frame): """Гланое окно приложения""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # screen_width = self.winfo_screenwidth() # print(screen_width, self.winfo_screenheight()) self.master.title(f'Mem-translate {__version__}') self.master.minsize(300, 200) menu = Menu(self.master) self.master.configure(menu=menu) menu_file = Menu(menu) menu_file.add_command(label='Импорт', command=self.on_import) menu.add_cascade(label='Файл', menu=menu_file) width = 73 self.text = ScrolledText(self, bg='white', height=31, width=width, undo=True, wrap='word') self.text['font'] = DEFAULT_FONT self.text.tag_configure(TAG_BLUE, background='#aaf') self.text.focus_set() self.text.bind('<Key>', self.on_key_text) self.text.grid_configure(row=0, column=0, rowspan=2) self.text_fuzz = ScrolledText(self, bg='white', height=15, width=width, wrap='word') self.text_fuzz['font'] = DEFAULT_FONT self.text_fuzz.tag_configure(TAG_BLUE, background='#afa') self.text_fuzz.bind('<Key>', lambda event: 'break') self.text_fuzz.grid_configure(row=0, column=1, sticky='n') self.text_tran = ScrolledText(self, bg='white', height=15, width=width, wrap='word') self.text_tran['font'] = DEFAULT_FONT self.text_tran.bind('<Key>', lambda event: 'break') self.text_tran.grid_configure(row=1, column=1, sticky='s') self.grid_configure() def destroy(self): # todo log.info('destroy') super().destroy() def on_import(self): """Обработчик кнопки Импорт""" filename = Open(initialdir='../you-can/source/', filetypes=(('Текст', '*.txt'),)).show() text_ls = do_import(filename) self.do_open(text_ls) def do_open(self, text_ls: List[str]): """Отрисовать текст""" for line in text_ls: self.text.insert('end', line) # добавляем немного подсветки # if not line.startswith(PREFIX_TRANSLATE) and line != PREFIX_CUT: if not line.startswith('>>>'): i = self.text.index('insert').split('.', 1)[0] self.text.tag_add(TAG_BLUE, f'{i}.0', f'{i}.{len(line)}') self.text.insert('end', '\n') log.debug(self.text.tag_ranges(TAG_BLUE)) def on_key_text(self, event): """Обработчик нажатий любой клавиши в главном textArea""" if event.keycode == 36: # Return self.do_enter() return 'break' log.debug(event) def do_enter(self): tag_range = self.text.tag_nextrange(TAG_BLUE, self.text.index('insert')) if not tag_range: return index1, index2 = tag_range # двигаем курсор index = int(index2.split('.')[0]) + 1 self.text.mark_set('insert', f'{index}.{len(PREFIX_TRANSLATE)}') self.text.see('insert') text: str = self.text.get(index1, index2) # переводим текст self.text_tran.delete('1.0', 'end') start_new_thread(self.thread_translate, (text,)) # ... self.text_fuzz.delete('1.0', 'end') start_new_thread(self.thread_fuzz, (text,)) def thread_translate(self, text: str): """Асинхронно запускаем машинный перевод""" try: text2 = translate_yandex(text) except BaseException as ex: text2 = str(ex) self.text_tran.insert('1.0', text2) def thread_fuzz(self, text: str): """Асинхронно ищем нечёткие совпадения""" # todo закешировать + парсить перевод + перенести в text.py ls: list = self.text.get('1.0', 'end').split('\n') ls.remove(text) choices = [f'{i + 1}: {line}' for i, line in enumerate(ls) if not line.startswith('>>>')] # result = [f'{line} ({p})' for line, p in extractBests(text, choices, score_cutoff=1, limit=7)] # result = [(line, fuzz.token_set_ratio(line, text)) for line in choices] ww = set(re.findall(r'\w{4,}', text)) - {'that', 'That', 'only', 'Only'} result = [] for line in choices: p = len(set(re.findall(r'\w{4,}', line)) & ww) if p > 0: result.append((line, p)) result = heapq.nlargest(7, result, key=lambda x: x[1]) result = [line for line, p in result] # self.text_fuzz.insert('1.0', '\n'.join(result)) for line in result: self.text_fuzz.insert('end', line) i = self.text_fuzz.index('insert').split('.', 1)[0] # for m in SequenceMatcher(None, line.lower(), text.lower()).get_matching_blocks(): # self.text_fuzz.tag_add(TAG_BLUE, f'{i}.{m.a}', f'{i}.{m.a + m.size}') for w in ww: for m in re.finditer(w, line): self.text_fuzz.tag_add(TAG_BLUE, f'{i}.{m.start()}', f'{i}.{m.end()}') self.text_fuzz.insert('end', '\n')
class OptimizerMainWindow: """ classdocs """ # TODO: change that name def reactToClick(self, event): a = AddRestrictionDialog(self) def __init__(self, optimizer): # always have a reference to model/controller self.optimizer = optimizer # setup main GUI and make stretchable self.guiRoot = Tk() self.guiRoot.title("OPTIMIZR") self.guiRoot.columnconfigure(1, weight=1) self.guiRoot.rowconfigure(0, weight=1) # left (settings) and right (sequences) part self.frameLeft = Frame(self.guiRoot) self.frameLeft.grid(row=0, column=0, sticky=W + E + N + S) self.frameLeft.columnconfigure(0, weight=1) self.frameRight = Frame(self.guiRoot) self.frameRight.grid(row=0, column=1, sticky=W + E + N + S) self.frameRight.columnconfigure(0, weight=1) self.frameRight.rowconfigure(0, weight=1) self.frameRight.rowconfigure(1, weight=1) self.frameSpeciesControll = LabelFrame(self.frameLeft, text="Species", pady=10, padx=10) self.frameSpeciesControll.columnconfigure(1, weight=1) self.frameOptimizationControll = LabelFrame(self.frameLeft, text="Optimization", pady=10, padx=10) self.frameRestrictionControll = LabelFrame(self.frameLeft, text="Restriction Enzymes", pady=10, padx=10) self.frameSpeciesControll.grid(row=0, column=0, sticky=W + E, padx=10, pady=10) self.frameOptimizationControll.grid(row=1, column=0, sticky=W + E, padx=10, pady=10) self.frameRestrictionControll.grid(row=2, column=0, sticky=W + E, padx=10, pady=10) # Species Controll Label(self.frameSpeciesControll, text="Source:").grid(row=0, column=0) Label(self.frameSpeciesControll, text="Target:").grid(row=1, column=0) self.comboSourceSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboSourceSpecies.grid(row=0, column=1, pady=5, sticky="ew") self.comboTargetSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboTargetSpecies.grid(row=1, column=1, pady=5, sticky="we") self.buttonSpeciesList = Button(self.frameSpeciesControll, text="Edit Species List") self.buttonSpeciesList.grid(row=2, column=1, pady=5, sticky="e") self.comboSourceSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) self.comboTargetSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Optimization Controll Label(self.frameOptimizationControll, text="Optimization Strategy:").grid(row=0, column=0) self.comboOptimizationStrategy = Combobox(self.frameOptimizationControll, state="readonly") self.comboOptimizationStrategy.grid(row=0, column=1) self.comboOptimizationStrategy["values"] = self.optimizer.possibleOptimizationStrategies self.comboOptimizationStrategy.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Restriction Enzymes self.listRestriction = Listbox(self.frameRestrictionControll) self.listRestriction.grid(row=0, column=0, columnspan=3, pady=5, sticky=W + E) self.frameRestrictionControll.columnconfigure(0, weight=1) self.buttonRestricionAdd = Button(self.frameRestrictionControll, text=" + ") self.buttonRestricionDel = Button(self.frameRestrictionControll, text=" - ") self.buttonRestricionAdd.grid(row=1, column=1, padx=5) self.buttonRestricionDel.grid(row=1, column=2, padx=5) # Source Sequence Frame self.frameSourceSequence = LabelFrame(self.frameRight, text="Source Sequence", padx=10, pady=10) self.frameResultSequence = LabelFrame(self.frameRight, text="Result Sequence", padx=10, pady=10) self.frameSourceSequence.grid(row=0, column=0, sticky="wens", padx=10, pady=10) self.frameResultSequence.grid(row=1, column=0, sticky="wens", padx=10, pady=10) self.buttonSourceLoad = Button(self.frameSourceSequence, text=" Load ") self.textSourceSeq = ScrolledText(self.frameSourceSequence, height=10) self.buttonSourceLoad.grid(row=0, column=1, sticky="e", pady=5) self.textSourceSeq.grid(row=1, column=0, columnspan=2, sticky="wens") self.frameSourceSequence.columnconfigure(0, weight=1) self.frameSourceSequence.rowconfigure(1, weight=1) self.textSourceSeq.frame.columnconfigure(1, weight=1) self.textSourceSeq.frame.rowconfigure(0, weight=1) self.buttonOptimize = Button(self.frameResultSequence, text=" OPTIMIZE! ") self.buttonOptimize.bind("<ButtonRelease>", self.actionOptimize) self.buttonRemoveRestriction = Button(self.frameResultSequence, text=" RESTRICTION-B-GONE! ") self.buttonRemoveRestriction.bind("<ButtonRelease>", self.actionRemoveRestricion) self.buttonSaveResult = Button(self.frameResultSequence, text=" Save ") self.textResultSequence = ScrolledText(self.frameResultSequence, height=10) self.buttonOptimize.grid(column=0, row=0, pady=5, sticky="w") self.buttonRemoveRestriction.grid(column=1, row=0, pady=5, padx=10, sticky="w") self.textResultSequence.grid(row=1, column=0, columnspan=4, sticky="wens") self.buttonSaveResult.grid(row=2, column=3, pady=5, sticky="e") self.frameResultSequence.columnconfigure(2, weight=1) self.frameResultSequence.rowconfigure(1, weight=1) self.textResultSequence.frame.columnconfigure(1, weight=1) self.textResultSequence.frame.rowconfigure(0, weight=1) self.textSourceSeq.bind("<<Modified>>", self.actionSequenceModified) self.textResultSequence.bind("<<Modified>>", self.actionSequenceModified) # generate color tags for textboxes for i in range(101): # green for normal codons (r, g, b) = colorsys.hsv_to_rgb(210 / 360, i / 100, 1.0) colorHex = "#%02x%02x%02x" % (int(r * 255), int(g * 255), int(b * 255)) self.textSourceSeq.tag_config("normal" + str(i), background=colorHex) self.textResultSequence.tag_config("normal" + str(i), background=colorHex) # red for codons with restriction sites (r, g, b) = colorsys.hsv_to_rgb(5 / 360, i / 100, 1.0) colorHex = "#%02x%02x%02x" % (int(r * 255), int(g * 255), int(b * 255)) self.textSourceSeq.tag_config("restrict" + str(i), background=colorHex) self.textResultSequence.tag_config("restrict" + str(i), background=colorHex) # Set (minimum + max) Window size self.guiRoot.update() self.guiRoot.minsize(self.guiRoot.winfo_width(), self.guiRoot.winfo_height()) self.buttonRestricionAdd.bind("<ButtonRelease>", self.reactToClick) self.buttonRestricionDel.bind("<ButtonRelease>", self.actionRestrictionEnzymeDelete) self.buttonSpeciesList.bind("<ButtonRelease>", self.actionEditSpeciesButton) self.buttonSourceLoad.bind("<ButtonRelease>", self.actionLoadSequence) self.buttonSaveResult.bind("<ButtonRelease>", self.actionSaveSequence) # TEST # self.listRestriction.insert("end", "EcoRI") # self.listRestriction.insert("end", "BamHI") # # dummy event to manually trigger update self.guiRoot.bind("<<Update>>", self.actionUpdate) self.actionUpdate(None) self.guiRoot.mainloop() def actionRestrictionEnzymeDelete(self, event): try: selectedEnzyme = self.listRestriction.selection_get() self.optimizer.restrictionEnzymeList.remove(selectedEnzyme) self.guiRoot.event_generate("<<Update>>") except tkinter.TclError: # no selection pass def actionUpdate(self, event): # print("update called") # clear list of restriction enzymes self.listRestriction.delete(0, "end") for r in self.optimizer.restrictionEnzymeList: self.listRestriction.insert("end", r) self.comboSourceSpecies.delete(0, "end") self.comboTargetSpecies.delete(0, "end") speciesValues = list() for (taxid, name) in self.optimizer.speciesList: speciesValues.append(taxid + ": " + name) self.comboSourceSpecies["values"] = speciesValues self.comboTargetSpecies["values"] = speciesValues if self.comboSourceSpecies.get() not in speciesValues: self.comboSourceSpecies.set("") if self.comboTargetSpecies.get() not in speciesValues: self.comboTargetSpecies.set("") self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) self.optimizer.saveConfig("config.ini") def actionEditSpeciesButton(self, event): speciesListDialog = SpeciesListDialog(self) def actionOptimizerSettingsChanged(self, event=None): # print("Something happened") strategy = self.comboOptimizationStrategy.get() sourceString = self.comboSourceSpecies.get() targetString = self.comboTargetSpecies.get() if not (strategy and sourceString and targetString): return sourceTaxid = sourceString.split(":")[0] targetTaxid = targetString.split(":")[0] self.optimizer.setOptimizer(sourceTaxid, targetTaxid, strategy) self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) # self.optimizer.testPrint() def actionOptimize(self, event=None): self.optimizer.runOptimization() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionRemoveRestricion(self, event=None): self.optimizer.runRestricionRemoval() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionSequenceModified(self, event=None): # necessary if, otherwise -> infinite loop if self.textSourceSeq.edit_modified(): seq = self.textSourceSeq.get("1.0", "end").strip() seq = stripCharsNotInList(seq.upper(), ["A", "C", "G", "T"]) self.optimizer.setSourceSeq(seq) oldInsert = self.textSourceSeq.index("insert") self.textSourceSeq.delete("1.0", "end") sourceCodons = self.optimizer.getCodonsForPrint(True) if not sourceCodons: self.textSourceSeq.insert("end", self.optimizer.sourceSequence) else: for (co, sc, r) in sourceCodons: if sc: if not r: self.textSourceSeq.insert("end", co, "normal" + str(int(sc * 100))) # print("normal"+str(int(sc*100))) else: self.textSourceSeq.insert("end", co, "restrict" + str(int(sc * 100))) else: # remainder without color self.textSourceSeq.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) # reset the modified status at the very end self.textSourceSeq.edit_modified(False) if self.textResultSequence.edit_modified(): seq = self.textResultSequence.get("1.0", "end").strip() # self.optimizer.setOptimizedSeq(seq) oldInsert = self.textResultSequence.index("insert") self.textResultSequence.delete("1.0", "end") targetCodons = self.optimizer.getCodonsForPrint(False) if not targetCodons: self.textSourceSeq.insert("end", self.optimizer.optimizedSequence) else: for (co, sc, r) in targetCodons: if sc: if not r: self.textResultSequence.insert("end", co, "normal" + str(int(sc * 100))) # print("normal"+str(int(sc*100))) else: self.textResultSequence.insert("end", co, "restrict" + str(int(sc * 100))) else: # remainder without color self.textResultSequence.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) self.textResultSequence.edit_modified(False) def actionLoadSequence(self, event=None): filename = tkinter.filedialog.askopenfilename() if filename: seq = sequenceIO.readFile(filename) self.textSourceSeq.delete("1.0", "end") self.textSourceSeq.insert("end", seq) self.textSourceSeq.edit_modified(True) def actionSaveSequence(self, event=None): filename = tkinter.filedialog.asksaveasfilename() if filename: # print("file is " + filename) with open(filename, mode="w") as fd: fd.write(self.optimizer.optimizedSequence)
class Application(Frame): def __init__(self, master=None): """ 控件初始化 :param master: """ self.debug = False self.version = 'miss' self.warning = '【封号防止】\n' + \ '请尽量在自己的日常刷魂时间使用\n' + \ '请不要长时间连续使用,任何使你看起来明显违背人类正常作息规律的行为,很容易会被鬼使黑盯上\n' + \ '当你离开了常在城市,请不要使用,这会被认为是找了代练\n' + \ '点到为止,贪婪是万恶之源\n' self.label = r'阴阳师-网易游戏' self.hwnd = None self.shell = None if not self.info_get(): self.scaling = 1 self.clear_time = 35 self.delay_time = 1 self.fight = None self.timing_value = None # 控件初始化 Frame.__init__(self, master) self.pack() self.frame1 = Frame(self) self.frame1.pack() self.frame2 = Frame(self) self.frame2.pack() self.label_mode = Label(self.frame1) self.var_mode = StringVar(self.frame1) self.listbox_mode = ttk.Combobox(self.frame1) self.button_mode_explain = Button(self.frame1) self.label_member = Label(self.frame1) self.var_member = IntVar() self.radio1 = Radiobutton(self.frame1) self.radio2 = Radiobutton(self.frame1) self.label_clear_time = Label(self.frame1) self.var_clear_time = StringVar(self.frame1) self.entry_clear_time = Entry(self.frame1) self.button_clear_time_explain = Button(self.frame1) self.label_delay_time = Label(self.frame1) self.var_delay_time = StringVar(self.frame1) self.entry_delay_time = Entry(self.frame1) self.button_delay_time_explain = Button(self.frame1) self.label_offer = Label(self.frame1) self.var_offer_mode = StringVar(self.frame1) self.listbox_offer_mode = ttk.Combobox(self.frame1) self.label_timing_mode = Label(self.frame1) self.var_timing_mode = StringVar(self.frame1) self.listbox_timing_mode = ttk.Combobox(self.frame1) self.var_timing_value = StringVar(self.frame1) self.entry_timing_value = Entry(self.frame1) self.label_done_action_mode = Label(self.frame1) self.var_done_action_mode = StringVar(self.frame1) self.listbox_done_action_mode = ttk.Combobox(self.frame1) self.entry_test = Entry(self.frame1) self.test_btn = Button(self.frame1) self.start_ctn = Button(self.frame2) self.stop_ctn = Button(self.frame2) self.info_box = ScrolledText(self.frame2) self.queue = Queue(maxsize=1) self._running = 0 hot_key = threading.Thread(target=self.hotkey_thread, name='hotkey_thread') hot_key.setDaemon(True) hot_key.start() def setdebug(self, debug): self.debug = debug def setversion(self, version): self.version = version def get_clear_time(self): """ 校验平均通关时间输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.var_clear_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='平均通关时间只能为数字') return False if var <= 5: messagebox.showinfo(title='提示', message='平均通关时间不能小于5') return False return var def get_delay_time(self): """ 校验平均通关时间输入值 :return: 校验通过则返回浮点型数字,否则返回False """ var = self.var_delay_time.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='战斗后等待时间只能为数字') return False if var <= 0: messagebox.showinfo(title='提示', message='战斗后等待时间不能小于0') return False return var def get_timimg(self): """ 校验预定结束输入值 :return: 校验通过则返回浮点型数字,否则返回False """ if self.listbox_timing_mode.get() == '无' or \ self.listbox_timing_mode.get() == '超鬼王模式1' or \ self.listbox_timing_mode.get() == '超鬼王模式2': return True var = self.var_timing_value.get() try: var = float(var) except ValueError: messagebox.showinfo(title='提示', message='预定结束只能填入数字') return False if var < 1: messagebox.showinfo(title='提示', message='数字过小,无法执行') return False return var def info_get(self): """ 读取存储文件 :return: """ try: with shelve.open('mysetting.db') as data: setting_data = data['setting'] self.scaling = setting_data['scaling'] self.clear_time = setting_data['clear_time'] self.delay_time = setting_data['delay_time'] except KeyError: return False return True def info_save(self): """ 存储设置 :return: """ with shelve.open('mysetting.db') as data: setting_data = dict() setting_data['clear_time'] = self.var_clear_time.get() setting_data['delay_time'] = self.var_delay_time.get() data['setting'] = setting_data def turn_radio_on(self, *args): """ 根据条件激活相应控件 :param args: :return: """ type(args) var = self.listbox_mode.get() if var == '司机': self.radio1.configure(state='active') self.radio2.configure(state='active') else: self.radio1.configure(state='disabled') self.radio2.configure(state='disabled') def turn_entry_on(self, *args): """ 根据条件激活相应控件 :param args: :return: """ type(args) var = self.listbox_timing_mode.get() if var == '定时[分钟]' or var == '场数': self.entry_timing_value.configure(state='normal') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('关闭游戏窗口') elif var == '超鬼王模式1': self.entry_timing_value.configure(state='disabled') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('仅停止挂机') content = '\n超鬼王模式1:\n仅自己发现的鬼王\n' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(content) + '\n') self.info_box.see(END) elif var == '超鬼王模式2': self.entry_timing_value.configure(state='disabled') self.listbox_done_action_mode.configure(state='normal') self.var_done_action_mode.set('仅停止挂机') content = '\n超鬼王模式2:\n自己发现的鬼王或好友邀请的鬼王\n' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(content) + '\n') self.info_box.see(END) else: self.entry_timing_value.configure(state='disabled') self.var_done_action_mode.set('') self.listbox_done_action_mode.configure(state='disabled') def turn_all_widget_off(self): self.entry_clear_time.configure(state='disabled') self.entry_delay_time.configure(state='disabled') self.entry_timing_value.configure(state='disabled') self.listbox_mode.configure(state='disabled') self.listbox_offer_mode.configure(state='disabled') self.listbox_timing_mode.configure(state='disabled') self.listbox_done_action_mode.configure(state='disabled') def turn_all_widget_on(self): self.entry_clear_time.configure(state='normal') self.entry_delay_time.configure(state='normal') self.entry_timing_value.configure(state='normal') self.listbox_mode.configure(state='normal') self.listbox_offer_mode.configure(state='normal') self.listbox_timing_mode.configure(state='normal') self.listbox_done_action_mode.configure(state='normal') def fight_start(self): """ START按钮响应流程 :return: """ self.clear_time = self.get_clear_time() if not self.clear_time: return False self.delay_time = self.get_delay_time() if not self.delay_time: return False self.timing_value = self.get_timimg() if not self.timing_value: return False self.info_save() # 获取游戏窗口句柄 self.hwnd = check_hwnd(self.label) if not self.hwnd: messagebox.showinfo(title='提示', message='游戏没有运行') return False # self.shell = win32com.client.Dispatch("WScript.Shell") # self.shell.SendKeys('%') jump_window(self.hwnd) time.sleep(0.5) try: self.fight = GameController(self.hwnd) print('原分辨率 %s * %s' % (self.fight.resolution['width'], self.fight.resolution['height'])) print('缩放后分辨率 %s * %s' % (self.fight.resolution['width_scale'], self.fight.resolution['height_scale'])) print('缩放比例 %s' % self.fight.resolution['scaling']) except ResolutionGetError: messagebox.showinfo(title='提示', message='获取Windows缩放比例失败,无法计算坐标') return False if self.debug: self.fight.setdebug(True) threads = [] thread1 = threading.Thread(target=self.fight_thread, name='fight_thread') threads.append(thread1) thread2 = threading.Thread(target=self.offer_thread, name='offer_thread') threads.append(thread2) thread3 = threading.Thread(target=self.fullrepo_thread, name='fullrepo_thread') threads.append(thread3) if self.listbox_timing_mode.get( ) == '超鬼王模式1' or self.listbox_timing_mode.get() == '超鬼王模式2': thread4 = threading.Thread(target=self.boss_monitoring_thread, name='boss_thread') threads.append(thread4) # 将线程状态、队列内容置为1 self._running = 1 if self.queue.empty(): self.queue.put(1) else: self.queue.get() self.queue.put(1) self.start_ctn.configure(state='disabled') self.stop_ctn.configure(state='active') for thread in threads: thread.setDaemon(True) thread.start() def fight_stop(self): """ STOP按钮响应流程 :return: """ # 将线程状态、队列内容置为0 self._running = 0 self.queue.put(0) self.start_ctn.configure(state='active') self.stop_ctn.configure(state='disabled') self.turn_all_widget_on() var = '[%s]挂机结束。记得关御魂buff' % datetime.datetime.now().strftime( "%H:%M:%S") self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) if self.debug: logging('STOP指令-----------------') if len(sys.argv) == 1 or (len(sys.argv) > 1 and sys.argv[1] != 'debug'): self.setdebug(False) def fight_thread(self): """ 战斗控制线程,并输出相关信息 :return: """ jump_window(self.hwnd) if not self.queue.empty(): self.queue.get() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(self.warning) + '\n', 'RED') self.info_box.tag_config('RED', foreground='red') var = '[%s]挂机开始。按Ctrl + F1可以停止挂机' % datetime.datetime.now().strftime( "%H:%M:%S") if self.debug: var = var + '\n当前以debug模式运行,在当前目录下将生成debug.log' self.turn_all_widget_off() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) rounds = 0 total_time = 0 beginning_time = int(time.time()) while True: if self._running == 1: fight_start_time = time.time() self.fight.form_team_phase(self.listbox_mode.get(), self.var_member.get(), self.queue) self.fight.wait_fight_finish_phase(self.listbox_mode.get(), self.clear_time, self.queue) jump_window(self.hwnd) self.fight.settle_phase(self.queue) if self._running == 1: fight_end_time = int(time.time()) fight_time = fight_end_time - fight_start_time rounds = rounds + 1 total_time = total_time + fight_time elapsed_time = fight_end_time - beginning_time var = '第 %s 场 耗时:%s 共计:%s' % \ (rounds, time_format(fight_time), time_format(elapsed_time)) self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) if self.debug: logging('------------------------') # 检查是否到达预定结束场数或时间 if (self.listbox_timing_mode.get() == '场数' and rounds >= self.timing_value) or \ (self.listbox_timing_mode.get() == '定时[分钟]' and elapsed_time / 60 >= self.timing_value): if self.listbox_done_action_mode.get() == '关闭游戏窗口': win32gui.PostMessage(self.hwnd, win32con.WM_CLOSE, 0, 0) time.sleep(1) lebel_exit = '退出游戏' hwnd_exit = check_hwnd(lebel_exit) win32gui.PostMessage(hwnd_exit, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0) win32gui.PostMessage(hwnd_exit, win32con.WM_KEYUP, win32con.VK_RETURN, 0) var = '已到达预定目标,游戏窗口已关闭。下线15分钟后buff自动关闭' elif self.listbox_done_action_mode.get() == '仅停止挂机': var = '已到达预定目标,挂机已停止。' self.fight_stop() self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) random.uniform(1, 2) delay_time = int(self.delay_time) + random.uniform( 0.2, 0.5) time.sleep(delay_time) elif self._running == 0: return def offer_thread(self): """ 悬赏协助控制线程 :return: """ while True: if self._running == 1: mode = None if self.listbox_offer_mode.get() == "接受": mode = 1 elif self.listbox_offer_mode.get() == "拒绝": mode = 2 self.fight.check_offer(mode, self.queue) elif self._running == 0: return def fullrepo_thread(self): """ 点击满仓提示控制线程 :return: """ while True: if self._running == 1: self.fight.check_fullrepo_alert(self.queue) elif self._running == 0: return def hotkey_thread(self): """ 快捷键监听线程 :return: """ user32 = ctypes.windll.user32 byref = ctypes.byref user32.RegisterHotKey(None, 10001, win32con.MOD_CONTROL, win32con.VK_F1) user32.RegisterHotKey(None, 10002, win32con.MOD_CONTROL, win32con.VK_F2) try: msg = ctypes.wintypes.MSG() while user32.GetMessageA(byref(msg), None, 0, 0) != 0: if msg.message == win32con.WM_HOTKEY: if self._running == 1 and msg.wParam == 10001: self.fight_stop() elif self._running == 0 and msg.wParam == 10002: self.setdebug(True) self.fight_start() user32.TranslateMessage(byref(msg)) user32.DispatchMessageA(byref(msg)) finally: user32.UnregisterHotKey(None, 10001) user32.UnregisterHotKey(None, 10002) def boss_monitoring_thread(self): """ 点击发现超鬼王提示控制线程 :return: """ "" mode = None if self.listbox_timing_mode.get() == '超鬼王模式1': mode = 1 elif self.listbox_timing_mode.get() == '超鬼王模式2': mode = 2 logging('mode:%s' % mode) while True: if self._running == 1: self.fight.click_boss_notice(mode, self.queue) self.fight_stop() time.sleep(3) audio_play() messagebox.showinfo('就你鬼王多', '发现超鬼王啦!还不快冲鸭!') audio_stop() return elif self._running == 0: return def when_click_start_window(self): when_click_start = Toplevel(self) when_click_start.title('模式说明') var = self.listbox_mode.get() if var == '单刷': title = Label(when_click_start) title['text'] = '\n【 单刷模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n请把游戏调整至如图所示界面,再点START\n' desc['width'] = 300 desc.pack() ipath = resource_path('image/single.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '乘客': title = Label(when_click_start) title['text'] = '\n【 乘客模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议接受了司机的默认邀请,再点START\n' + \ '因为我不会在战斗里帮你点开始...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = resource_path('image/passenger_accept.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.7), load.size))) render = ImageTk.PhotoImage(load) img = Label(when_click_start, image=render) img.image = render img.pack() elif var == '司机': title = Label(when_click_start) title['text'] = '\n【 司机模式 】' title.pack() desc = Message(when_click_start) desc['text'] = '\n建议对乘客发出默认邀请,回到组队界面再点START\n' + \ '因为自动发出邀请这个功能没写...不服憋着\n_(:3」∠)_\n' desc['width'] = 300 desc.pack() ipath = resource_path('image/driver_invite.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img1 = Label(when_click_start, image=render) img1.image = render img1.pack() ipath = resource_path('image/driver_form.png') load = PLI_Image.open(ipath) load = load.resize(tuple(map(lambda x: int(x * 0.5), load.size))) render = ImageTk.PhotoImage(load) img2 = Label(when_click_start, image=render) img2.image = render img2.pack() init_window_position(when_click_start, 1.3, 3) def what_is_clear_time(self): what_is_clear = Toplevel(self) what_is_clear.title('平均通关时间说明') title = Label(what_is_clear) title['text'] = '\n【 平均通关时间 】' title.pack() desc = Message(what_is_clear) desc['text'] = '\n平均通关时间是指在游戏中,从按下开始战斗到进入结算奖励界面所经过的时间(秒)\n' + \ '\n程序会在经过指定的时间后,再开始检测游戏画面是否进入了结算界面\n' + \ '\n如果设置一个较短的时间也可以,不过设置一个合理的时间,能节省你CPU资源\n(其实也没占多少_(:3」∠)_\n' desc['width'] = 300 desc.pack() init_window_position(what_is_clear, 1.3, 3) def what_is_delay_time(self): what_is_delay = Toplevel(self) what_is_delay.title('战斗后等待时间说明') title = Label(what_is_delay) title['text'] = '\n【 战斗后等待时间 】' title.pack() desc = Message(what_is_delay) desc['text'] = '\n战斗后等待时间是指,在下一次战斗开始前强制等待的时间(秒)\n' + \ '\n填入的时间还会加上一个300毫秒以内的随机时间\n' desc['width'] = 300 desc.pack() init_window_position(what_is_delay, 1.3, 3) def create_main(self): """ 窗体、控件绘制 :return: """ self.label_mode['text'] = '模式' self.var_mode.set('单刷') self.listbox_mode['textvariable'] = self.var_mode self.listbox_mode['width'] = 10 self.listbox_mode['values'] = ["单刷", "乘客", "司机"] self.listbox_mode.bind("<<ComboboxSelected>>", self.turn_radio_on) self.label_mode.grid(row=1, column=0, sticky='E') self.listbox_mode.grid(row=1, column=1, sticky='W') self.button_mode_explain['text'] = '?' self.button_mode_explain['command'] = self.when_click_start_window self.button_mode_explain['relief'] = 'flat' self.button_mode_explain.grid(row=1, column=2, sticky='W') self.var_member.set(2) self.label_member['text'] = '车队人数' self.label_member.grid(row=2, column=0, sticky='E') self.radio1['text'] = '2人' self.radio1['variable'] = self.var_member self.radio1['value'] = 2 # self.radio1['command'] = self.test_val3 self.radio1.grid(row=2, column=1, sticky='W') self.radio1.configure(state='disabled') self.radio2['text'] = '3人' self.radio2['variable'] = self.var_member self.radio2['value'] = 3 # self.radio2['command'] = self.test_val3 self.radio2.grid(row=2, column=2, sticky='W') self.radio2.configure(state='disabled') self.label_clear_time['text'] = '平均通关时间' self.var_clear_time.set(self.clear_time) self.entry_clear_time['textvariable'] = self.var_clear_time self.label_clear_time.grid(row=3, column=0, sticky='E') self.entry_clear_time.grid(row=3, column=1, sticky='W', columnspan=2) self.button_clear_time_explain['text'] = '?' self.button_clear_time_explain['command'] = self.what_is_clear_time self.button_clear_time_explain['relief'] = 'flat' self.button_clear_time_explain.grid(row=3, column=2, sticky='E') self.label_delay_time['text'] = '战斗结束后等待时间' self.var_delay_time.set(self.delay_time) self.entry_delay_time['textvariable'] = self.var_delay_time self.label_delay_time.grid(row=4, column=0, sticky='E') self.entry_delay_time.grid(row=4, column=1, sticky='W', columnspan=2) self.button_delay_time_explain['text'] = '?' self.button_delay_time_explain['command'] = self.what_is_delay_time self.button_delay_time_explain['relief'] = 'flat' self.button_delay_time_explain.grid(row=4, column=2, sticky='E') self.label_offer['text'] = '好友发来悬赏' self.var_offer_mode.set('接受') self.listbox_offer_mode['textvariable'] = self.var_offer_mode self.listbox_offer_mode['width'] = 10 self.listbox_offer_mode['values'] = ["接受", "拒绝"] # self.listbox_offer_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_offer.grid(row=5, column=0, sticky='E') self.listbox_offer_mode.grid(row=5, column=1, sticky='W') self.label_timing_mode['text'] = '预定结束' self.var_timing_mode.set('无') self.listbox_timing_mode['textvariable'] = self.var_timing_mode self.listbox_timing_mode['width'] = 10 self.listbox_timing_mode['values'] = [ "无", "定时[分钟]", "场数", "超鬼王模式1", "超鬼王模式2" ] self.listbox_timing_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_timing_mode.grid(row=6, column=0, sticky='E') self.listbox_timing_mode.grid(row=6, column=1, sticky='W') self.var_timing_value.set('') self.entry_timing_value['textvariable'] = self.var_timing_value self.entry_timing_value['width'] = 5 self.entry_timing_value.configure(state='disabled') self.entry_timing_value.grid(row=6, column=2, sticky='W') self.label_done_action_mode['text'] = '预定结束后动作' self.var_done_action_mode.set('') self.listbox_done_action_mode[ 'textvariable'] = self.var_done_action_mode self.listbox_done_action_mode['width'] = 10 self.listbox_done_action_mode.configure(state='disabled') self.listbox_done_action_mode['values'] = ["关闭游戏窗口", "仅停止挂机"] # self.listbox_done_action_mode.bind("<<ComboboxSelected>>", self.turn_entry_on) self.label_done_action_mode.grid(row=7, column=0, sticky='E') self.listbox_done_action_mode.grid(row=7, column=1, sticky='W') self.start_ctn['text'] = 'START' self.start_ctn['width'] = 10 self.start_ctn['height'] = 2 self.start_ctn['command'] = self.fight_start self.start_ctn['relief'] = 'groove' self.start_ctn.grid(row=0, column=0, sticky='E') self.stop_ctn['text'] = 'STOP' self.stop_ctn['width'] = 10 self.stop_ctn['height'] = 2 self.stop_ctn['command'] = self.fight_stop self.stop_ctn['relief'] = 'groove' self.stop_ctn.grid(row=0, column=1, sticky='W') self.stop_ctn.configure(state='disabled') self.info_box['width'] = 40 self.info_box['height'] = 20 self.info_box.grid(row=1, column=0, columnspan=2) self.info_box.see(END) var = 'Build ' + self.version self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END) var = '请授予此程序管理员权限运行,否则在游戏窗口内鼠标无法被控制' self.info_box.mark_set('insert', END) self.info_box.insert('insert', str(var) + '\n') self.info_box.see(END)
class SpinDelight(Frame): def __init__(self): Frame.__init__(self) self.master.geometry("1020x600+150+50") self.master.title("Spin Delight 1.0 - Copyright (c) Robin Thomas") self.master.resizable(0,0) self.grid() self.brwe = Button(self, text = "Browse", command = self.open_file, width = 10, relief = "groove") self.rtxt = Label(self, text="Input Text:") self.txt1 = ScrolledText(self, width = 50, height = 25) self.txt1.bind("<Control-Key-a>", self.select_all_txt1) self.txt1.bind("<Control-Key-A>", self.select_all_txt1) self.spin = Button(self, text = "Spin", command = self.spin_file, width = 10, relief = "groove") self.stxt = Label(self, text="Spun Text:") self.txt2 = ScrolledText(self, width = 50, height = 25) self.txt2.bind("<Control-Key-a>", self.select_all_txt2) self.txt2.bind("<Control-Key-A>", self.select_all_txt2) self.brwe.grid(row = 2, column = 2, pady = 15) self.rtxt.grid(row = 2, column = 0, padx = 25) self.txt1.grid(row = 3, column = 0, columnspan = 10, padx = 25) self.spin.grid(row = 3, column = 12) self.stxt.grid(row = 2, column = 13, padx = 25, pady = 5) self.txt2.grid(row = 3, column = 13, columnspan = 10, padx = 25) def select_all_txt1(self,event): self.txt1.tag_add(SEL, "1.0", END) self.txt1.mark_set(INSERT, "1.0") self.txt1.see(INSERT) return 'break' def select_all_txt2(self,event): self.txt2.tag_add(SEL, "1.0", END) self.txt2.mark_set(INSERT, "1.0") self.txt2.see(INSERT) return 'break' def open_file(self): fname = askopenfilename(filetypes=(("Text files", "*.txt"), ("All files", "*.*") )) if fname: try: self.txt1.delete(0.0, END) f = open(fname,'r') self.txt1.insert(INSERT,f.read()) except: showerror("Open Source File", "Failed to read file\n'%s'" % fname) def spin_file(self): txt = self.txt1.get("1.0", END) self.txt2.delete(0.0, END) if len(txt): try: words = sub(r'([.,?])+', r' \1 ', sub(r'[^a-zA-Z0-9 .,?]+', ' ', txt)).split() w1 = words[0] z = [(words[j - 1], words[j]) for j in range(1, len(words))] values = self.generate_dict(z, w1) string = self.generate_sent(values) if len(string): self.txt2.insert(INSERT, string) else: showerror("Error", "Insufficient data to spin !!") except: showerror("Error", "Nothing to spin !!") def generate_dict(self, x, w1): values = {'.': [w1]} for (wa, wb) in x: if wa in values: values[wa].append(wb) else: values[wa] = [wb] return values def generate_sent(self, values): w1 = '.' w2 = choice(values[w1]) string = w2 values[w1].remove(w2) while values: w1 = w2 if len(values[w1]): w2 = choice(values[w1]) else: del values[w1] w1 = '.' break if w2 in ('.', ',', '?'): string += w2 else: string += " " + w2 values[w1].remove(w2) return string
class EditorWindow: def __init__(self): self.root = Tk(className="EDITOR") self.python_files = PythonFiles(self) self.root.geometry("%dx%d+%d+%d" % ( self.root.winfo_screenwidth() * 0.5, self.root.winfo_screenheight() * 0.4, # self.root.winfo_screenwidth() * 0.1, self.root.winfo_screenheight() * 0.1 0, 0)) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.base_title = "PyEditor v%s" % __version__ self.root.title(self.base_title) self.text_frame = Frame(master=self.root) self.text = ScrolledText(master=self.root, background="white") self.text.bind("<Tab>", self.tab_event) self.text.grid(row=0, column=0, sticky=NSEW) #TODO: find a right height self.exec_output = ScrolledText(master=self.root, height=10, state=DISABLED, background="#dddddd") # for information text like load/save/run: self.exec_output.tag_config( "info", foreground="#0000ff", #background="#eeeeee" ) self.exec_output.grid(row=1, column=0, sticky=NSEW) self.text.focus_set() # self.script_list = ScriptList(self) p = Percolator(self.text) d = ColorDelegator() p.insertfilter(d) # add statusbar to window self.init_statusbar() # add menu to window self.init_menu() # Add special RPi/Minecraft features, if available self.rpi = MinecraftSpecials(self) if self.rpi.mcpi_available: # minecraft is available self.set_content(DEFAULT_MCPI_SCRIPT) if not self.rpi.is_running: self.rpi.startup_minecraft() else: # no minecraft available self.set_content(DEFAULT_SCRIPT) self.root.update() ########################################################################### # Status bar FILENAME_LABEL = "filename" def get_filename(self): filename = self.status_bar.get_textEntry(self.FILENAME_LABEL) return filename def set_filename(self, filename): filename = os.path.split(filename)[-1] self.status_bar.set_textEntry(self.FILENAME_LABEL, filename) def update_filename(self, event=None): filename = self.get_filename() if filename and not filename.endswith(".py"): filename = "%s.py" % filename self.set_filename(filename) def init_statusbar(self): self.status_bar = MyMultiStatusBar(self.root) if sys.platform == "darwin": # Insert some padding to avoid obscuring some of the statusbar # by the resize widget. self.status_bar.set_label('_padding1', ' ', side=RIGHT) self.status_bar.grid(row=2, column=0) self.text.bind("<<set-line-and-column>>", self.set_line_and_column) self.text.event_add("<<set-line-and-column>>", "<KeyRelease>", "<ButtonRelease>") self.text.after_idle(self.set_line_and_column) self.status_bar.new_textEntry(self.FILENAME_LABEL, 'unnamed.py', callback=self.update_filename) def set_line_and_column(self, event=None): line, column = self.text.index(INSERT).split('.') self.status_bar.set_label('column', 'Column: %s' % column) self.status_bar.set_label('line', 'Line: %s' % line) ########################################################################### # Menu def init_menu(self): self.menubar = Menu(self.root) filemenu = Menu(self.menubar, tearoff=0) self.menubar.add_command(label="Run", command=self.command_run) self.menubar.add_command(label="Load", command=self.command_load_file) # filemenu.add_command(label="Load", command=self.command_load_file) self.menubar.add_command(label="Save", command=self.command_save_file) self.menubar.add_command(label="Exit", command=self.root.quit) # # self.menubar.add_cascade(label="File", menu=filemenu) self.root.config(menu=self.menubar) def command_run(self): source_listing = self.get_content() self.exec_output.config(state=NORMAL) self.exec_output.delete("1.0", END) filename = self.get_filename() self.python_files.run_source_listing(source_listing, filename) log.debug("Adding to terminal out") #self.exec_output.insert(END, "Run Script") self.exec_output.config(state=DISABLED) def command_load_file(self): infile = askopenfile( parent=self.root, mode="r", title="Select a Python file to load", filetypes=DEFAULT_FILETYPES, initialdir=BASE_PATH, ) if infile is not None: source_listing = infile.read() infile.close() self.set_content(source_listing) self.set_filename(infile.name) # FIXME: insert only name! self.append_feedback_to_output("Script %r loaded." % infile.name) def command_save_file(self): self.update_filename() # FIXME: add .py if missing content = self.get_content() filename = self.get_filename() filepath = os.path.join(BASE_PATH, filename) if os.path.isfile(filepath): self.python_files.move_to_backup(filepath) with open(filepath, "w") as f: f.write(content) self.append_feedback_to_output("Save to: %r" % filepath) ########################################################################### def get_content(self): content = self.text.get("1.0", END) content = content.strip() return content def set_content(self, source_listing): self.text.delete("1.0", END) log.critical("insert %i Bytes listing.", len(source_listing)) self.text.insert(END, source_listing) self.text.mark_set(INSERT, '1.0') # Set cursor at start self.text.focus() def append_exec_output(self, text): self.exec_output.config(state=NORMAL) self.exec_output.insert(END, text) self.exec_output.config(state=DISABLED) def append_feedback_to_output(self, text): text = "%s\n" % text.rstrip() self.exec_output.config(state=NORMAL) self.exec_output.insert(END, text, "info") self.exec_output.config(state=DISABLED) ########################################################################### indent_pad = " " * 4 def tab_event(self, event): log.debug("Tab event") self.text.insert("insert", self.indent_pad) return BREAK
class PiDiteur(Frame): def __init__(self, parent=None, nom_fichier=None): Frame.__init__(self, parent) self.pack(expand=YES, fill=BOTH) self.fichier_courant = nom_fichier self.nom_editeur = self.__class__.__name__ self.creer_composants() self.gerer_evenements() self.afficher_fichier(nom_fichier) def creer_composants(self): self.creer_zone_texte() self.creer_barre_menu() self.creer_barre_texte() def creer_zone_texte(self): self.zone_texte = ScrolledText( self, padx=5, pady=5, wrap=WORD, relief=SUNKEN, font=('courier', 14, 'normal'), bg='white', fg='black', undo=True, autoseparators=True, ) self.zone_texte.pack(side=TOP, fill=BOTH, expand=YES) def creer_barre_texte(self): self.barre_texte = Label(self, relief=SUNKEN, bd=2) self.barre_texte.pack(side=BOTTOM, fill=X) def creer_barre_menu(self): self.barre_menu = Menu(self.master) self.master.config(menu=self.barre_menu) self.menu_fichier() self.menu_editer() def menu_fichier(self): menu = Menu(self.barre_menu, tearoff=False) menu.add_command(label='Ouvrir (Ctrl+o)', command=self.ouvrir) menu.add_command(label='Nouveau (Ctrl+n)', command=self.afficher_fichier) menu.add_command(label='Enregistrer (Ctrl+s)', command=self.enregistrer) menu.add_command(label='Enregistrer sous', command=self.enregistrer_sous) menu.add_command(label='Fermer (Alt+F4)', command=self.quitter) self.barre_menu.add_cascade(label='Fichier', menu=menu) def menu_editer(self): menu = Menu(self.barre_menu, tearoff=False) menu.add_command(label='Couper (Ctrl+x)', command=lambda: self.copier(True)) menu.add_command(label='Copier (Ctrl+c)', command=self.copier) menu.add_command(label='Coller (Ctrl+v)', command=self.coller) menu.add_command(label='Chercher (Ctrl+f)', command=self.chercher) self.barre_menu.add_cascade(label='Edition', menu=menu) def gerer_evenements(self): self.master.bind('<Control-Key-f>', lambda ev: self.chercher()) self.master.bind('<Control-Key-o>', lambda ev: self.ouvrir()) self.master.bind('<Control-Key-s>', lambda ev: self.enregistrer()) self.master.bind('<Control-Key-n>', lambda ev: self.afficher_fichier()) self.master.protocol("WM_DELETE_WINDOW", self.quitter) def afficher_fichier(self, nom_fichier=None): if nom_fichier: with open(nom_fichier, 'r', encoding='utf-8') as f: texte = f.read() self.barre_texte.config(text=nom_fichier) self.master.title('%s - %s' % (self.nom_editeur, nom_fichier)) else: texte = '' nouveau = 'Nouveau fichier' self.barre_texte.config(text=nouveau) self.master.title('%s - %s' % (self.nom_editeur, nouveau)) self.fichier_courant = nom_fichier self.zone_texte.delete('0.0', END) self.zone_texte.insert('0.0', texte) self.zone_texte.mark_set(INSERT, '0.0') self.zone_texte.focus() self.update() def ouvrir(self): fichier = askopenfilename() if fichier: self.afficher_fichier(nom_fichier=fichier) def enregistrer(self): if not self.fichier_courant: fichier = asksaveasfilename() if fichier: self.fichier_courant = fichier else: return fichier = self.fichier_courant texte = self.zone_texte.get('0.0', END) with open(fichier, 'w', encoding='utf-8') as f: f.write(texte) self.barre_texte.config(text=fichier) self.master.title('%s - %s' % (self.nom_editeur, fichier)) def enregistrer_sous(self): fichier = asksaveasfilename() if fichier: self.fichier_courant = fichier self.enregistrer() def copier(self, couper=False): try: texte = self.zone_texte.get(SEL_FIRST, SEL_LAST) except TclError: showinfo(message='Selectionnez du texte à copier !') return if couper: self.zone_texte.delete(SEL_FIRST, SEL_LAST) self.clipboard_clear() self.clipboard_append(texte) def coller(self): try: texte = self.selection_get(selection='CLIPBOARD') self.zone_texte.insert(INSERT, texte) except TclError: pass def chercher(self): caractere = askstring('Recherche', 'Tapez votre chaîne de caractères :') if caractere: trouve = self.zone_texte.search(caractere, INSERT, END) if trouve: aprestrouve = trouve + ('+%dc' % len(caractere)) self.zone_texte.tag_add(SEL, trouve, aprestrouve) self.zone_texte.mark_set(INSERT, aprestrouve) self.zone_texte.see(INSERT) self.zone_texte.focus() def quitter(self): if askyesno( 'Confirmation', 'Voulez-vous vraiment fermer {0} ?'.format(self.nom_editeur)): Frame.quit(self)
class LogView(ttk.Frame): """ Widget for the program log messages, ttk Frame implementation. :ivar List[MessageType] message_types: the MessageTypes to include in the filter combobox :ivar List[MessageType] all_types: a list of all the message types :ivar List[MessageDelay] message_delays: a list of all of the message delays :ivar Dict[str: collections.deque] messages: mapping of message type title string to dequeues of fixed size containing messages' body :ivar Dict[str: float] message_time: message body without timestamp mapped to time in s :ivar Dict[str: MessageDelay] message_time_filer: message body without timestamp mapped to MessageDelay :ivar float first_click_time: the time the header text was first clicked (Used for developer messages) :ivar int num_clicks: the number of times the header text was clicked within the specified time (Used for dev msgs) :ivar bool showing: True if developer messages are in the filter, False otherwise :ivar MessageType current_filter: the current message type to filter messages :ivar ttk.Combobox filter_box: the combobox tkinter widget used for selecting a filter level :ivar ttk.ScrolledText log_view: the scrolled text tkinter widget used for displaying log messages """ def __init__(self, container: ttk.Frame, **kwargs): """ Setup the log view widgets, and the data structures for storing messages. :param container: parent frame :param kwargs: additional arguments for the Frame """ super().__init__(container, **kwargs) self.message_types = [ MessageType.INFO, MessageType.WARNING, MessageType.ERROR ] self.all_types = self.message_types + [ MessageType.CRITICAL, MessageType.DEVELOPER ] self.message_delays = [ MessageDelay.FIRST, MessageDelay.SHORT, MessageDelay.LONG, MessageDelay.MAX ] self.messages = {} self.message_time = SizeDict(maxsize=1000) # type: Dict[str, float] self.message_time_filter = SizeDict( maxsize=1000) # type: Dict[str, MessageDelay] self.first_click_time = time.time() self.num_clicks = 0 self.showing = False self.current_filter = MessageType.INFO for t in self.all_types: self.messages[t.name.title()] = collections.deque(maxlen=25000) self.pack() header_frame = ttk.Frame(self) header_frame.pack(expand=True, fill=tk.BOTH) header_lbl = ttk.Label(header_frame, text="Program Log") header_lbl.pack(anchor=tk.W, side=tk.LEFT) header_lbl.bind("<Button-1>", self.click_handler) self.filter_box = ttk.Combobox( header_frame, values=[_type.name.title() for _type in self.message_types]) self.filter_box.config(state="readonly") self.filter_box.set(MessageType.INFO.name.title()) self.filter_box.pack(anchor=tk.E, side=tk.RIGHT) self.filter_box.bind("<<ComboboxSelected>>", self.filter_msg) self.filter_box.pack(anchor=tk.E) self.log_view = ScrolledText(self, wrap=tk.WORD, background=LOG_BACKGROUND_COLOR) for t in self.all_types: self.log_view.tag_configure(t.name, font=Font(family="Helvetica", size=10), foreground=t.color) self.log_view.pack(expand=True, fill=tk.BOTH) ttk.Button(self, text="Export", command=self.export).pack(anchor=tk.CENTER) def click_handler(self, _): """Click handler for the Program Log header to allow the user to view developer messages.""" if time.time() - self.first_click_time > 15.: self.first_click_time = time.time() self.num_clicks = 0 else: self.num_clicks += 1 if self.num_clicks == 10: self.num_clicks = 0 if not self.showing: self.message_types.append(MessageType.DEVELOPER) else: self.message_types.remove(MessageType.DEVELOPER) self.showing = not self.showing self.filter_box.config( values=[_type.name.title() for _type in self.message_types]) def export(self): """Export the messages to a log text file in the log folder.""" t = time.time() timestamp = datetime.datetime.fromtimestamp(t).strftime( "%Y%m%dT%H%M%S") if not os.path.isdir("log"): os.mkdir("log") with open(os.path.join("log", "{}_log.txt".format(str(timestamp))), "w") as f: _type = MessageType.INFO.filter_num if MessageType.DEVELOPER in self.message_types: _type = MessageType.DEVELOPER.filter_num msgs = self.get_msgs(_type) msgs_sorted = sort_messages(msgs) for t, (text, tag) in msgs_sorted: f.write(text) def clear(self): """Clear the log view scrolled text.""" self.log_view.config(state='normal') for t in self.all_types: try: self.log_view.tag_remove(t.name, "1.0", tk.END) except tk.TclError: pass self.log_view.delete("1.0", tk.END) def add_msg(self, msg: Message): """ Add the msg to the log view, and the message store data structures. :param msg: message to add to the log view """ self.message_time[msg.msg] = msg.time self.messages[msg.type.name.title()].append((msg.time, msg.text)) if msg.type.filter_num <= self.current_filter.filter_num: self.write_msg(msg.text, msg.type.name) def write_msg(self, text: str, tag: str, start: str = "1.0"): """ Write the text to the Scrolled Text tkinter widget, color it based on the tag, add it to the beginning if start is '1.0', if start tk.END add it to the end. :param text: text to write to the scrolled text view :param tag: name of the tag that defines the style for the text, based on MessageType :param start: the position to start writing the text """ self.log_view.config(state='normal') self.log_view.insert(start, text) self.highlight_pattern(text, tag) self.log_view.config(state='disabled') def highlight_pattern(self, pattern: str, tag: str, start: str = "1.0", end: str = "end", regexp: bool = False): """ Apply the given tag to all text that matches the given pattern. :param pattern: pattern to match when looking to format the text using the tag. :param tag: tkinter scrolled text tag corresponding to a tk font :param start: where to start looking for the pattern from :param end: where to end looking for the pattern :param regexp: If True, pattern will be treated as a Tcl regular expression """ start = self.log_view.index(start) end = self.log_view.index(end) self.log_view.mark_set("matchStart", start) self.log_view.mark_set("matchEnd", start) self.log_view.mark_set("searchLimit", end) count = tk.IntVar() while True: index = self.log_view.search(pattern, "matchEnd", "searchLimit", count=count, regexp=regexp) if index == "": break if count.get() == 0: break self.log_view.mark_set("matchStart", index) self.log_view.mark_set("matchEnd", "%s+%sc" % (index, count.get())) self.log_view.tag_add(tag, "matchStart", "matchEnd") def get_msgs(self, filter_num: int) -> collections.OrderedDict: """ Get all of the messages that have a filter number less than or equal the filter number. :param filter_num: the number used for filtering messages :return: time mapped to (text, tag) for all filtered messages """ msgs = {} for _type in self.all_types: if _type.filter_num <= filter_num: for msg in self.messages[_type.name.title()]: msgs[msg[0]] = (msg[1], _type.name) return collections.OrderedDict(msgs.items(), key=lambda t: t[0]) def filter_msg(self, _): """Filters messages when the filter combobox value is changed.""" for t in self.all_types: selection = self.filter_box.current() if t.name.title() == self.message_types[selection].name.title(): self.current_filter = t msgs = self.get_msgs(self.current_filter.filter_num) self.clear() msgs_sorted = sort_messages(msgs) for t, (text, tag) in msgs_sorted: self.write_msg(text, tag, start=tk.END)
class PiDiteur(Frame): def __init__(self, parent=None, nom_fichier=None): Frame.__init__(self, parent) self.pack(expand=YES, fill=BOTH) self.fichier_courant = nom_fichier self.nom_editeur = self.__class__.__name__ self.creer_composants() self.gerer_evenements() self.afficher_fichier(nom_fichier) def creer_composants(self): self.creer_zone_texte() self.creer_barre_menu() self.creer_barre_texte() def creer_zone_texte(self): self.zone_texte = ScrolledText( self, padx=5, pady=5, wrap=WORD, relief=SUNKEN, font=("courier", 14, "normal"), bg="white", fg="black", undo=True, autoseparators=True, ) self.zone_texte.pack(side=TOP, fill=BOTH, expand=YES) def creer_barre_texte(self): self.barre_texte = Label(self, relief=SUNKEN, bd=2) self.barre_texte.pack(side=BOTTOM, fill=X) def creer_barre_menu(self): self.barre_menu = Menu(self.master) self.master.config(menu=self.barre_menu) self.menu_fichier() self.menu_editer() def menu_fichier(self): menu = Menu(self.barre_menu, tearoff=False) menu.add_command(label="Ouvrir (Ctrl+o)", command=self.ouvrir) menu.add_command(label="Nouveau (Ctrl+n)", command=self.afficher_fichier) menu.add_command(label="Enregistrer (Ctrl+s)", command=self.enregistrer) menu.add_command(label="Enregistrer sous", command=self.enregistrer_sous) menu.add_command(label="Fermer (Alt+F4)", command=self.quitter) self.barre_menu.add_cascade(label="Fichier", menu=menu) def menu_editer(self): menu = Menu(self.barre_menu, tearoff=False) menu.add_command(label="Couper (Ctrl+x)", command=lambda: self.copier(True)) menu.add_command(label="Copier (Ctrl+c)", command=self.copier) menu.add_command(label="Coller (Ctrl+v)", command=self.coller) menu.add_command(label="Chercher (Ctrl+f)", command=self.chercher) self.barre_menu.add_cascade(label="Edition", menu=menu) def gerer_evenements(self): self.master.bind("<Control-Key-f>", lambda ev: self.chercher()) self.master.bind("<Control-Key-o>", lambda ev: self.ouvrir()) self.master.bind("<Control-Key-s>", lambda ev: self.enregistrer()) self.master.bind("<Control-Key-n>", lambda ev: self.afficher_fichier()) self.master.protocol("WM_DELETE_WINDOW", self.quitter) def afficher_fichier(self, nom_fichier=None): if nom_fichier: with open(nom_fichier, "r", encoding="utf-8") as f: texte = f.read() self.barre_texte.config(text=nom_fichier) self.master.title("%s - %s" % (self.nom_editeur, nom_fichier)) else: texte = "" nouveau = "Nouveau fichier" self.barre_texte.config(text=nouveau) self.master.title("%s - %s" % (self.nom_editeur, nouveau)) self.fichier_courant = nom_fichier self.zone_texte.delete("0.0", END) self.zone_texte.insert("0.0", texte) self.zone_texte.mark_set(INSERT, "0.0") self.zone_texte.focus() self.update() def ouvrir(self): fichier = askopenfilename() if fichier: self.afficher_fichier(nom_fichier=fichier) def enregistrer(self): if not self.fichier_courant: fichier = asksaveasfilename() if fichier: self.fichier_courant = fichier else: return fichier = self.fichier_courant texte = self.zone_texte.get("0.0", END) with open(fichier, "w", encoding="utf-8") as f: f.write(texte) self.barre_texte.config(text=fichier) self.master.title("{} - {}".format(self.nom_editeur, fichier)) def enregistrer_sous(self): fichier = asksaveasfilename() if fichier: self.fichier_courant = fichier self.enregistrer() def copier(self, couper=False): try: texte = self.zone_texte.get(SEL_FIRST, SEL_LAST) except TclError: showinfo(message="Selectionnez du texte à copier !") return if couper: self.zone_texte.delete(SEL_FIRST, SEL_LAST) self.clipboard_clear() self.clipboard_append(texte) def coller(self): try: texte = self.selection_get(selection="CLIPBOARD") self.zone_texte.insert(INSERT, texte) except TclError: pass def chercher(self): caractere = askstring("Recherche", "Tapez votre chaîne de caractères :") if caractere: trouve = self.zone_texte.search(caractere, INSERT, END) if trouve: aprestrouve = trouve + ("+%dc" % len(caractere)) self.zone_texte.tag_add(SEL, trouve, aprestrouve) self.zone_texte.mark_set(INSERT, aprestrouve) self.zone_texte.see(INSERT) self.zone_texte.focus() def quitter(self): if askyesno("Confirmation", f"Voulez-vous vraiment fermer {self.nom_editeur} ?"): Frame.quit(self)
class EditorTab(tk.Frame): def __init__(self, master, filepath: str, new_file=False): tk.Frame.__init__(self, master) self.new_file = new_file self.filepath = filepath self.filename = get_filename(filepath) if not new_file else filepath self.master = master self.modified = False self.text_editor = ScrolledText(self, font=("", 15), undo=True, maxundo=-1, wrap="none") self.text_editor.config(highlightthickness=0, bd=0) self.text_editor.grid(row=0, column=1, sticky=tk.NSEW) self.scrollbar_x = tk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.text_editor.xview) self.scrollbar_x.grid(row=1, column=0, columnspan=2, stick=tk.EW) self.text_editor.configure(xscrollcommand=self.scrollbar_x.set) self.line_nb_canvas = tk.Canvas(self, bg=self.text_editor.cget("bg"), bd=0, highlightthickness=0) self.line_nb_canvas.grid_propagate(False) self.line_nb_canvas.grid(row=0, column=0, sticky=tk.NS) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) self.default_file_content = str() @property def id(self) -> str: return str(self) def get(self) -> str: return self.text_editor.get("1.0", "end-1c") @property def lines(self): return self.get().splitlines() def update_lines(self): self.line_nb_canvas.delete("all") font = self.text_editor.cget("font") i = 1 y = 0 while self.text_editor.compare(f"{i}.0", "<", tk.END): dline = self.text_editor.dlineinfo(f"{i}.0") if dline: y = dline[1] else: y = -20 self.line_nb_canvas.create_text(1, y, anchor="ne", text=str(i), font=font, fill=Color(175, 175, 175).hex) i += 1 all_boxes = [ self.line_nb_canvas.bbox(item) for item in self.line_nb_canvas.find_all() ] max_width = (min(box[2] - box[0] for box in all_boxes)) * 4 self.line_nb_canvas.configure(width=max_width + 20) for item in self.line_nb_canvas.find_all(): self.line_nb_canvas.move(item, max_width, 0) def get_filename_from_champion_name(self) -> (str, None): content = self.lines for line in content: if line.startswith(".name"): first_quote = line.find('"') if first_quote == -1: break second_quote = line.find('"', first_quote + 1) if second_quote == -1: break name = line[first_quote + 1:second_quote] if len(name) == 0: break return name.replace(" ", "_").lower() + ".s" return None def open(self) -> bool: if not os.path.isfile(self.filepath): showwarning("An error occurs...", f"Can't open '{self.filepath}'") return False with open(self.filepath, "r") as file: self.default_file_content = file.read() self.text_editor.insert("1.0", self.default_file_content) self.text_editor.edit_reset() self.text_editor.edit_modified(False) self.set_modified_status(False, on_opening=True) return True def save(self) -> bool: if self.new_file: return self.master.save_file_as() self.default_file_content = self.text_editor.get("1.0", "end-1c") with open(self.filepath, "w") as file: file.write(self.default_file_content) self.set_modified_status(False) self.text_editor.edit_modified(False) return True def save_as(self, filepath: str) -> bool: self.master.files_opened[filepath] = self.master.files_opened[ self.filepath] self.master.files_opened.pop(self.filepath) self.filepath = filepath self.filename = get_filename(filepath) self.new_file = False return self.save() def close(self) -> bool: if self.modified: save_file = askyesnocancel( f"{self.filename} - Modifications not saved", "This file was modified and was not saved.\nDo you want to save this file ?" ) if save_file is None: return False if save_file and not self.save(): return False self.master.forget(self.id) self.master.files_opened.pop(self.filepath) return True def undo(self) -> None: try: self.text_editor.edit_undo() except tk.TclError: pass def redo(self) -> None: try: self.text_editor.edit_redo() except tk.TclError: pass def copy_to_clipboard(self, remove_from_editor=False) -> bool: try: txt = self.text_editor.get("sel.first", "sel.last") self.clipboard_clear() self.clipboard_append(txt) if remove_from_editor: self.text_editor.delete("sel.first", "sel.last") except tk.TclError: return False return True def paste_from_clipboard(self) -> None: try: self.text_editor.get("sel.first", "sel.last") except tk.TclError: pass else: self.text_editor.mark_set("insert", "sel.first") self.text_editor.delete("sel.first", "sel.last") self.text_editor.insert("insert", self.clipboard_get()) def check_file_status(self) -> None: actual = self.text_editor.get("1.0", "end-1c") if self.text_editor.edit_modified(): self.text_editor.edit_separator() self.text_editor.edit_modified(False) self.set_modified_status(actual != self.default_file_content) def set_modified_status(self, status: bool, on_opening=False) -> None: self.modified = status if not on_opening: if self.modified and not self.new_file: self.master.tab(self.id, text=self.filename + " - Modified") else: self.master.tab(self.id, text=self.filename) def add(self) -> None: self.master.add(self, text=self.filename) def select(self) -> None: self.master.select(self.id) self.text_editor.focus_set() def set_template(self, name: str, comment: str, author: str) -> None: content = [ line for line in self.lines if not line.startswith(".name") and not line.startswith(".comment") ] header = [ "#", "# {name} champion for CoreWar".format(name=name), "#", "# By {author}".format(author=author), "#", "# {date}".format(date=date.today().strftime("%c")), "#", "" ".name \"{name}\"".format(name=name), ".comment \"{comment}\"".format(comment=comment), "" ] content = header + content self.text_editor.delete("1.0", "end") self.text_editor.insert("1.0", "\n".join(content)) def insert_command(self, cmd: str) -> None: insert = self.text_editor.index(tk.INSERT).split(".") end_of_line = insert[0] + "." + tk.END self.text_editor.insert(end_of_line, "\n" + cmd)
class GroceryProgram: def __init__(self, master, email_config: EmailAccessBase = None, wunderpy_config: WunderpyAccessBase = None, inital_grocery_content: str = ''): self.inital_menu_content = inital_grocery_content self.wunderpy_config = wunderpy_config self.email_config = email_config self.master = master self.master.wm_title('Grocery shopping') self.master.geometry('1000x500') self.current_menu = None # Grid definition: tk.Grid.rowconfigure(self.master, 0, weight=1) tk.Grid.columnconfigure(self.master, 0, weight=1) frame = tk.Frame(self.master) frame.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W) grid = tk.Frame(frame) grid.grid(sticky=tk.N + tk.S + tk.E + tk.W, column=0, row=0) tk.Grid.rowconfigure(frame, 0, weight=1) tk.Grid.columnconfigure(frame, 0, weight=1) ## Grocery list self.grocery_list = ScrolledText(frame, undo=True) self.grocery_list.grid(rowspan=2, columnspan=1, row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) # Set callback on all key presses: bindtags = list(self.grocery_list.bindtags()) bindtags.insert(2, "custom") # index 1 is where most default bindings live self.grocery_list.bindtags(tuple(bindtags)) self.grocery_list.bind_class("custom", "<Key>", self.callback_any_key_grocery_list) self.grocery_list.bind('<Control-Return>', self.callback_controll_return_grocery_list) self.grocery_list.bind('<Control-BackSpace>', self.callback_get_recipe_from_parsed) # self.grocery_list.bind('<Key>', self.callback_parse_grocery_list) # set initial grocery_list: self.grocery_list.insert(tk.INSERT, inital_grocery_content) ## Menu list self.menu_box = ScrolledText(frame, undo=True) self.menu_box.grid(rowspan=2, columnspan=3, row=0, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) ## View menu self.view_menu_button = tk.Button(frame, text='View menu', command=self.callback_view_menu) self.view_menu_button.grid(rowspan=1, columnspan=1, row=2, column=0, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) ## View grocery list self.view_grocery_list = tk.Button(frame, text='View grocery list', command=self.callback_view_grocery_list) self.view_grocery_list.grid(rowspan=1, columnspan=1, row=3, column=0, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) ## View categories self.categories_button = tk.Button(frame, text='View categories', command=self.calback_show_categories_list) self.categories_button.grid(rowspan=1, columnspan=1, row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) ## Commands self.command_text = tk.Label(frame, text='Ctrl+Enter: Reroll recipe suggestion.\nCtrl+Backspace: Lock suggestion.') self.command_text.grid(rowspan=1, columnspan=1, row=3, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) ## Email recipients self.email_target_entry = tk.Entry(frame) self.email_target_entry.grid(rowspan=1, columnspan=1, row=2, column=2, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) if self.email_config: self.email_target_entry.insert(tk.INSERT, ', '.join(self.email_config.recipients)) ## Send email_sender button self.email_button = tk.Button(frame, text='Send menu to email_sender', command=self.callback_send_menu_to_email) self.email_button.grid(rowspan=1, columnspan=1, row=2, column=3, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) if not self.email_config: self.email_button['state'] = tk.DISABLED ## Wunderlist target entry self.wunderlist_target_entry = tk.Entry(frame) self.wunderlist_target_entry.grid(rowspan=1, columnspan=1, row=3, column=2, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) if self.wunderpy_config: self.wunderlist_target_entry.insert(tk.INSERT, self.wunderpy_config.default_list) ## Send to wunderlist button: self.send_to_wunderlist_button = tk.Button(frame, text='Send groceries to Wunderlist', command=self.callback_send_to_wunderlist_button) self.send_to_wunderlist_button.grid(rowspan=1, columnspan=1, row=3, column=3, sticky=tk.N + tk.S + tk.E + tk.W, padx=10, pady=10) if not self.wunderpy_config: self.send_to_wunderlist_button['state'] = tk.DISABLED rows = range(3) columns = [] for row in rows: tk.Grid.rowconfigure(frame, row, weight=1) for column in columns: tk.Grid.columnconfigure(frame, column, weight=1) self.parse_grocery_list() def callback_get_recipe_from_parsed(self, event): cursor_position = self.grocery_list.index(tk.INSERT) row = int(cursor_position.split('.')[0]) corresponding_line = self.menu_box.get(1.0, tk.END).split('\n')[row - 1] all_lines = self.grocery_list.get(1.0, tk.END).split('\n') # Swap line: all_lines[row - 1] = corresponding_line self.grocery_list.delete(1.0, tk.END) self.grocery_list.insert(tk.INSERT, '\n'.join(all_lines)) self.grocery_list.mark_set(tk.INSERT, cursor_position) print("I've hit control+backspace at row {0} and column {1}".format( *self.grocery_list.index(tk.INSERT).split('.'))) return 'break' def callback_send_menu_to_email(self): print('send menu by email_sender button') sender = 'GroceryProgram' recipients = self.email_target_entry.get().split(', ') text = html.escape(self.current_menu.generate_menu_str(), quote=True) template = '<html><pre><font face="Courier New, Courier, monospace">%s</font></pre></html>' % text template = template.replace('\n', '<br />') send_email(self.email_config, 'Week menu', recipients, template) print('email_sender ok') def callback_send_to_wunderlist_button(self): print('send to wunderlist button') target_list = self.wunderlist_target_entry.get() # Create a list of {item, description} for all groceries processed_groceries = [] for grocery in self.current_menu.groceries.components(): item = '' if grocery['amount']: item += grocery['amount'] + ' ' item += grocery['name'] descriptions = [] for source_dict in grocery['components']: source = '' source_name = '' if source_dict['amount']: source_name += source_dict['amount'] + ' ' source_name += source_dict['name'] source += source_name if source_dict['comments']: comments = '(' + ', '.join(source_dict['comments']) + ')' source += comments + ' ' if source_dict['recipe']: recipe = ' til %s' % source_dict['recipe'] if not source_dict['recipe'] == config.language.no_recipe_name: if source_dict['recipe_multiplier'] == 1: recipe += ' for %d pers' % source_dict['recipe_made_for'] else: recipe += ' x%f' % source_dict['recipe_multiplier'] source += recipe descriptions += [source] processed_groceries += [{'item': item, 'description': ', '.join(descriptions)}] response = add_groceries_to_wunderlist(self.wunderpy_config, target_list_name=target_list, groceries=processed_groceries) print(response) def callback_controll_return_grocery_list(self, event): self.parse_grocery_list(smart=False) return 'break' def callback_any_key_grocery_list(self, event): self.parse_grocery_list() def callback_button_parse_grocery_list(self): self.parse_grocery_list(smart=False) def parse_grocery_list(self, smart=True): print('callback works') text = self.grocery_list.get(1.0, tk.END) self.menu_box.delete(1.0, tk.END) if text.strip() == 'tags': string = '\n'.join([tag for tag in COOKBOOK.available_tags.keys()]) self.menu_box.insert(tk.INSERT, string) if text.strip() == 'recipes': string = '\n'.join(COOKBOOK.available_recipes) self.menu_box.insert(tk.INSERT, string) else: # Intelligent update: Only update the lines that have changed. if not self.current_menu or not smart: self.current_menu = COOKBOOK.parse_menu(self.grocery_list.get(1.0, tk.END)) else: new_menu = COOKBOOK.parse_menu(self.grocery_list.get(1.0, tk.END)) for index, line in enumerate(new_menu.input_lines): if line in self.current_menu.input_lines: current_index = self.current_menu.input_lines.index(line) new_menu.input_lines[index] = self.current_menu.input_lines[current_index] new_menu.processed_lines[index] = self.current_menu.processed_lines[current_index] new_menu.input_plan = '\n'.join(new_menu.input_lines) new_menu.processed_plan = new_menu.create_output_lines(new_menu.processed_lines) self.current_menu = new_menu self.current_menu.process_input() self.menu_box.insert(tk.INSERT, self.current_menu.processed_plan) def callback_view_menu(self): """Callback for the send menu as email_sender button.""" print('callback_send_menu_email') if isinstance(self.current_menu, Menu): self.menu_box.delete(1.0, tk.END) self.menu_box.insert(tk.INSERT, '\n'+self.current_menu.generate_menu_str()) else: print('No menu to view') def callback_view_grocery_list(self): """Callback for the send menu as email_sender button.""" print('callback_view_grocery_list') if isinstance(self.current_menu, Menu): self.menu_box.delete(1.0, tk.END) string = '\n'.join(self.current_menu.groceries.ingredients_formatted(pretty=True, sort='alphabetical')) self.menu_box.insert(tk.INSERT, string) else: print('No menu to view') def calback_show_categories_list(self): self.menu_box.delete(1.0, tk.END) string = '\n'.join(sorted(COOKBOOK.tags)) self.menu_box.insert(tk.INSERT, string)
class ScrolledTextInfoFrame(Frame): def __init__(self, master, *args, **kwargs): self.master = master super(ScrolledTextInfoFrame, self).__init__(self.master, *args, **kwargs) self.saved_time = StringVar() self.highlighter = Highlighter() self._create_widgets() # the associated file self._file = None # TODO: rename the textentry def _create_widgets(self): # create a Text widget and read in the file self.textentry = ScrolledText(self, wrap=WORD) self.textentry.grid(column=0, row=0, columnspan=2, sticky='nsew') for key, value in self.highlighter.style: self.textentry.tag_configure(key, foreground=value) self.save_label = Label(self, textvar=self.saved_time) self.save_label.grid(column=0, row=1, sticky='es') self.save_btn = Button(self, text="Save", command=self.save_file) self.save_btn.grid(column=1, row=1, sticky='es') self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=0) self.grid_rowconfigure(0, weight=1) self.grid_rowconfigure(1, weight=0) def update(self): self._update_savetime() self.textentry.delete(1.0, END) with open(self.file.file, 'r') as file: self.textentry.insert(END, file.read()) if HAS_PYGMENTS: if self.highlighter.change_type(self.file.dtype): # remove current tags for tag in self.textentry.tag_names(): self.textentry.tag_configure(tag, foreground="#000000") for key, value in self.highlighter.style.items(): self.textentry.tag_configure(key, foreground=value) self.syn() def _update_savetime(self): self.saved_time.set("Last saved:\t{0}\t".format(self.file.saved_time)) @threaded def syn(self, event=None): """ Allow for syntax highlighting. Source: https://stackoverflow.com/a/30199105 This will highlight the entire document once. Dynamic highlighting not yet supported. #TODO: (maybe?): https://stackoverflow.com/questions/32058760/improve-pygments-syntax-highlighting-speed-for-tkinter-text/32064481 # noqa This is threaded to hopefully stop it blocking the view from displaying and causing a race condition. """ self.textentry.mark_set("range_start", "1.0") data = self.textentry.get("1.0", "end-1c") lexer = self.highlighter.lexer if lexer is not None: for token, content in lex(data, lexer()): self.textentry.mark_set("range_end", "range_start + %dc" % len(content)) self.textentry.tag_add(str(token), "range_start", "range_end") self.textentry.mark_set("range_start", "range_end") def save_file(self): """ Write the current data in the text widget back to the file """ file_contents = self.textentry.get("1.0", "end-1c") with open(self.file.file, 'w') as file: file.write(file_contents) savetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.file.saved_time = savetime self._update_savetime() # also re-apply the syntax highlighting self.syn() @property def file(self): return self._file @file.setter def file(self, other): """ Set the file property to whatever the new file is. When this happens the update command will be called which will redraw the channel info list """ # if the file is being set as a con_file continue if other != self._file: self._file = other self.update()
class Window(Listbox): # Initializes the variables and settings for the project. Finally # executes the create_menu for the menu bar, and the create_notepad # for the text window def __init__(self, master, **kw): # Sets master, or root super().__init__(master, **kw) self.master = master # Set some variables self.current_file_path = '' self.current_file_text = '' self.is_saved = True # Set up the context menu and the text box self.context_popup_menu = Menu(self.master, tearoff=0) self.text_window = ScrolledText(self.master, undo=True) self.text_window.focus() self.user_data = self.text_window.get('1.0', END + '-1c') # Name the window, icon, and start the create functions self.master.title(NAME) # self.master.iconbitmap('./tk/images/icon.ico') self.initiate_shortcuts() self.create_menu() self.create_notepad() self.create_context_menu() # Creates the context menu def create_context_menu(self): # Adds a command for button, separator for separator self.context_popup_menu.add_command(label="Undo", command=lambda: self.undo()) self.context_popup_menu.add_command(label="Redo", command=lambda: self.redo()) self.context_popup_menu.add_separator() self.context_popup_menu.add_command( label="Cut", command=lambda: self.text_window.event_generate("<<Cut>>")) self.context_popup_menu.add_command( label="Copy", command=lambda: self.text_window.event_generate("<<Copy>>")) self.context_popup_menu.add_command( label="Paste", command=lambda: self.text_window.event_generate("<<Paste>>")) self.context_popup_menu.add_separator() self.context_popup_menu.add_command(label="Delete", command=lambda: self.clear()) self.context_popup_menu.add_separator() self.context_popup_menu.add_command(label="Select All", command=lambda: self.select_all()) # Creates the top bar menu def create_menu(self): # Creating menu bar and adding it to master menu_bar = Menu(self.master) text = self.text_window # Telling root that menu_bar is the Window's menu self.master.config(menu=menu_bar) # Creating the File menu dropdown file_menu = Menu(menu_bar, tearoff=False) file_menu.add_command(label="New Document...", command=self.new_file, accelerator="Ctrl+N") file_menu.add_command(label="Open Document...", command=self.open_file, accelerator="Ctrl+O") file_menu.add_command(label="Save...", command=self.save_file, accelerator="Ctrl+S") file_menu.add_command(label="Save as...", command=self.save_as_file, accelerator="Ctrl+Shift+S") file_menu.add_separator() file_menu.add_command(label="Quit", command=self.exit, accelerator="Ctrl+Q") # Adding it to the menu_bar menu_bar.add_cascade(label="File", menu=file_menu, underline=0) # Creating the Edit menu dropdown edit_menu = Menu(menu_bar, tearoff=False) edit_menu.add_command(label="Undo", command=self.undo, accelerator="Ctrl+Z") edit_menu.add_command(label="Redo", command=self.redo, accelerator="Ctrl+Y") edit_menu.add_separator() edit_menu.add_command(label="Cut", command=lambda: text.event_generate("<<Cut>>"), accelerator="Ctrl+X") edit_menu.add_command(label="Copy", command=lambda: text.event_generate("<<Copy>>"), accelerator="Ctrl+C") edit_menu.add_command(label="Paste", command=lambda: text.event_generate("<<Paste>>"), accelerator="Ctrl+V") edit_menu.add_separator() edit_menu.add_command(label="Select All", command=lambda: self.select_all(), accelerator="Ctrl+A") edit_menu.add_command(label="Delete", command=self.clear, accelerator="Del") # edit_menu.add_separator() # edit_menu.add_command(label="Settings...", command=settings, accelerator="Ctrl+S") # Adding it to the menu_bar menu_bar.add_cascade(label="Edit", menu=edit_menu) # Creating the Help menu help_menu = Menu(menu_bar, tearoff=False) help_menu.add_command(label="About...", command=about) # Adding it to the menu_bar menu_bar.add_cascade(label="Help", menu=help_menu) # Bind the shortcuts to their specified functions def initiate_shortcuts(self): self.master.bind("<KeyRelease>", lambda event: self.on_text_change()) self.master.bind("<Control-n>", lambda event: self.new_file()) self.master.bind("<Control-o>", lambda event: self.open_file()) self.master.bind("<Control-s>", lambda event: self.save_file()) self.master.bind("<Control-Shift-s>", lambda event: self.save_as_file()) self.master.bind("<Control-q>", lambda event: self.exit()) self.master.bind("<Control-z>", lambda event: self.undo()) self.master.bind("<Control-y>", lambda event: self.redo()) self.text_window.bind("<Control-a>", lambda event: self.select_all()) # self.master.bind("<Control-s>", lambda event: settings()) self.master.bind("<Button-3>", lambda event: self.right_click_popup(event)) # Display context menu popup def right_click_popup(self, event): try: # Used +45 and + 12 to corner it self.context_popup_menu.tk_popup(event.x_root + 45, event.y_root + 12, 0) finally: self.context_popup_menu.grab_release() # Scaling the text_window to fit the screen def create_notepad(self): self.text_window.pack(fill="both", expand=True) # Returns the value of the text field def get_text_data(self): return self.text_window.get('1.0', END + '-1c') # Clears the text off the screen, resets the variables def clear_text(self): self.text_window.delete('1.0', END) self.current_file_path = '' self.current_file_text = '' # Called when typing, sets the is_saved variable def on_text_change(self): # If the text in the textbox is equal to the saved text in the variable # This is used when opening a file, changing something, then undoing that change if self.get_text_data() == self.current_file_text: self.is_saved = True else: # If the saved file exists or is valid if os.path.isfile(self.current_file_path): # Open the file, save it's data to this_file with open(self.current_file_path, "r") as f: this_file = f.read() # If this_file is equal to the same text in the textbox # Used if no changes were made, and if they were, set to False self.is_saved = True if this_file == self.get_text_data( ) else False else: # If the data is not equal to variable, and no file, then changes # must have been made self.is_saved = False # MENU CONTROL FUNCTIONS # Clear current selection, erase the current file if saved def new_file(self): # If it's saved, clear it and set the file to saved if self.is_saved is True: self.clear_text() self.is_saved = True else: # Popup the saved popup popup_value = is_saved_popup() if popup_value == "yes": # Save the file, clear it and set the is_saved to True if self.save_file() is True: self.clear_text() self.is_saved = True elif popup_value == "no": # Don't save the file, but clear it and set the is_saved to True self.clear_text() self.is_saved = True else: # Something went wrong print("Error: new_file error") # Open a file if the current file is saved, then insert new file data def open_file(self): # If file is saved, open the open_file window if self.is_saved is True: self.open_file_popup() else: # Save the file, if it's saved, open the open_file window popup_value = is_saved_popup() if popup_value == "yes": if self.save_file() is True: self.is_saved = True self.open_file_popup() # Open the open_file window elif popup_value == "no": self.open_file_popup() else: # An error occurred print("Error: open_file error") # The function that displays the open_file popup def open_file_popup(self): # Gets old data from current file old_file = self.current_file_path # Opens the file location, stores it in file_name file_name = filedialog.askopenfilename( title="Open", filetypes=(("Text files", "*.txt"), ("All files", "*.*"))) # If a file was actually selected, open it if file_name is not '': with open(file_name) as f: data = f.read() # Clear current text self.clear_text() # Set the path variable of the new file self.current_file_path = file_name if os.path.isfile( file_name) else old_file # Add the file data to the text_box self.text_window.insert(INSERT, data) # Add the file data to the variable self.current_file_text = data # is_saved is True self.is_saved = True # Save file, if file exists, overwrite it, otherwise, call save_as_file function def save_file(self): # If the file path exists if os.path.isfile(self.current_file_path): # Stores the current text data into the variable self.current_file_text = self.get_text_data() # Saves the data to the existing file (overwriting) with open(self.current_file_path, "w") as f: return True if f.writelines( self.get_text_data()) is True else False else: # File doesn't exist, call save_as_file if self.save_as_file() is True: return True # Saves file with asksaveasfile to open a save as window. def save_as_file(self): # Gets old file path old_file = self.current_file_path # Opens save_as window file_name = filedialog.asksaveasfilename( title="Save As", defaultextension=".txt", filetypes=(("Text files", "*.txt"), ("All files", "*.*"))) # Set current file path self.current_file_path = old_file if file_name is None else file_name # If the file_path already exists if os.path.isfile(self.current_file_path): # Copy the current text to the variable self.current_file_text = self.get_text_data() # Writes to the named file with open(self.current_file_path, "w") as f: f.writelines(self.get_text_data()) return True else: # A file wasn't selected if file_name is '': print("Error: File is none") return False # Create a new file to store the data self.current_file_text = self.get_text_data() with open(file_name, 'w'): pass self.is_saved = True return True # Exit override command def exit(self): # If the file is saved, exit if self.is_saved is True: self.master.quit() else: # If the file is not saved, call the saved_popup popup_value = is_saved_popup() if popup_value == "yes": # Save and then quit if self.save_file() is True: self.is_saved = True self.quit() elif popup_value == "no": # Don't save, just quit self.master.quit() else: # An error occurred print("Error: open_file error") # Undo last action def undo(self): self.text_window.edit_undo() # Redo last action def redo(self): self.text_window.edit_redo() # Clear (delete) the selected text def clear(self): self.text_window.delete(SEL_FIRST, SEL_LAST) self.text_window.update() # Select the selected text (without new line) def select_all(self): self.text_window.tag_add(SEL, "1.0", END + '-1c') self.text_window.mark_set(INSERT, "1.0") self.text_window.see(INSERT) return 'break'
class Editor(Toplevel): @property def text(self): return self.sc_text.get('1.0', END) @text.setter def text(self, value): pos = self.sc_text.yview() self.sc_text.delete('1.0', END) self.sc_text.insert(END, value) self.sc_text.yview_moveto(pos[0]) def __init__(self, master): super().__init__(master) self.index_matches = None self.current_index = None self.search_content = StringVar() self.sc_text = ScrolledText(self, wrap=NONE) self.x_scrollbar_content_text = Scrollbar(self, orient=HORIZONTAL, command=self.sc_text.xview) self.sc_text.configure( xscrollcommand=self.x_scrollbar_content_text.set) self.wrap_text = IntVar() self.wrap_text.set(False) Button(self, text='<-', command=self.click_prev_button).grid(row=0, column=0) self.search_content_entry = Entry(self, textvariable=self.search_content) self.search_content_entry.bind( '<KeyRelease>', lambda event: self.highlight_pattern(event.widget.get())) self.search_content_entry.grid(row=0, column=1, sticky=W + E) Button(self, text='->', command=self.click_next_button).grid(row=0, column=2) Checkbutton(self, text="Wrap Text", variable=self.wrap_text, command=lambda: self.sc_text.config( wrap=NONE if not self.wrap_text.get() else WORD)).grid(row=1, column=0) self.sc_text.grid(row=2, column=0, columnspan=3, sticky=N + S + E + W) self.x_scrollbar_content_text.grid(row=3, column=0, columnspan=3, sticky=W + E) self.columnconfigure(1, weight=1) self.rowconfigure(2, weight=1) self.withdraw() self.protocol('WM_DELETE_WINDOW', lambda t=self: t.withdraw()) def click_next_button(self): if not self.index_matches: return if self.current_index is None: self.current_index = 0 else: self.current_index += 1 self.current_index %= len(self.index_matches) self.sc_text.see(self.index_matches[self.current_index]) def click_prev_button(self): if not self.index_matches: return if self.current_index is None: self.current_index = len(self.index_matches) - 1 else: self.current_index -= 1 self.current_index %= len(self.index_matches) self.sc_text.see(self.index_matches[self.current_index]) def highlight_pattern(self, pattern, start="1.0", end="end"): for t in self.sc_text.tag_names(): self.sc_text.tag_delete(t) if not pattern: return self.index_matches = [] self.current_index = None self.sc_text.tag_config('found', background="green") start = self.sc_text.index(start) end = self.sc_text.index(end) self.sc_text.mark_set("matchStart", start) self.sc_text.mark_set("matchEnd", start) self.sc_text.mark_set("searchLimit", end) count = IntVar() while True: index = self.sc_text.search(pattern, "matchEnd", "searchLimit", count=count) if index == "": break self.sc_text.mark_set("matchStart", index) match_index = "%s+%sc" % (index, count.get()) self.index_matches.append(match_index) self.sc_text.mark_set("matchEnd", match_index) self.sc_text.tag_add('found', "matchStart", "matchEnd")
class WbRunner(tk.Frame): def __init__(self, tool_name=None, master=None): # First, try to find the WhiteboxTools exe directory if _platform == 'win32': ext = '.exe' else: ext = '' exe_name = "whitebox_tools{}".format(ext) self.exe_path = path.dirname(path.abspath(__file__)) os.chdir(self.exe_path) for filename in glob.iglob('**/*', recursive=True): if filename.endswith(exe_name): self.exe_path = path.dirname(path.abspath(filename)) break wbt.set_whitebox_dir(self.exe_path) ttk.Frame.__init__(self, master) self.script_dir = os.path.dirname(os.path.realpath(__file__)) self.grid() self.tool_name = tool_name self.master.title("WhiteboxTools Runner") # widthpixels = 800 # heightpixels = 600 # self.master.geometry('{}x{}'.format(widthpixels, heightpixels)) # self.master.resizable(0, 0) # self.master.lift() if _platform == "darwin": os.system( '''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''' ) self.create_widgets() self.working_dir = str(Path.home()) def create_widgets(self): toplevel_frame = ttk.Frame(self, padding='0.1i') (self.toolslist, selected_item) = self.get_tools_list() self.tools_frame = ttk.LabelFrame(toplevel_frame, text="{} Available Tools".format( len(self.toolslist)), padding='0.1i') self.toolnames = tk.StringVar(value=self.toolslist) self.tools_listbox = tk.Listbox(self.tools_frame, height=22, listvariable=self.toolnames) self.tools_listbox.bind("<<ListboxSelect>>", self.update_tool_help) self.tools_listbox.grid(row=0, column=0, sticky=tk.NSEW) self.tools_listbox.columnconfigure(0, weight=10) self.tools_listbox.rowconfigure(0, weight=1) s = ttk.Scrollbar(self.tools_frame, orient=tk.VERTICAL, command=self.tools_listbox.yview) s.grid(row=0, column=1, sticky=(tk.N, tk.S)) self.tools_listbox['yscrollcommand'] = s.set self.tools_frame.grid(row=0, column=0, sticky=tk.NSEW) self.tools_frame.columnconfigure(0, weight=10) self.tools_frame.columnconfigure(1, weight=1) self.tools_frame.rowconfigure(0, weight=1) overall_frame = ttk.Frame(toplevel_frame, padding='0.1i') # json_str = '{"default_value": null, "description": "Directory containing data files.", "flags": ["--wd"], "name": "Working Directory", "optional": true, "parameter_type": "Directory"}' # self.wd = FileSelector(json_str, overall_frame) # self.wd.grid(row=0, column=0, sticky=tk.NSEW) current_tool_frame = ttk.Frame(overall_frame, padding='0.1i') self.current_tool_lbl = ttk.Label( current_tool_frame, text="Current Tool: {}".format(self.tool_name), justify=tk.LEFT) # , font=("Helvetica", 12, "bold") self.current_tool_lbl.grid(row=0, column=0, sticky=tk.W) self.view_code_button = ttk.Button(current_tool_frame, text="View Code", width=12, command=self.view_code) self.view_code_button.grid(row=0, column=1, sticky=tk.E) current_tool_frame.grid(row=1, column=0, sticky=tk.NSEW) current_tool_frame.columnconfigure(0, weight=1) current_tool_frame.columnconfigure(1, weight=1) tool_args_frame = ttk.Frame(overall_frame, padding='0.0i') self.tool_args_frame = ttk.Frame(overall_frame, padding='0.0i') self.tool_args_frame.grid(row=2, column=0, sticky=tk.NSEW) self.tool_args_frame.columnconfigure(0, weight=1) # args_frame = ttk.Frame(overall_frame, padding='0.1i') # self.args_label = ttk.Label(args_frame, text="Tool Arguments:", justify=tk.LEFT) # self.args_label.grid(row=0, column=0, sticky=tk.W) # args_frame2 = ttk.Frame(args_frame, padding='0.0i') # self.args_value = tk.StringVar() # self.args_text = ttk.Entry(args_frame2, width=45, justify=tk.LEFT, textvariable=self.args_value) # self.args_text.grid(row=0, column=0, sticky=tk.NSEW) # self.args_text.columnconfigure(0, weight=1) # self.clearButton = ttk.Button(args_frame2, text="Clear", width=4, command=self.clear_args_box) # self.clearButton.pack(pady=10, padx=10) # self.clearButton.grid(row=0, column=1, sticky=tk.E) # self.clearButton.columnconfigure(0, weight=1) # args_frame2.grid(row=1, column=0, sticky=tk.NSEW) # args_frame2.columnconfigure(0, weight=10) # args_frame2.columnconfigure(1, weight=1) # args_frame.grid(row=2, column=0, sticky=tk.NSEW) # args_frame.columnconfigure(0, weight=1) # # Add the bindings # if _platform == "darwin": # self.args_text.bind("<Command-Key-a>", self.args_select_all) # else: # self.args_text.bind("<Control-Key-a>", self.args_select_all) buttonsFrame = ttk.Frame(overall_frame, padding='0.1i') self.run_button = ttk.Button(buttonsFrame, text="Run", width=8, command=self.run_tool) # self.run_button.pack(pady=10, padx=10) self.run_button.grid(row=0, column=0) self.quitButton = ttk.Button(buttonsFrame, text="Cancel", width=8, command=self.cancel_operation) self.quitButton.grid(row=0, column=1) buttonsFrame.grid(row=3, column=0, sticky=tk.E) output_frame = ttk.Frame(overall_frame, padding='0.1i') outlabel = ttk.Label(output_frame, text="Output:", justify=tk.LEFT) outlabel.grid(row=0, column=0, sticky=tk.NW) k = wbt.tool_help(self.tool_name) self.out_text = ScrolledText(output_frame, width=63, height=10, wrap=tk.NONE, padx=7, pady=7) self.out_text.insert(tk.END, k) self.out_text.grid(row=1, column=0, sticky=tk.NSEW) self.out_text.columnconfigure(0, weight=1) output_frame.grid(row=4, column=0, sticky=tk.NSEW) output_frame.columnconfigure(0, weight=1) # Add the binding if _platform == "darwin": self.out_text.bind("<Command-Key-a>", self.select_all) # self.out_text.bind("<Command-Key-A>", self.select_all) else: self.out_text.bind("<Control-Key-a>", self.select_all) progress_frame = ttk.Frame(overall_frame, padding='0.1i') self.progress_label = ttk.Label(progress_frame, text="Progress:", justify=tk.LEFT) self.progress_label.grid(row=0, column=0, sticky=tk.E, padx=5) self.progress_var = tk.DoubleVar() self.progress = ttk.Progressbar(progress_frame, orient="horizontal", variable=self.progress_var, length=200, maximum=100) self.progress.grid(row=0, column=1, sticky=tk.E) progress_frame.grid(row=5, column=0, sticky=tk.E) overall_frame.grid(row=0, column=1, sticky=tk.NSEW) overall_frame.columnconfigure(0, weight=1) toplevel_frame.columnconfigure(0, weight=1) toplevel_frame.columnconfigure(1, weight=4) # self.pack(fill=tk.BOTH, expand=1) # toplevel_frame.columnconfigure(0, weight=1) # toplevel_frame.rowconfigure(0, weight=1) toplevel_frame.grid(row=0, column=0, sticky=tk.NSEW) # Select the appropriate tool, if specified, otherwise the first tool self.tools_listbox.select_set(selected_item) self.tools_listbox.event_generate("<<ListboxSelect>>") self.tools_listbox.see(selected_item) menubar = tk.Menu(self) filemenu = tk.Menu(menubar, tearoff=0) filemenu.add_command(label="Set Working Directory", command=self.set_directory) filemenu.add_command(label="Locate WhiteboxTools exe", command=self.select_exe) filemenu.add_command(label="Refresh Tools", command=self.refresh_tools) filemenu.add_separator() filemenu.add_command(label="Exit", command=self.quit) menubar.add_cascade(label="File", menu=filemenu) editmenu = tk.Menu(menubar, tearoff=0) editmenu.add_command( label="Cut", command=lambda: self.focus_get().event_generate("<<Cut>>")) editmenu.add_command( label="Copy", command=lambda: self.focus_get().event_generate("<<Copy>>")) editmenu.add_command( label="Paste", command=lambda: self.focus_get().event_generate("<<Paste>>")) menubar.add_cascade(label="Edit ", menu=editmenu) helpmenu = tk.Menu(menubar, tearoff=0) helpmenu.add_command(label="About", command=self.help) helpmenu.add_command(label="License", command=self.license) menubar.add_cascade(label="Help ", menu=helpmenu) self.master.config(menu=menubar) # self.get_toolboxes() def help(self): self.print_to_output(wbt.version()) def license(self): self.print_to_output(wbt.license()) def set_directory(self): try: self.working_dir = filedialog.askdirectory( initialdir=self.exe_path) wbt.set_working_dir(self.working_dir) except: messagebox.showinfo( "Warning", "Could not find WhiteboxTools executable file.") def select_exe(self): try: filename = filedialog.askopenfilename(initialdir=self.exe_path) self.exe_path = path.dirname(path.abspath(filename)) wbt.set_whitebox_dir(self.exe_path) self.refresh_tools() except: messagebox.showinfo( "Warning", "Could not find WhiteboxTools executable file.") def run_tool(self): # wd_str = self.wd.get_value() wbt.set_working_dir(self.working_dir) # args = shlex.split(self.args_value.get()) args = [] for widget in self.tool_args_frame.winfo_children(): v = widget.get_value() if v: args.append(v) elif not widget.optional: messagebox.showinfo( "Error", "Non-optional tool parameter not specified.") return self.print_line_to_output("") # self.print_line_to_output("Tool arguments:{}".format(args)) # self.print_line_to_output("") # Run the tool and check the return value for an error if wbt.run_tool(self.tool_name, args, self.custom_callback) == 1: print("Error running {}".format(self.tool_name)) else: self.run_button["text"] = "Run" self.progress_var.set(0) self.progress_label['text'] = "Progress:" self.progress.update_idletasks() def print_to_output(self, value): self.out_text.insert(tk.END, value) self.out_text.see(tk.END) def print_line_to_output(self, value): self.out_text.insert(tk.END, value + "\n") self.out_text.see(tk.END) def cancel_operation(self): wbt.cancel_op = True self.print_line_to_output("Cancelling operation...") self.progress.update_idletasks() def view_code(self): webbrowser.open_new_tab(wbt.view_code(self.tool_name).strip()) def update_tool_help(self, event): selection = self.tools_listbox.curselection() self.tool_name = self.tools_listbox.get(selection[0]) self.out_text.delete('1.0', tk.END) for widget in self.tool_args_frame.winfo_children(): widget.destroy() k = wbt.tool_help(self.tool_name) self.print_to_output(k) j = json.loads(wbt.tool_parameters(self.tool_name)) param_num = 0 for p in j['parameters']: json_str = json.dumps(p, sort_keys=True, indent=2, separators=(',', ': ')) pt = p['parameter_type'] if 'ExistingFileOrFloat' in pt: ff = FileOrFloat(json_str, self, self.tool_args_frame) ff.grid(row=param_num, column=0, sticky=tk.NSEW) param_num = param_num + 1 elif ('ExistingFile' in pt or 'NewFile' in pt or 'Directory' in pt): fs = FileSelector(json_str, self, self.tool_args_frame) fs.grid(row=param_num, column=0, sticky=tk.NSEW) param_num = param_num + 1 elif 'FileList' in pt: b = MultifileSelector(json_str, self, self.tool_args_frame) b.grid(row=param_num, column=0, sticky=tk.W) param_num = param_num + 1 elif 'Boolean' in pt: b = BooleanInput(json_str, self.tool_args_frame) b.grid(row=param_num, column=0, sticky=tk.W) param_num = param_num + 1 elif 'OptionList' in pt: b = OptionsInput(json_str, self.tool_args_frame) b.grid(row=param_num, column=0, sticky=tk.W) param_num = param_num + 1 elif ('Float' in pt or 'Integer' in pt or 'String' in pt or 'StringOrNumber' in pt or 'StringList' in pt): b = DataInput(json_str, self.tool_args_frame) b.grid(row=param_num, column=0, sticky=tk.NSEW) param_num = param_num + 1 else: messagebox.showinfo( "Error", "Unsupported parameter type: {}.".format(pt)) self.update_args_box() self.out_text.see("%d.%d" % (1, 0)) def update_args_box(self): s = "" self.current_tool_lbl['text'] = "Current Tool: {}".format( self.tool_name) # self.spacer['width'] = width=(35-len(self.tool_name)) for item in wbt.tool_help(self.tool_name).splitlines(): if item.startswith("-"): k = item.split(" ") if "--" in k[1]: value = k[1].replace(",", "") else: value = k[0].replace(",", "") if "flag" in item.lower(): s = s + value + " " else: if "file" in item.lower(): s = s + value + "='{}' " else: s = s + value + "={} " # self.args_value.set(s.strip()) def clear_args_box(self): self.args_value.set("") def args_select_all(self, event): self.args_text.select_range(0, tk.END) return 'break' def custom_callback(self, value): ''' A custom callback for dealing with tool output. ''' if "%" in value: try: str_array = value.split(" ") label = value.replace(str_array[len(str_array) - 1], "").strip() progress = float(str_array[len(str_array) - 1].replace( "%", "").strip()) self.progress_var.set(int(progress)) self.progress_label['text'] = label except ValueError as e: print("Problem converting parsed data into number: ", e) except Exception as e: print(e) else: self.print_line_to_output(value) self.update( ) # this is needed for cancelling and updating the progress bar def select_all(self, event): self.out_text.tag_add(tk.SEL, "1.0", tk.END) self.out_text.mark_set(tk.INSERT, "1.0") self.out_text.see(tk.INSERT) return 'break' def get_tools_list(self): list = [] selected_item = -1 for item in wbt.list_tools().splitlines(): if item: if "available tools" not in item.lower(): value = item.split(":")[0] list.append(value) if value == self.tool_name: selected_item = len(list) - 1 if selected_item == -1: selected_item = 0 self.tool_name = list[0] return (list, selected_item) def get_toolboxes(self): toolboxes = set() for item in wbt.toolbox().splitlines( ): # run wbt.toolbox with no tool specified--returns all if item: tb = item.split(":")[1].strip() toolboxes.add(tb) for v in sorted(toolboxes): # print(v) self.print_line_to_output(v) def refresh_tools(self): (self.toolslist, selected_item) = self.get_tools_list() self.tools_listbox.delete(0, len(self.toolslist)) for item in self.toolslist: self.tools_listbox.insert(len(self.toolslist), item) self.tools_frame["text"] = "{} Available Tools".format( len(self.toolslist))
class IqtreeWindow(): displayed_output ="" command = "" partition_command = "" wd = "~" def __init__(self, master, settings): self.settings = settings self.master = master self.master.resizable(False, False) self.master.protocol( "WM_DELETE_WINDOW", self.close) self.master.title("iqtree Output") self.checkpoints = Listbox(self.master) self.checkpoints.grid(column=1,row=1, sticky=N+W+S) #self.checkpoints.bind("<Button-1>", self.jump_to_selection) self.checkpoints.bind("<<ListboxSelect>>", self.jump_to_selection) self.output_label = ScrolledText(self.master, font=("Helvetica", 10), width=100) self.output_label.grid(column=2,row=1) self.save_button = Button(self.master, text="Save Output") self.save_button.grid(column=1,row=2) self.line_number = 0 self.checkpoints_dict = {} self.checkpoints_dict["Start of run"] = self.line_number self.checkpoints.insert(END, "Start of run") self.n_empty_lines = 0 def jump_to_selection(self, ef): selection = self.checkpoints.curselection() line = self.checkpoints_dict[self.checkpoints.get(selection[0])] print(line) self.output_label.mark_set("section", "%s.1"%line) self.output_label.see("section") def display(self, text): if text == "": self.n_empty_lines += 1 if self.n_empty_lines >= 10: self.process.kill() else: self.line_number += 1 self.displayed_output = str(self.line_number) + " " + text self.displayed_output = " " + text self.output_label.insert(END,self.displayed_output) self.output_label.see(END) if self.displayed_output.startswith("IQ-TREE"): self.checkpoints.insert(END, "IQ-TREE") self.checkpoints_dict["IQ-TREE"] = self.line_number if self.displayed_output.startswith("ModelFinder"): self.checkpoints.insert(END, "ModelFinder") self.checkpoints_dict["ModelFinder"] = self.line_number if self.displayed_output.startswith("Akaike Information Criterion:"): self.checkpoints.insert(END, "Best Model") self.checkpoints_dict["Best Model"] = self.line_number if "INITIALIZING CANDIDATE TREE SET" in self.displayed_output: self.checkpoints.insert(END, "Initialize tree") self.checkpoints_dict["Initialize tree"] = self.line_number if "OPTIMIZING CANDIDATE TREE SET" in self.displayed_output: self.checkpoints.insert(END, "Optimize tree") self.checkpoints_dict["Optimize tree"] = self.line_number if "FINALIZING TREE SEARCH" in self.displayed_output: self.checkpoints.insert(END, "Finalize tree") self.checkpoints_dict["Finalize tree"] = self.line_number #print self.checkpoints_dict #self.frame.configure(text=self.displayed_output) def send_command(self, command): self.command = command def send_partitions(self, partition_command): self.partition_command = partition_command def spawn_process(self): print("Command is:", self.command) #cmd_list = shlex.split(self.command) if "Windows" in platform.system(): separator="\\" else: separator="/" os.chdir(self.settings.wd + separator + self.settings.analysisname) self.process = Popen(self.command, stdout=PIPE, stderr=STDOUT, universal_newlines=True, shell=True) self.q = Queue(maxsize=1024) self.t = Thread(target=self.reader_thread, args=[self.q]) self.t.setDaemon(True) self.t.start() self.update(self.q) def reader_thread(self, q): # Read subprocess output and put it into the queue. print("READING") try: with self.process.stdout as pipe: for line in iter(pipe.readline, b''): q.put(line) finally: q.put(None) self.process.kill() try: with self.process.stderr as pipe: for line in iter(pipe.readline, b''): q.put(line) finally: q.put(None) self.process.kill() def update(self, q): # Update GUI with items from the queue. for line in iter_except(q.get_nowait, Empty): # display all content if line is None: #self.quit() return else: self.display(line) # update GUI break # display no more than one line per 40 milliseconds self.master.after(40, self.update, q) # schedule next update def close(self): self.process.kill() self.master.destroy()
class Gui(): def __init__(self): self.file_path = None self.simulation_data = None # A ScriptOutput object self.root = tk.Tk() self.root.protocol("WM_DELETE_WINDOW", self.file_quit) self.set_title() self.scriptLabel = None self.scriptField = None self._create_widgets() self._assign_accelerators() self.root.mainloop() def _create_widgets(self): # The frame containing the widgets frame = tk.Frame(self.root) # The menu bar menu_bar = tk.Menu(self.root, tearoff=0) # The File menu file_menu = tk.Menu( menu_bar, tearoff=0) # tearoff = 0: can't be seperated from window file_menu.add_command(label="New", underline=0, command=self.file_new) # , accelerator="Ctrl+N") file_menu.add_command( label="Open...", underline=0, command=self.file_open) # , accelerator="Ctrl+O") file_menu.add_command( label="Save", underline=0, command=self.file_save) # , accelerator="Ctrl+S") file_menu.add_command(label="Save As...", underline=1, command=self.file_save_as) file_menu.add_separator() file_menu.add_command(label="Exit", underline=1, command=self.file_quit) menu_bar.add_cascade(label="File", underline=0, menu=file_menu) # The Run menu run_menu = tk.Menu( menu_bar, tearoff=0) # tearoff = 0: can't be seperated from window run_menu.add_command(label="Simulate and Plot", underline=0, command=self.simulate, accelerator="F5") run_menu.add_command(label="Plot", underline=0, command=self.plot) menu_bar.add_cascade(label="Run", underline=0, menu=run_menu) # The Edit menu edit_menu = tk.Menu( menu_bar, tearoff=0) # tearoff = 0: can't be seperated from window edit_menu.add_command(label="Undo", underline=0, command=self.undo, accelerator="Ctrl+Z") edit_menu.add_command(label="Redo", underline=0, command=self.redo, accelerator="Ctrl+Y") menu_bar.add_cascade(label="Edit", underline=0, menu=edit_menu) self.root.config(menu=menu_bar) # The label lbltxt = "Place your script in the box below or open a text file" # lbltxt = "Simulate: F5, Open: Ctrl+O, Save: Ctrl+S, New: Ctrl+N" scriptLabel = tk.Label(frame, text=lbltxt) scriptLabel.pack(side="top", anchor="w") # The Text widget self.scriptField = ScrolledText(frame) self.scriptField.pack(side="top", fill=BOTH, expand=YES) self.scriptField.config(undo=True) self.scriptField.focus_set() # self.scriptField.config( # borderwidth=0, # font="{Lucida Sans Typewriter} 12", # foreground="green", # background="black", # insertbackground="white", # cursor # selectforeground="green", # selection # selectbackground="#008000", # wrap=tk.WORD, # use word wrapping # width=64, # undo=True, # Tk 8.4 # ) # The Quit button # quitButton = tk.Button(frame, text="Quit", command=self.quit) # quitButton.pack(side="right") # The Close All button closefigButton = tk.Button(frame, text="Close All Figures", command=self.close_figs) closefigButton.pack(side="right") # The Simulate button simButton = tk.Button(frame, text="Simulate and Plot", command=self.simulate) simButton.pack(side="left") # The Plot button plotButton = tk.Button(frame, text="Plot", command=self.plot) plotButton.pack(side="left") frame.pack(fill=BOTH, expand=YES) def simulate(self, event=None): try: script = self.scriptField.get("1.0", "end-1c") script_obj = LsScript.LsScript(script) self.simulation_data = script_obj.run() script_obj.postproc(self.simulation_data) except Exception as ex: self.handle_exception(ex) def plot(self): try: if self.simulation_data is None: raise LsGuiException("No simulation data to plot.") script = self.scriptField.get("1.0", "end-1c") script_obj = LsScript.LsScript(script) script_obj.postproc(self.simulation_data) except Exception as ex: self.handle_exception(ex) def close_figs(self): plt.close("all") def handle_exception(self, ex): # err_msg = ex.args[0] err_msg = str(ex) # if len(ex.args) == 2: # err_msg = "{0} {1}".format(err_msg, ex.args[1]) # # err_msg = err_msg + ex.args[1] messagebox.showerror("Error", err_msg) print(traceback.format_exc()) # def file_open(self): # filename = filedialog.askopenfilename() # # filename = "C:/Python/Python36-32/_Markus/scriptexempel2.txt" # XXX # file = open(filename, "r") # self.scriptField.delete("1.0", "end-1c") # self.scriptField.insert("1.0", file.read()) # self.scriptField.mark_set("insert", "1.0") # file.close() # Make sure you close the file when done def save_changes(self): if self.scriptField.edit_modified(): msg = "This document has been modified. Do you want to save changes?" save_changes = messagebox.askyesnocancel("Save?", msg) if save_changes is None: # Cancel return False elif save_changes is True: # Yes self.file_save() return True def file_new(self, event=None): save_changes = self.save_changes() if not save_changes: return self.scriptField.delete(1.0, "end") self.scriptField.edit_modified(False) self.scriptField.edit_reset() self.file_path = None self.set_title() def file_open(self, event=None): # , filepath=None): save_changes = self.save_changes() if not save_changes: return # XXX initialdir = '.' if os.path.isdir('/home/markus/Dropbox/'): initialdir = '/home/markus/Dropbox/LearningSimulator/Scripts' filepath = filedialog.askopenfilename(filetypes=FILETYPES, initialdir=initialdir) if filepath is not None and len(filepath) != 0: with open(filepath, encoding="utf-8") as f: file_contents = f.read() # Set current text to file contents self.scriptField.delete(1.0, "end") self.scriptField.insert(1.0, file_contents) self.scriptField.edit_modified(False) self.scriptField.mark_set("insert", "1.0") self.file_path = filepath self.set_title() def file_save(self, event=None): self.file_save_as(filepath=self.file_path) def file_save_as(self, filepath=None, event=None): if filepath is None: filepath = filedialog.asksaveasfilename(filetypes=FILETYPES) if len( filepath ) == 0: # Empty tuple or empty string is returned if cancelled return # "cancelled" try: with open(filepath, 'wb') as f: text = self.scriptField.get(1.0, "end-1c") f.write(bytes(text, 'UTF-8')) self.scriptField.edit_modified(False) self.file_path = filepath self.set_title() return # "saved" except IOError as e: self.handle_exception(e) return # "cancelled" def file_quit(self, event=None): save_changes = self.save_changes() if not save_changes: return self.close_figs() self.root.destroy() # sys.exit(0) def set_title(self, event=None): if self.file_path is not None: # title = os.path.basename(self.file_path) title = os.path.abspath(self.file_path) else: title = "Untitled" self.root.title(title + " - " + TITLE) def undo(self, event=None): try: self.scriptField.edit_undo() except Exception as e: self.handle_exception(e) return "break" def redo(self, event=None): self.scriptField.edit_redo() return "break" def _assign_accelerators(self): # self.scriptField.bind("<Control-n>", self.file_new) # self.scriptField.bind("<Control-N>", self.file_new) # self.scriptField.bind("<Control-o>", self.file_open) # self.scriptField.bind("<Control-O>", self.file_open) # self.scriptField.bind("<Control-S>", self.file_save) # self.scriptField.bind("<Control-s>", self.file_save) self.scriptField.bind("<Control-y>", self.redo) self.scriptField.bind("<Control-Y>", self.redo) self.scriptField.bind("<Control-z>", self.undo) self.scriptField.bind("<Control-Z>", self.undo) # self.root.bind_class("Text", ",<Control-z>", self.undo) # self.root.bind_class("Text", ",<Control-Z>", self.undo) # self.root.bind_class("Text", ",<Control-y>", self.redo) # self.root.bind_class("Text", ",<Control-Y>", self.redo) self.scriptField.bind("<F5>", self.simulate)
class main: def __init__(self, master, lexer): self.master = master self.master.title("PyDE - Untitled") self.filename = None self.lexer = lexer self.x, self.y = 0, 10 self.ftsize = 15 self.end = "" self.img = PhotoImage(file="C:/Users/shiven/Desktop/anime.png") self.__anime__ = self.img.subsample(3, 3) self.mario1 = PhotoImage( file="C:/Users/shiven/Desktop/C++/mariofinal1.png") self.mario2 = PhotoImage( file="C:/Users/shiven/Desktop/C++/mariofinal2.png") self.mario1 = self.mario1.subsample(2, 2) self.types = [("All Files", "*.*"), ("Text Files", "*.txt")] self.draw() self.text.bind("<Control-N>", self.newfile) self.text.bind("<Control-n>", self.newfile) self.text.bind("<Control-S>", self.savefile) self.text.bind("<Control-s>", self.savefile) self.text.bind("<Control-o>", self.openfile) self.text.bind("<Control-O>", self.openfile) self.text.bind("<Control-d>", self.copy_cur_line) self.text.bind("<Control-D>", self.copy_cur_line) self.text.bind("<Tab>", self.spaces) self.text.bind("<KeyRelease>", self.cur_line_col) self.text.bind("<Button-1>", self.cur_line_col) self.text.bind("<Button-3>", self.cur_line_col) self.text.bind("<Button-2>", self.cur_line_col) self.text.bind("<Motion>", self.cur_line_col) self.text.bind("<Configure>", self.cur_line_col) self.master.bind("<Control-[>", self.indent) self.master.bind("<Control-]>", self.dedent) self.master.bind("<Control-/>", self.comment) self.master.bind("<Alt-s>", self.uncomment) self.master.bind("<Alt-Up>", self.zoom_in) self.master.bind("<F3>", self.zoom_out) self.master.bind("<Shift-(>", self.insert_paren) self.master.bind("<[>", self.insert_paren) self.master.bind("<Shift-{>", self.insert_paren) self.master.bind("<Control-b>", self.runscript) self.animation() self.display_time() self.__styles() self.master.bind("<KeyRelease>", self.highlight) self.master.bind("<Key>", self.highlight) def highlight(self, e): self.recolor() def highlight_(self): self.recolor() self.master.after(1000, self.highlight_()) def __styles(self): self.bdfont = font.Font(self.text, self.text.cget("font")) self.bdfont.config(weight=font.BOLD) self.itfont = font.Font(self.text, self.text.cget("font")) self.itfont.config(slant=font.ITALIC) self.style = __get__('default') for ttype, ndef in self.style: self.tag_font = None if ndef['bold']: self.tag_font = self.bdfont elif ndef['italic']: self.tag_font = self.itfont if ndef['color']: self.fg = "#%s" % ndef['color'] else: self.fg = None self.text.tag_configure(str(ttype), foreground=self.fg, font=self.tag_font) def recolor(self): self.code = self.text.get("1.0", "end-1c") self.tokensource = self.lexer.get_tokens(self.code) self.start_line = 1 self.start_index = 0 self.end_line = 1 self.end_index = 0 for ttype, value in self.tokensource: if "\n" in value: self.end_line += value.count("\n") self.end_index = len(value.rsplit("\n", 1)[1]) else: self.end_index += len(value) if value not in (" ", "\n"): idx1 = "%s.%s" % (self.start_line, self.start_index) idx2 = "%s.%s" % (self.end_line, self.end_index) for tagname in self.text.tag_names(idx1): self.text.tag_remove(tagname, idx1, idx2) self.text.tag_add(str(ttype), idx1, idx2) self.start_line = self.end_line self.start_index = self.end_index def draw(self): self.filename = None self.path = None self.master.title("PyDE - {}".format("Untitled")) self.master.config(bg="Gray") self.anime__ = Canvas(self.master, width=1200, height=25, bg="Gray", relief=RAISED, highlightbackground='Gray') self.anime__.pack(anchor=NE) self.__display = Label(self.master, text="", bg="Gray", fg="White", padx=55, pady=10, justify=RIGHT, font=("8514oem", 1, 'normal')) self.__display.place(x=0, y=0) self.lcol = Label(self.master, bg="Gray") self.lcol.pack(side=BOTTOM, fill=X) self.scrollx = Scrollbar(self.master, orient=HORIZONTAL) self.scrollx.pack(side=BOTTOM, fill=X) self.text = ST(self.master, xscrollcommand=self.scrollx.set, selectbackground="Gray", fg="Gray", height=400, bg="Black", width=500, wrap=NONE, blockcursor=True) self.text.pack(side=TOP) self.scrollx.config(command=self.text.xview) self.text.config(fg="White", font=("8514oem", self.ftsize, 'bold'), insertbackground="Red") self.l_c = Label(self.lcol, bg="Gray") self.l_c.pack(side=RIGHT) self.timelabel = Label(self.lcol, text="", bg=self.anime__['bg'], font=("8514oem", self.ftsize, "bold")) self.timelabel.place(x=0, y=self.master.winfo_height() - 3) def newfile(self, e): self.filename = None self.path = None self.curname = "Untitled" if len(self.text.get(0.0, END)) > 1: self.asknew = askyesno("File changed", "Save file?") if self.asknew == True: self.savefile_() else: self.text.delete(1.0, END) self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text="Untitled.py") else: self.__display.config(text="Untitled.py") def savefile_(self): if self.filename == None: self.s = asksaveasfile(defaultextension=self.types, filetypes=self.types) self.path = self.s.name self.curname = self.s.name.split("/")[-1] self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text=self.curname) else: self.s.write(self.text.get(1.0, END)) def savefile(self, e): if self.filename == None: self.s = asksaveasfile(defaultextension=self.types, filetypes=self.types) self.path = self.s.name self.curname = self.s.name.split("/")[-1] self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text=self.curname) else: self.s.write(self.text.get(1.0, END)) def openfile(self, e): try: self.o = askopenfile(filetypes=self.types, defaultextension=self.types) self.curname = self.o.name.split("/")[-1] self.path = self.o.name self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text=self.curname) if self.text.edit_modified(): self.a_open = askyesno("save this thing?", "Save file?") if self.a_open == True: self.savefile_() else: pass else: self.text.delete(0.0, END) self.op = self.o.read() self.text.insert(END, self.op) except UnicodeDecodeError: self.unable = showerror("Invalid file", "Invalid file") def openfile_(self): try: if self.text.edit_modified(): self.savefile_() else: self.o = askopenfile(filetypes=self.types, defaultextension=self.types) self.op = self.o.read() self.path = self.o.name self.text.insert(END, self.op) except UnicodeDecodeError: self.unable = showerror("Invalid file", "Invalid file") def animation(self): self.x += 5 self.anime__.delete(ALL) self.anime__.create_image(self.x * 2, self.y + 5, image=self.mario1) if (self.x - 10) >= self.anime__.winfo_width(): self.x = 0 self.master.after(100, self.animation) # self.y-=5 def cur_line_col(self, e): self.l_raw = self.text.index(INSERT) self.lines = self.l_raw.split(".")[0] self.cols = self.l_raw.split(".")[1] self.binder_ = int(self.cols) self.l_c.config(text="lines:{0} columns:{1}".format( self.lines, self.cols), font=("8514oem", 9, 'bold')) def spaces(self, e): self.text.insert(INSERT, " " * 4) return 'break' def indent(self, e): self.tab = " " self.untabbed = self.text.get("sel.first", "sel.last") self.splitted = self.untabbed.split("\n") self.text.delete("sel.first", "sel.last") self.conts = [] for self.conts in list(self.splitted): self.conts = self.tab + self.conts + "\n" self.text.insert(INSERT, self.conts) def dedent(self, e): self.tab = " " self.tabbed = self.text.get("sel.first", "sel.last") self.splitted = self.tabbed.split("\n") self.text.delete("sel.first", "sel.last") self.conts = [] for self.conts in list(self.splitted): self.conts = self.conts.replace(self.tab, "") + "\n" self.text.insert(INSERT, self.conts) def comment(self, e): self.comment = "#" self.uncommented = self.text.get("sel.first", "sel.last") self.split_comment = self.uncommented.split("\n") self.split_comment = list(self.split_comment) self.text.delete("sel.first", "sel.last") self.commconts = [] for self.commconts in self.split_comment: self.commconts = self.comment + self.commconts + "\n" self.text.insert(INSERT, self.commconts) def uncomment(self, e): self.comment = "#" self.commented = self.text.get("sel.first", "sel.last") self.split_uncomm = self.commented.split("\n") self.split_uncomm = list(self.split_uncomm) self.text.delete("sel.first", "sel.last") self.unconts = [] for self.unconts in self.split_uncomm: self.unconts = self.unconts.replace(self.comment, "") + "\n" self.text.insert(INSERT, self.unconts) def runscript(self, e): if self.path == None: self.asksave = askyesno("Save this file?", "Save?") if self.asksave == True: self.savefile() os.system("python {}".format(self.path)) self.result = str( subprocess.check_output(['python', self.path])) self.output = showinfo("Output", "%s" % (self.result)) else: showinfo("Cant run before saving..", "Cant run before saving..") else: os.system("python {}".format(self.path)) self.result = str(subprocess.check_output(['python', self.path])) self.output = showinfo("Output", "%s" % (self.result)) def zoom_in(self, event): self.ftsize += 2 self.bdfont.config(size=self.ftsize) self.itfont.config(size=self.ftsize) self.text.config(font=("8514oem", self.ftsize, 'bold')) def zoom_out(self, e): self.ftsize -= 2 self.bdfont.config(size=self.ftsize) self.itfont.config(size=self.ftsize) self.text.config(font=("8514oem", self.ftsize, "bold")) def display_time(self): self.curtime = strftime("%H : %M : %S") self.timelabel.config(text=self.curtime) self.master.after(1000, self.display_time) def insert_paren(self, e): self.startparams = "([{" self.endparams = ")]}" self.cursor = self.text.index(INSERT) self.linecur = str(self.cursor.split(".")[0]) self.colcur = int(self.cursor.split(".")[1]) if e.char == self.startparams[0]: self.text.insert(INSERT, self.endparams[0]) self.text.mark_set(INSERT, self.linecur + "." + str(self.colcur)) elif e.char == self.startparams[1]: self.text.insert(INSERT, self.endparams[1]) self.text.mark_set(INSERT, self.linecur + "." + str(self.colcur)) elif e.char == self.startparams[2]: self.text.insert(INSERT, self.endparams[2]) self.text.mark_set(INSERT, self.linecur + "." + str(self.colcur)) else: pass def copy_cur_line(self, e): self.linetext = self.text.get("insert linestart", "insert lineend") self.newidx = float(self.text.index(INSERT)) + 1.1 self.text.insert(INSERT, "\n") self.text.insert(self.newidx, self.linetext + "\n") self.text.mark_set("insert", self.newidx) return 'break'
class myPanel(tkinter.Tk): def __init__(self): tkinter.Tk.__init__(self, 'lsx') self.withdraw() # 先withdraw隐藏再deiconify显示可使setCenter不会导致页面闪烁 self.title('电话簿v1.05 (联系作者:QQ11313213)') # TODO 是否有用 self.keys_var = tkinter.StringVar() self.tex1 = ScrolledText(self) ent1 = tkinter.Entry(self, textvariable=self.keys_var, width=125) ent1.pack(padx=2, pady=2, fill=tkinter.constants.BOTH, side=tkinter.constants.TOP) self.tex1.pack(padx=2, pady=2, fill=tkinter.constants.BOTH, expand=True) self.menu = tkinter.Menu(self, tearoff=0) self.menu.add_command(label='复制', command=self.copyItem) self.menu.add_separator() self.menu.add_command(label='来源') self.menu.add_separator() self.menu.add_command(label='刷新', command=readContacts2) self.menu.add_command(label='前后文', command=self.location) self.menu.add_separator() self.menu.add_command(label='导入文件', command=ImportFiles) self.menu.add_command(label='新增和更改', command=UpdateFile) self.menu0 = tkinter.Menu(self, tearoff=0) self.menu0.add_command(label='刷新', command=readContacts2) self.menu0.add_separator() self.menu0.add_command(label='导入文件', command=ImportFiles) self.menu0.add_command(label='新增和更改', command=UpdateFile) self.menu0.add_separator() submenu = [tkinter.Menu(self, tearoff=0)] self.menu0.add_cascade(label='Designed by Lsx. ', menu=submenu[0]) for key, value in [['Name', 'Li Shixian'], ['Mail', '*****@*****.**'], ['Website', 'github.com/znsoooo/contacts'], ['Wechat', 'Xian_2'], ['Donate', 'xxxx']]: submenu.append(tkinter.Menu(self, tearoff=0)) submenu.append(tkinter.Menu(self, tearoff=0)) submenu[-1].add_command(label=value) submenu[0].add_cascade(label=key, menu=submenu[-1]) self.img_wechat = tkinter.PhotoImage( data=Image.img1) # 没有self会导致显示图片为空白 self.img_donate = tkinter.PhotoImage(data=Image.img2) submenu[8].entryconfig(0, image=self.img_wechat) submenu[10].entryconfig(0, image=self.img_donate) submenu[0].add_separator() submenu[0].add_command(label='All Rights Reserved.', command=bonus) setCenter(self) self.deiconify() ent1.focus() ent1.bind('<KeyRelease>', self.onKeyRelease) self.tex1.bind('<ButtonRelease-3>', self.onRightClick) def select(self, row): self.tex1.mark_set('insert', '%d.0' % row) self.tex1.tag_remove('sel', '0.0', 'end') self.tex1.tag_add('sel', '%d.0' % row, '%d.0' % (row + 1)) def location(self, row=0): if not row: row = self.current_index + 1 self.onKeyRelease(keys='') self.select(row) self.tex1.see('%d.0' % row) def copyItem(self): text = self.tex1.selection_get() self.clipboard_clear() self.clipboard_append(text[:-1]) # 去掉文末换行符 def onRightClick(self, evt=0): self.tex1.focus() # 当焦点在ent1中时 self.current = int(self.tex1.index('current').split('.')[0]) if len(self.index): self.current_index = self.index[self.current - 1] line_last = 0 for line, file in file_list: if line > self.current_index: break else: line_last = line self.menu.entryconfig(2, label='来源: %s (line:%s)' % (file, self.current_index - line_last + 1)) self.menu.entryconfig( 2, command=lambda: os.popen('explorer /select, %s\\%s\\%s' % (os.getcwd(), DATA_FOLDER, file))) self.select(self.current) self.menu.post(evt.x_root, evt.y_root) else: self.menu0.post(evt.x_root, evt.y_root) return self.current def onKeyRelease(self, evt=0, keys=None): if keys is None: keys = self.keys_var.get() keys = keys.lower().split(' ') ss_new = [] self.index = [] for n, s in enumerate(ss): ok = True for key in keys: if key not in s[1]: ok = False if ok: ss_new.append(s[0]) self.index.append(n) # TODO 提出搜索部分到独立的函数 self.tex1.config(state='normal') self.tex1.delete('1.0', 'end') self.tex1.insert('1.0', '\n'.join(ss_new)) self.tex1.config(state='disabled') # 禁止编辑 self.title('电话簿v1.05 (联系作者:QQ11313213) - %s结果' % len(ss_new)) # title更改耗时短可以做到'同时'更改的效果 return ss_new
class NoteEditor: def __init__(self): self.id = None self.page_name = None self.font_name = 'arial' self.font_size = 12 self.font_weight = tk.NORMAL self.editor = None self.file_io = FileIO() self.syntax_file_io = FileIO() def create_editor(self, master): self.editor = ScrolledText(master, undo=True, autoseparators=True, maxundo=-1) # Styling of text area self.set_editor_font(None, None) self.editor.pack(side="left") self.editor.focus() self.editor.pack(fill="both", expand=True) # Configuring style tags self.editor.tag_config("BACKGROUND", background="yellow") self.editor.tag_configure("HIGHLIGHT", foreground="red") self.editor['wrap'] = tk.NONE self.editor.bind('<Button-3>', self.rClicker, add='') def set_editor_font(self, font_name, font_size, font_weight=None): if font_name is not None: self.font_name = font_name if font_size is not None and int(font_size) > 0: self.font_size = font_size if font_weight is not None: self.font_weight = font_weight self.editor['font'] = Font(family=self.font_name, size=self.font_size, weight=self.font_weight) def set_editor_bgcolor(self, hex_color): self.editor['background'] = hex_color def set_editor_fgcolor(self, hex_color): self.editor['foreground'] = hex_color def set_emphasis(self, on): if on == 1: bold_font = Font(family=self.font_name, size=self.font_size, weight="bold") self.editor.tag_configure("BOLDFONT", font=bold_font) if self.editor.tag_ranges(tk.SEL): self.editor.tag_add("BOLDFONT", tk.SEL_FIRST, tk.SEL_LAST) else: self.editor.tag_add("BOLDFONT", "1.0", tk.END) else: self.editor.tag_remove("BOLDFONT", "1.0", tk.END) def toggle_wrap(self, on): if on == 1: self.editor['wrap'] = tk.WORD else: self.editor['wrap'] = tk.NONE def search_forward(self, text): located_start = self.editor.search(text, tk.INSERT, stopindex=tk.END, forwards=True, nocase=True) located_end = '{}+{}c'.format(located_start, len(text)) if located_start is '' or located_end is '': return False self.select_editor_location(located_start, located_end) # Start position is moved after current found location. self.editor.mark_set(tk.INSERT, located_end) return True def search_backward(self, text): located_start = self.editor.search(text, tk.INSERT, stopindex='1.0', backwards=True, nocase=True) located_end = '{}+{}c'.format(located_start, len(text)) if located_start is '' or located_end is '': return False self.select_editor_location(located_start, located_end) # Start position is moved after current found location. self.editor.mark_set(tk.INSERT, located_start) return True def replace_selected_text(self, new_text): self.editor.delete('sel.first', 'sel.last') self.editor.insert('insert', new_text) def select_editor_location(self, selection_start, selection_end): print('Found location start: ', selection_start) print('Found location end: ', selection_end) selection_start_float = float(selection_start) self.editor.tag_remove(tk.SEL, "1.0", 'end') self.editor.tag_add(tk.SEL, selection_start, selection_end) self.editor.focus_force() self.editor.see(selection_start_float) def is_dirty(self): return self.editor.edit_modified() def rClicker(self, e): ''' right click context menu for all Tk Entry and Text widgets ''' try: def rClick_Copy(e, apnd=0): e.widget.event_generate('<Control-c>') def rClick_Cut(e): e.widget.event_generate('<Control-x>') def rClick_Paste(e): e.widget.event_generate('<Control-v>') def rClick_Highlight_Keyword(e): self.highlight_syntax(True) e.widget.focus() nclst = [ (' Cut', lambda e=e: rClick_Cut(e)), (' Copy', lambda e=e: rClick_Copy(e)), (' Paste', lambda e=e: rClick_Paste(e)), (' Highlight Keyword', lambda e=e: rClick_Highlight_Keyword(e)), ] rmenu = tk.Menu(None, tearoff=0, takefocus=0) for (txt, cmd) in nclst: rmenu.add_command(label=txt, command=cmd) rmenu.tk_popup(e.x_root + 40, e.y_root + 10, entry="0") except tk.TclError: print ' - rClick menu, something wrong' pass return "break" def highlight_syntax(self, enable=True): syntax_file = Path(Path( self.file_io.file_name).suffix[1:]).with_suffix('.hs') hs_config_data = Configuration.get_hs_configuration(syntax_file) if hs_config_data is None: print('No syntax file ', syntax_file) return #print(hs_config_data) keywords = hs_config_data['keyword']['tags'] keyword_fgcolor = hs_config_data['keyword']['color'] constant_fgcolor = hs_config_data['constant']['color'] numbers = re.findall(r'\d{1,3}', self.file_io.file_data) self.editor.tag_config('tg_kw', foreground=keyword_fgcolor) self.editor.tag_config('tg_num', foreground=constant_fgcolor) #keywords = ['package', 'public', 'private', 'abstract', 'internal', 'new', 'static', 'final', 'long', 'extends', # 'class', 'import', 'null', 'for', 'if', 'return', 'int', 'char', 'float', 'double', 'implements'] for keyword in keywords: self.editor.mark_set(tk.INSERT, '1.0') while True: located_end = self.highlight_keyword(keyword + ' ', 'tg_kw') if located_end == 0: break self.editor.mark_set(tk.INSERT, located_end) self.editor.mark_set(tk.INSERT, '1.0') for each_number in numbers: located_end = self.highlight_keyword(each_number, 'tg_num') if located_end != 0: self.editor.mark_set(tk.INSERT, located_end) print("Syntax highlight executed.") def highlight_keyword(self, text, tag): located_start = self.editor.search(text, tk.INSERT, stopindex=tk.END, forwards=True, nocase=False) located_end = '{}+{}c'.format(located_start, len(text)) print(located_start, ',', located_end) print('keyword', text) if located_start is '' or located_end is '': return 0 self.editor.tag_add(tag, located_start, located_end) return located_end