def descripText(destroy = False): 'Laat de puntentelling zien op het spelscherm' T.pack_forget() global hint, root, destxt destxt = ScrolledText(root, height=8, width=50, padx=170, pady=50) destxt.pack() destxt.insert(END, hint) destxt.config(state=DISABLED) destxt.tag_configure("center", justify='center') destxt.tag_add("center", 1.0, "end") destxt.place(relx=1, x=-2, y=2, anchor=NE)
def _init_message_box(): """初始化信息框""" message_box = ScrolledText(MAIN_TK) message_box.pack(side=BOTTOM, fill=BOTH) # 设置消息展示样式 message_box.tag_configure('info', font=('微软雅黑', 8), foreground='#303133') message_box.tag_configure('warning', font=('微软雅黑', 10), foreground='#ebb563') message_box.tag_configure('error', font=('微软雅黑', 12, 'bold'), foreground='#f56c6c') message_box.tag_configure('success', font=('微软雅黑', 14, 'bold'), foreground='#85ce61') return message_box
class Logger(Frame): ERROR, BORRING, EVENT, NORMAL = "error", "borring", "event", None def __init__(self, *args, **kw): text_height = kw.pop("text_height", 25) Frame.__init__(self, *args, **kw) self.deque = deque() self.txt = ScrolledText(self, wrap=WORD, state=DISABLED, relief=SUNKEN, height=text_height) self.txt.grid(column=0, row=0, sticky=(N, W, E, S)) self.txt.configure(LoggerColors.default) for k, v in LoggerColors.tags.items(): self.txt.tag_configure(k, v) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.after(100, self._toscreen) def __call__(self, *args): self.deque.appendleft(args) def _toscreen(self): if len(self.deque): self.txt["state"] = NORMAL while(len(self.deque)): self.txt.insert( END, "\n[{}] ".format(strftime("%H:%M:%S")), "time", *self.deque.pop()) self.txt.yview(END) self.txt["state"] = DISABLED self.after(100, self._toscreen)
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 textEditor(): alltabs = None def __init__(self, window, labelFrame, tabs, vocab, startWithSameLetter, tabsOpen, file_path=""): self.window = window # record the directory path of the file self.file_path = file_path if file_path: self.file_name = self.file_path else: # if the file path doesn't exist, name it accordingly self.file_name = 'Untitled' # record the necessary passed-in parameters self.labelFrame = labelFrame self.tabsOpen = tabsOpen self.tabs = tabs self.vocab = vocab self.startWithSameLetter = startWithSameLetter # create the main gui elements in the respective tab frame self.notepad = ScrolledText(self.labelFrame, font=("Calibri", 15)) editorbox = self.notepad self.var = tk.IntVar() self.autoCorrectOption = tk.Checkbutton(self.labelFrame, \ text="Enable Auto-Correct", variable=self.var, command=self.switchSpellChecker) self.autoComplete_suggestions = tk.Listbox(self.labelFrame) self.autoCorrect_suggestions = tk.Listbox(self.labelFrame) myFont = Font(family="Calibri", size=15) self.autoComplete_suggestions.configure(font=myFont) self.autoCorrect_suggestions.configure(font=myFont) # create funtionality bars inside tab frame self.createMenuBar() self.createToolBar(self.labelFrame) self.autoCorrectOption.grid(row=1, column=9) self.notepad.config(undo=True) self.notepad.config(height=900) self.notepad.grid(row=2, column=0, columnspan=11, sticky="WE") self.window.protocol("WM_DELETE_WINDOW", lambda: newFileTab.closeCheck(self.tabsOpen)) # add pre-set markup on the entire text widget in the tab frame self.notepad.tag_configure("misspelling", foreground="red", underline=True) # bind all navigation to checking the spelling of the word self.nav_click = self.notepad.bind("<ButtonRelease-1>", self.spellChecker) self.nav_up = self.notepad.bind("<Up>", self.spellChecker) self.nav_down = self.notepad.bind("<Down>", self.spellChecker) self.nav_left = self.notepad.bind("<Left>", self.spellChecker) self.nav_right = self.notepad.bind("<Right>", self.spellChecker) # check each word's spelling after typed and mark it up self.notepad.bind("<space>", self.markUp) self.notepad.bind(".", self.markUp) # keep calling autocomplete while user is writing for letter in "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM": self.notepad.bind("<KeyRelease-" + letter + ">", self.autoComplete) self.notepad.bind("<KeyRelease-BackSpace>", self.autoComplete) # bind file shortcuts self.notepad.bind('<Control-s>', newFileTab.saveToFile) self.notepad.bind('<Control-o>', newFileTab.openFile) self.notepad.bind('<Control-n>', newFileTab.createFile) self.notepad.bind('<Control-c>', newFileTab.copySelected) self.notepad.bind('<Control-x>', newFileTab.cutSelected) self.notepad.bind('<Control-v>', newFileTab.pasteClipboard) # this function creates the top menu bar including all functionalities def createMenuBar(self): menuBar = Menu(self.window) # create drop-down options for the file menu fileMenu = tk.Menu(menuBar, tearoff=0) fileMenu.add_command( label="New Document", command=lambda: newFileTab.createFile(self.tabsOpen)) fileMenu.add_command( label="Open Local File", command=lambda: newFileTab.openFile(self.tabsOpen)) fileMenu.add_command( label="Save file", command=lambda: newFileTab.saveToFile(self.tabsOpen)) fileMenu.add_separator() fileMenu.add_command( label="Close File", command=lambda: newFileTab.closeFile(self.tabsOpen)) fileMenu.add_command(label="Exit", command=lambda: newFileTab.quit(self.tabsOpen)) menuBar.add_cascade(label="File", menu=fileMenu) # create drop-down options for the edit menu editMenu = tk.Menu(menuBar, tearoff=0) editMenu.add_command( label="Undo", command=lambda: newFileTab.undoEdit(self.tabsOpen)) editMenu.add_command( label="Redo", command=lambda: newFileTab.redoEdit(self.tabsOpen)) editMenu.add_command( label="Copy", command=lambda: newFileTab.copySelected(self.tabsOpen)) editMenu.add_command( label="Cut", command=lambda: newFileTab.cutSelected(self.tabsOpen)) editMenu.add_command( label="Paste", command=lambda: newFileTab.pasteClipboard(self.tabsOpen)) menuBar.add_cascade(label="Edit", menu=editMenu) self.window.config(menu=menuBar) '''icon pics retrieved from: https://icons-for-free.com/folder+open+icon-1320161390409087972/''' # this function creates the tool bar with clickable icon shortcuts for the functionalities def createToolBar(self, labelFrame): # add icon for handling creating new files new_img = tk.PhotoImage(file="newicon.png") new_img = new_img.zoom(1) new_img = new_img.subsample(15) # add icon for handling opening local files open_img = tk.PhotoImage(file="openicon.png") open_img = open_img.zoom(1) open_img = open_img.subsample(15) # add icon for handling saving files save_img = tk.PhotoImage(file="saveicon.png") save_img = save_img.zoom(1) save_img = save_img.subsample(4) # add icon for handling copying from files copy_img = tk.PhotoImage(file="copyicon.png") copy_img = copy_img.zoom(1) copy_img = copy_img.subsample(4) # add icon for handling cutting from files cut_img = tk.PhotoImage(file="cuticon.png") cut_img = cut_img.zoom(1) cut_img = cut_img.subsample(4) # add icon for handling cutting from clipboard paste_img = tk.PhotoImage(file="pasteicon.png") paste_img = paste_img.zoom(1) paste_img = paste_img.subsample(4) # add icon for handling undo edits undo_img = tk.PhotoImage(file="undoicon.png") undo_img = undo_img.zoom(1) undo_img = undo_img.subsample(4) # add icon for handling redo edits redo_img = tk.PhotoImage(file="redoicon.png") redo_img = redo_img.zoom(1) redo_img = redo_img.subsample(4) # add icon for handling closing current file tab close_img = tk.PhotoImage(file="closeicon.png") close_img = close_img.zoom(1) close_img = close_img.subsample(4) # create all respective buttons and configure them to their appropriate icons and function calls new_button = tk.Button( labelFrame, image=new_img, command=lambda: newFileTab.createFile(self.tabsOpen)) open_button = tk.Button( labelFrame, image=open_img, command=lambda: newFileTab.openFile(self.tabsOpen)) save_button = tk.Button( labelFrame, image=save_img, command=lambda: newFileTab.saveToFile(self.tabsOpen)) copy_button = tk.Button( labelFrame, image=copy_img, command=lambda: newFileTab.copySelected(self.tabsOpen)) cut_button = tk.Button( labelFrame, image=cut_img, command=lambda: newFileTab.cutSelected(self.tabsOpen)) paste_button = tk.Button( labelFrame, image=paste_img, command=lambda: newFileTab.pasteClipboard(self.tabsOpen)) undo_button = tk.Button( labelFrame, image=undo_img, command=lambda: newFileTab.undoEdit(self.tabsOpen)) redo_button = tk.Button( labelFrame, image=redo_img, command=lambda: newFileTab.redoEdit(self.tabsOpen)) close_button = tk.Button( labelFrame, image=close_img, command=lambda: newFileTab.closeFile(self.tabsOpen)) new_button.image = new_img open_button.image = open_img save_button.image = save_img copy_button.image = copy_img cut_button.image = cut_img paste_button.image = paste_img undo_button.image = undo_img redo_button.image = redo_img close_button.image = close_img # grid the buttons appropriately onto the tab frame new_button.grid(row=1, column=1) open_button.grid(row=1, column=2) save_button.grid(row=1, column=3) copy_button.grid(row=1, column=4) cut_button.grid(row=1, column=5) paste_button.grid(row=1, column=6) undo_button.grid(row=1, column=7) redo_button.grid(row=1, column=8) close_button.grid(row=1, column=10) # this function takes automatically the first choice from the suggestion # box and replaces it with the word that is underlined as misspelt def autoCorrect(self, event): lastWord = self.getLastWord() if self.spellCheckerList(lastWord): # get first suggestiosn from listbox contents bestSuggestion = self.spellCheckerList(lastWord)[0] # configure and find first and last index of word to be replaced start = self.notepad.get('1.0', tk.END).index(lastWord) end = start + len(lastWord) line_num = int(float(self.notepad.index(tk.CURRENT))) start_i = str(line_num) + '.' + str(start) end_i = str(line_num) + '.' + str(end) # delete the misspelled word by the best suggestion in text widget self.notepad.delete(start_i, end_i) self.notepad.insert(start_i, bestSuggestion) # this function unbinds the arrows with the list from the dictionary # so that the list dosen't appear when pressing the auto-correct option def switchSpellChecker(self): self.notepad.unbind('<ButtonRelease-1>') self.notepad.unbind('<Up>') self.notepad.unbind('<Down>') self.notepad.unbind('<Left>') self.notepad.unbind('<Right>') self.notepad.unbind("<space>") # if the autocorrect option is pressed if self.var.get(): # replace the spellchecker bindings to autocorrect self.notepad.bind("<space>", self.autoCorrect) self.notepad.bind(".", self.autoCorrect) # if it is not pressed else: # rebind the orginal keys for the spellchecker listbox functionality self.notepad.bind("<ButtonRelease-1>", self.spellChecker) self.notepad.bind("<Up>", self.spellChecker) self.notepad.bind("<Down>", self.spellChecker) self.notepad.bind("<Left>", self.spellChecker) self.notepad.bind("<Right>", self.spellChecker) # check each word's spelling after typed and mark it up self.notepad.bind("<space>", self.isSpeltCorrect) self.notepad.bind(".", self.isSpeltCorrect) # this function gets the last word that was typed by the user def getLastWord(self): # split all input text at all white space characters (e.g. space, tab, enter) wordsList = re.split("\s+", self.notepad.get("1.0", tk.END)) # remove last empty string wordsList.remove('') # last word is at the last index of the words list lastWord = wordsList[len(wordsList) - 1] # remove unnecessary punctuations next to the last word lastWord_stripped = lastWord.translate( str.maketrans('', '', string.punctuation)) return lastWord_stripped.lower() # here we edit the words that are misspelt after # getting the words from the screen and correct their form def spellCheckerList(self, word_to_check): edits = {} # if there's no word selected or a space is selected if word_to_check == "" or word_to_check == " ": return # if the word is misspelt, record its respective edit distances and frequencies elif not self.isSpeltCorrect(word_to_check): # compute for min edit distance from each word in dictionary for word in self.vocab: edits_num = self.minEditDistance(word_to_check, word) # record all words corresponding to edits numbers 1 and 2 in a dictionary if edits_num <= 2: # if there is a key in the dictionary corresponding to the same edit distance if edits_num in edits: # add it to its list of values edits[edits_num].append(word) else: # if not, create a new key for the number of edits and add it edits[edits_num] = [word] # record and sort frequencies of words corresponding for 1 edit and 2 edits freqs1 = [] freqs2 = [] # sorting words with edit distance 1 one based on frequency if 1 in edits: for similar_word in edits.get(1): # record frequency of each word with the same edit distance freq = self.vocab.get(similar_word) freqs1.append(freq) # sorting words with edit distance 1 one based on frequency if 2 in edits: for similar_word in edits.get(2): # record frequency of each word with the same edit distance freq = self.vocab.get(similar_word) freqs2.append(freq) # rearrange frequencies individually freqs1.sort() freqs2.sort() # combine the two frequency lists in order of 1 then 2 to get appropriate suggestions list # the smallest edit distance if the first priority, then its frequency freqs = freqs1 + freqs2 suggestions = [] for f in freqs: for word in self.vocab: # get words based on their corresponding frequencies in order if self.vocab.get(word) == f: # add each corresponding word to the suggestions list suggestions.append(word) return suggestions '''STILL TO DO, CONSIDER CAPITALIZATION IN SPELLCHECKER and replacement word/pop-up lists''' # this function checks if the word is spelt correctly or not # it returns a boolean value based on this condition def isSpeltCorrect(self, word): if word in self.vocab: return True return False # this functions recognizes the word and finds similar words # depending on their frequency, this will be then added to the # suggestion list. this function updates after typing each charachter def autoCompleteList(self, e): typed_word = self.getCurrWord(e).lower() if typed_word == "": return freqs = [] suggestions = [] inp_length = len(typed_word) for word in self.vocab: # check for english words that start with the same characters if word[:inp_length].lower() == typed_word: print('hi') # record the frequency ranks of such words freq = self.vocab.get(word) freqs.append(freq) # order frequencies freqs.sort() for f in freqs: for word in self.vocab: # get words based on their corresponding frequencies in order if self.vocab.get(word) == f: suggestions.append(word) return suggestions # this function takes the list of words suggested if any and # inserts them on the screen in the autocomplete suggestions listbox def autoComplete(self, event): self.autoComplete_suggestions.destroy() self.autoComplete_suggestions = tk.Listbox(window) myFont = Font(family="Calibri", size=15) self.autoComplete_suggestions.configure(font=myFont) word = self.getCurrWord(event).lower() # ignore autocomplete call if the word is empty if not word: return # if there is one character typed if len(word) == 1: # use pre-loaded dictionary to get suggestiosn into listbox suggestions = self.startWithSameLetter.get(word) i = 0 # add the first 10 word suggestions, as long as they exist while i < 11 and i < len(suggestions): for l in suggestions: # add them to the suggestions listbox in order self.autoComplete_suggestions.insert(i, l + " ") i += 1 else: # if typed portion is a part of a valid word if self.autoCompleteList(event): # get autocomplete list and append its first 10 values into the listbox suggestions = self.autoCompleteList(event)[:10] for i in range(len(suggestions)): self.autoComplete_suggestions.insert( i, suggestions[i] + " ") # if not, indicate lack of matches on listbox else: self.autoComplete_suggestions.insert(0, "No matches found.") # remove duplicate words in the suggestions listbox and the typed word if word in self.autoComplete_suggestions.get(0, tk.END): index = self.autoComplete_suggestions.get(0, tk.END).index(word) # delete duplicate word from suggestions listbox self.autoComplete_suggestions.delete(index) # if there are more suggestions available after 10, add the next one if len(self.autoCompleteList(event)) >= 11: self.autoComplete_suggestions.insert( 10, self.autoCompleteList(event)[10] + " ") # place the listbox where the typing cursor is (x, y, w, h) = self.notepad.bbox('insert') self.autoComplete_suggestions.place(x=x + 140, y=y + 200, anchor="center") self.autoComplete_suggestions.bind('<<ListboxSelect>>', self.autoCompleteClickSelect) # this function also draws a list box with all the suggested words that # could replace the misspelt word. def spellChecker(self, event): self.autoComplete_suggestions.destroy() self.autoCorrect_suggestions.destroy() self.autoCorrect_suggestions = tk.Listbox(self.labelFrame) myFont = Font(family="Calibri", size=15) self.autoCorrect_suggestions.configure(font=myFont) # if the selected word is the one being currently typed # autocomplete it and don't spellcheck it (word not fully typed yet) '''if self.getCurrWord(event) and self.getNavigWord(event): self.autoComplete(event) return''' word = self.getNavigWord(event) # if the suggestions listbox is not empty, clear it if len(self.autoCorrect_suggestions.get(0, tk.END)) != 0: self.autoCorrect_suggestions.delete(0, tk.END) # exit spell checker if the word is spelt correctly if self.isSpeltCorrect(word): return # if current word is not empty and is spelled incorrectly elif len(self.notepad.get('1.0', 'end-1c')) != 0: if self.spellCheckerList(word): # append first 10 suggestions into listbox suggestions = self.spellCheckerList(word)[:10] for i in range(len(suggestions)): self.autoCorrect_suggestions.insert(i, suggestions[i]) else: # if not close matches from min edit function, display appropriate message self.autoCorrect_suggestions.insert(0, "No matches found.") self.autoCorrect_suggestions.insert(1, "Add word to dictionary") if len(word) != 1: # place the listbox where the cursor is (x, y, w, h) = self.notepad.bbox('insert') self.autoCorrect_suggestions.place(x=x + 115, y=y + 160, anchor="center") self.autoComplete_suggestions = tk.Listbox(self.labelFrame) myFont = Font(family="Calibri", size=15) self.autoComplete_suggestions.configure(font=myFont) self.autoCorrect_suggestions.bind('<<ListboxSelect>>', self.autoCorrectClickSelect) # this function takes the selection that the user made from the suggestion box # and overwrites the word in he screen def autoCorrectClickSelect(self, event): selected_word = self.autoCorrect_suggestions.get( self.autoCorrect_suggestions.curselection()) # get the entire word the cursor is on navigWord = self.getNavigWord(event) if selected_word == "No matches found.": self.autoCorrect_suggestions.destroy() return elif selected_word == "Add word to dictionary": self.vocab[navigWord] = len(self.vocab) + 1 else: start = self.notepad.get('1.0', tk.END).index(navigWord) end = start + len(navigWord) line_num = int(float(self.notepad.index(tk.CURRENT))) # configure start and end indices of the word to be corrected syntax correctly start_i = str(line_num) + '.' + str(start) end_i = str(line_num) + '.' + str(end) # delete the misspelled word and replace it by the correct one selected from the listbox self.notepad.delete(start_i, end_i) self.notepad.insert(start_i, selected_word) if self.autoCorrect_suggestions.winfo_exists: self.autoCorrect_suggestions.destroy() # this function takes the selection that the user made from the suggestion box # and overwrites the word in the screen for the autocomplete option def autoCompleteClickSelect(self, event): if self.autoComplete_suggestions.curselection(): selected_word = self.autoComplete_suggestions.get( self.autoComplete_suggestions.curselection()) if selected_word == "No matches found.": self.autoComplete_suggestions.destroy() return # get the partial word currently being typed currWord = self.getCurrWord(event).lower() # configure start and end indices of the word to be corrected syntax correctly start = self.notepad.get('1.0', tk.END).index(currWord) end = start + len(currWord) line_num = int(float(self.notepad.index(tk.CURRENT))) start_i = str(line_num) + '.' + str(start) end_i = str(line_num) + '.' + str(end) # delete the misspelled word and replace it by the correct one selected from the listbox self.notepad.delete(start_i, end_i) self.notepad.insert(start_i, selected_word) self.autoComplete_suggestions.destroy() # this function underlines the word that is misspelt and # colors it with red def markUp(self, misspelt_word): lastWord = self.getLastWord() # if word contains numbers of special characters, don't mark it up if not lastWord.isalpha(): return self.autoComplete_suggestions.destroy() # search for starting index of the misspelt word index = self.notepad.search(r'\s', "insert", backwards=True, regexp=True) if index == "": index = "1.0" else: index = self.notepad.index("%s+1c" % index) word = self.notepad.get(index, "insert").translate( str.maketrans('', '', string.punctuation)) # if word spelled correctly, remove pre-set misspelling tag if word.lower() in self.vocab: self.notepad.tag_remove("misspelling", index, "%s+%dc" % (index, len(word))) else: self.notepad.tag_add("misspelling", index, "%s+%dc" % (index, len(word))) '''modfiied code from: https://stackoverflow.com/questions/3732605/add-advanced-features-to-a-tkinter-text-widget''' # This function finds the minimum edit distance using a modified version of the Levistein algorithm # This is my own implementation of the algorithm def minEditDistance(self, misspelt_word, vocab_word): rows = len(misspelt_word) + 1 columns = len(vocab_word) + 1 matrix = [] # split list of lists based on rows # initialize values for column contents for each row for i in range(rows): matrix.append([]) for j in range(columns): matrix[i].append(-1) # empty string row first_row = [] for n in range(columns): first_row.append(n) matrix = [first_row] + matrix[1:] # add first column values in matrix n = 0 for i in range(rows): matrix[i][0] = n n += 1 # for each letter of the misspelt word for r in range(rows - 1): # go through each letter in the vocab word for c in range(columns - 1): # if the letters are the same if vocab_word[c] == misspelt_word[r]: # copy down the value at the relative left diagonal position in the matrix # into the corresponding matrix position of the current string comparison matrix[r + 1][c + 1] = matrix[r][c] # if letters are different else: # take the minimum value of the three upper left diagonals to the current position adj_min = min(matrix[r][c], matrix[r][c + 1], matrix[r + 1][c]) # add 1 to get the minimum additional edit to transform the two strings parts so far # add resulting value into corresponding matrix position matrix[r + 1][c + 1] = adj_min + 1 # minimum number of edits is the last computed value of the matrix minEdits = matrix[rows - 1][columns - 1] return minEdits # this function gets the word that the cursor is hovering over in the text widget # and returns it. def getNavigWord(self, event): start = self.notepad.index("insert wordstart") end = self.notepad.index("insert wordend") nav_word = self.notepad.get(start, end) # remove unnecessary punctuations next to the typed word nav_word_stripped = nav_word.translate( str.maketrans('', '', string.punctuation)) return nav_word_stripped.lower() # this function gets the word that is being modified currently from the user # and returns it. def getCurrWord(self, event): all_typed = self.notepad.get("1.0", "end") i = all_typed.rfind(" ") curr_word = all_typed[i + 1:].strip() # remove unnecessary punctuations next to the typed word curr_word_stripped = curr_word.translate( str.maketrans('', '', string.punctuation)) return curr_word_stripped.lower()
class Application(tkinter.Tk): def __init__(self): """Initialize widgets, methods.""" tkinter.Tk.__init__(self) self.grid() fontoptions = families(self) font = Font(family="Verdana", size=10) menubar = tkinter.Menu(self) fileMenu = tkinter.Menu(menubar, tearoff=0) editMenu = tkinter.Menu(menubar, tearoff=0) fsubmenu = tkinter.Menu(editMenu, tearoff=0) ssubmenu = tkinter.Menu(editMenu, tearoff=0) # adds fonts to the font submenu and associates lambda functions for option in fontoptions: fsubmenu.add_command(label=option, command = lambda: font.configure(family=option)) # adds values to the size submenu and associates lambda functions for value in range(1,31): ssubmenu.add_command(label=str(value), command = lambda: font.configure(size=value)) # adds commands to the menus menubar.add_cascade(label="File",underline=0, menu=fileMenu) menubar.add_cascade(label="Edit",underline=0, menu=editMenu) fileMenu.add_command(label="New", underline=1, command=self.new, accelerator="Ctrl+N") fileMenu.add_command(label="Open", command=self.open, accelerator="Ctrl+O") fileMenu.add_command(label="Save", command=self.save, accelerator="Ctrl+S") fileMenu.add_command(label="Exit", underline=1, command=exit, accelerator="Ctrl+Q") editMenu.add_command(label="Copy", command=self.copy, accelerator="Ctrl+C") editMenu.add_command(label="Cut", command=self.cut, accelerator="Ctrl+X") editMenu.add_command(label="Paste", command=self.paste, accelerator="Ctrl+V") editMenu.add_cascade(label="Font", underline=0, menu=fsubmenu) editMenu.add_cascade(label="Size", underline=0, menu=ssubmenu) editMenu.add_command(label="Color", command=self.color) editMenu.add_command(label="Bold", command=self.bold, accelerator="Ctrl+B") editMenu.add_command(label="Italic", command=self.italic, accelerator="Ctrl+I") editMenu.add_command(label="Underline", command=self.underline, accelerator="Ctrl+U") editMenu.add_command(label="Overstrike", command=self.overstrike, accelerator="Ctrl+T") editMenu.add_command(label="Undo", command=self.undo, accelerator="Ctrl+Z") editMenu.add_command(label="Redo", command=self.redo, accelerator="Ctrl+Y") self.config(menu=menubar) """Accelerator bindings. The cut, copy, and paste functions are not bound to keyboard shortcuts because Windows already binds them, so if Tkinter bound them as well whenever you typed ctrl+v the text would be pasted twice.""" self.bind_all("<Control-n>", self.new) self.bind_all("<Control-o>", self.open) self.bind_all("<Control-s>", self.save) self.bind_all("<Control-q>", self.exit) self.bind_all("<Control-b>", self.bold) self.bind_all("<Control-i>", self.italic) self.bind_all("<Control-u>", self.underline) self.bind_all("<Control-T>", self.overstrike) self.bind_all("<Control-z>", self.undo) self.bind_all("<Control-y>", self.redo) self.text = ScrolledText(self, state='normal', height=30, wrap='word', font = font, pady=2, padx=3, undo=True) self.text.grid(column=0, row=0, sticky='NSEW') # Frame configuration self.grid_columnconfigure(0, weight=1) self.resizable(True, True) """Command functions. *args is included because the keyboard bindings pass two arguments to the functions, while clicking in the menu passes only 1.""" def new(self, *args): """Creates a new window.""" app = Application() app.title('Python Text Editor') app.option_add('*tearOff', False) app.mainloop() def color(self): """Changes selected text color.""" try: (rgb, hx) = tkinter.colorchooser.askcolor() self.text.tag_add('color', 'sel.first', 'sel.last') self.text.tag_configure('color', foreground=hx) except TclError: pass def bold(self, *args): """Toggles bold for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "bold" in current_tags: self.text.tag_remove("bold", "sel.first", "sel.last") else: self.text.tag_add("bold", "sel.first", "sel.last") bold_font = Font(self.text, self.text.cget("font")) bold_font.configure(weight="bold") self.text.tag_configure("bold", font=bold_font) except TclError: pass def italic(self, *args): """Toggles italic for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "italic" in current_tags: self.text.tag_remove("italic", "sel.first", "sel.last") else: self.text.tag_add("italic", "sel.first", "sel.last") italic_font = Font(self.text, self.text.cget("font")) italic_font.configure(slant="italic") self.text.tag_configure("italic", font=italic_font) except TclError: pass def underline(self, *args): """Toggles underline for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "underline" in current_tags: self.text.tag_remove("underline", "sel.first", "sel.last") else: self.text.tag_add("underline", "sel.first", "sel.last") underline_font = Font(self.text, self.text.cget("font")) underline_font.configure(underline=1) self.text.tag_configure("underline", font=underline_font) except TclError: pass def overstrike(self, *args): """Toggles overstrike for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "overstrike" in current_tags: self.text.tag_remove("overstrike", "sel.first", "sel.last") else: self.text.tag_add("overstrike", "sel.first", "sel.last") overstrike_font = Font(self.text, self.text.cget("font")) overstrike_font.configure(overstrike=1) self.text.tag_configure("overstrike", font=overstrike_font) except TclError: pass def undo(self, *args): """Undo function""" try: self.text.edit_undo() except TclError: pass def redo(self, *args): """Redo function""" try: self.text.edit_redo() except TclError: pass def copy(self, *args): """Copy text""" self.clipboard_clear() self.clipboard_append(self.text.selection_get()) def cut(self, *args): """Cut text""" self.copy self.text.delete("sel.first", "sel.last") def paste(self, *args): """Paste text""" insertion = self.selection_get(selection = "CLIPBOARD") self.text.insert(0.0, insertion) def open(self, *args): """Opens a file dialog to open a plain text file.""" filename = tkinter.filedialog.askopenfilename() with open(filename) as f: text = f.read() self.text.delete("1.0", "end") self.text.insert('insert', text) def save(self, *args): try: """Opens a file dialog to save the text in plain text format.""" text = self.text.get("1.0", "end") filename = tkinter.filedialog.asksaveasfilename() with open(filename, 'w') as f: f.write(text) except FileNotFoundError: pass def exit(self, *args): """Exits the program.""" self.quit()
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 MainWindow(Frame): def __init__(self, root=None, width=0.6, height=0.75, size=10, use_factor=True): self.__root = root Frame.__init__(self, self.__root) # MainWindow size w, h, x, y = get_geometry(self, width, height, use_factor) self.__root.geometry('%dx%d+%d+%d' % (w, h, x, y)) self.__root.minsize(int(w), int(h)) self.lift() # select frame self.__test_select_frame = TestSelectFrame(self) self.__test_select_frame.pack(fill=BOTH, anchor=NW, expand=YES, padx=5, pady=5) # comment label comment_label = Label(self, text=COMMENT_LABEL, font=(FONT_NAME, size-2, BOLD)) comment_label.pack(anchor=NE, padx=5, pady=0) # console self.__console = ScrolledText(self, font=(CONSOLE_FONT_NAME, size), height=1) self.__console.configure(state=DISABLED) self.__console.pack(fill=BOTH, anchor=NW, expand=YES, padx=5, pady=5) # Progressbar self.__pg_bar = ttk.Progressbar(self, orient=HORIZONTAL, mode=DETERMINATE) self.__pg_bar.configure(maximum=100, value=0) self.__pg_bar.pack(anchor=SE, padx=5, pady=5) self.__root.title(TOOL_NAME) self.pack(side=TOP, fill=BOTH, expand=YES) self.__main_menu = MainMenu(self.__root) self.__root.configure(menu=self.__main_menu) # Console output color self.__console.tag_configure(INFO, foreground=BLACK, font=(CONSOLE_FONT_NAME, size)) self.__console.tag_configure(WARN, foreground=GOLDENROD, font=(CONSOLE_FONT_NAME, size)) self.__console.tag_configure(ERROR, foreground=RED, font=(CONSOLE_FONT_NAME, size, BOLD)) self.is_running = False self.__root.protocol(WM_DELETE_WINDOW, self.__close) self.__user = TOOL_NAME def __close(self): if not self.is_running: self.pg_bar_stop() self.__root.destroy() def c_println(self, str_val='', mode='normal'): self.__console.configure(state=NORMAL) split_val = str_val.splitlines() for index, value in enumerate(split_val): # When it exceeds the maximum line, # it deletes it from the first line if len(self.__console.get('1.0', END).splitlines()) > 1024 * 4: # Delete First Line self.__console.delete('1.0', '1.end') # Delete Line Feed self.__console.delete('1.0') # Insert New Line if index is 0: if mode == 'normal': self.__console.insert( END, '%s : [%s]' % (datetime.datetime.now(), self.__user), mode) else: self.__console.insert( END, '%s : [%s] [%s] ' % (datetime.datetime.now(), self.__user, mode.upper()), mode) self.__console.insert(END, '%s%s' % (value, os.linesep), mode) self.__console.see(END) self.update() self.__console.configure(state=DISABLED) @property def test_select_frame(self): return self.__test_select_frame @test_select_frame.deleter def test_select_frame(self): del self.__test_select_frame @property def console(self): return self.__console @console.deleter def console(self): del self.__console @property def pg_bar(self): return self.__pg_bar @pg_bar.deleter def pg_bar(self): del self.__pg_bar def pg_bar_start(self): self.__pg_bar.configure(mode=INDETERMINATE) self.__pg_bar.start(20) def pg_bar_stop(self): self.__pg_bar.stop() self.__pg_bar.configure(mode=DETERMINATE) self.__pg_bar[VALUE] = 0 def test_func_run(self): # Check anaconda if ANACONDA_DIR is None: self.c_println(NOT_SELECTED_ANACONDA_MSG, ERROR) return select_test_func_list = self.__test_select_frame.get_select_test_func() select_model_list = self.__test_select_frame.get_select_model() select_data_list = self.__test_select_frame.get_select_data() if len(select_test_func_list) > 0 and len(select_model_list) > 0: # Treeview selectmode is BROWSE test_func = select_test_func_list[0] self.c_println('%s : %s' % (TEST_FUNC_LABEL, test_func.abs_path), mode=INFO) if select_data_list: data_script = select_data_list[0] self.c_println('%s : %s' % (DATA_SCRIPT_LABEL, data_script.abs_path), mode=INFO) else: data_script = None model_script = select_model_list[0] self.c_println('%s : %s' % (MODEL_SCRIPT_LABEL, model_script.abs_path), mode=INFO) # select confing conf_select_wizard = ConfSelectWizard( master=self.master, conf_path=test_func.conf_path) show_wizard(title=SELECT_USE_CONF_LABEL, wizard=conf_select_wizard) if not conf_select_wizard.is_run: self.c_println(CANCEL_MSG, mode=INFO) return test_func.conf_path = conf_select_wizard.conf_path # Save config save_config() if test_func.conf_path: self.c_println('Configuration : %s' % test_func.conf_path, mode=INFO) else: self.c_println('Not used configuration file', mode=INFO) # Create Execute Environment if data_script: env_id = min(set(test_func.env_id) & set(model_script.env_id) & set(data_script.env_id)) else: env_id = min(set(test_func.env_id) & set(model_script.env_id)) env_setup = EnvSetupInfo.get_data(env_id) env_python_dir = self.__create_env(script_path=env_setup.abs_path) if not env_python_dir: self.c_println(CANCEL_MSG, mode=INFO) return self.c_println('Execute Env : %s' % env_python_dir, mode=INFO) # template python file replace keyword # Created file is deleted after execution exec_path = create_test_exec_script( test_func=test_func, data=data_script, model=model_script, print_func=self.c_println) if exec_path: # Run Test Execute Function try: self.__call_test_func( test_func=test_func, env_python_dir=env_python_dir, test_func_script_path=exec_path) finally: os.remove(exec_path) def __create_env(self, script_path): # Format of Setup script(sh or bat) # Search env name after execute setup script # (search 'conda create or python venv') # return env directory # (AnacondaDir/envs/env_name/bin or AnacondaDir/envs/env_name) self.c_println(CREATE_ENV_MSG, mode=INFO) self.pg_bar_start() # Search Env Name try: ret_dir = create_env(script_path, self) except Exception as e: self.c_println(os.linesep + str(e), ERROR) return None finally: self.pg_bar_stop() return ret_dir def __call_test_func(self, test_func, env_python_dir, test_func_script_path): self.c_println('Test Function Start ( %s )' % test_func.abs_path, mode=INFO) self.pg_bar_start() # Execute environment Python and Script cmd = [os.path.join(env_python_dir, 'python'), '-u', test_func_script_path] ret = False try: # Execute Script self.__user = '******' % test_func.id if os.name == LINUX_OS: ret = cmd_exec_run_posix(command=cmd, main_window=self, cwd=test_func.dir_path) else: ret = False except Exception as e: self.c_println(os.linesep + str(e), ERROR) finally: self.__user = TOOL_NAME self.pg_bar_stop() if ret: self.c_println('Test Function Complete', mode=INFO) else: self.c_println('Test Function Failed', mode=INFO) return ret def stop_test_func(self): if stop_cmd(): self.c_println('Stop!!', WARN)
class Application(tkinter.Tk): def __init__(self): """Initialize widgets, methods.""" tkinter.Tk.__init__(self) self.grid() fontoptions = families(self) font = Font(family="Verdana", size=10) menubar = tkinter.Menu(self) fileMenu = tkinter.Menu(menubar, tearoff=0) editMenu = tkinter.Menu(menubar, tearoff=0) fsubmenu = tkinter.Menu(editMenu, tearoff=0) ssubmenu = tkinter.Menu(editMenu, tearoff=0) # adds fonts to the font submenu and associates lambda functions for option in fontoptions: fsubmenu.add_command(label=option, command = lambda: font.configure(family=option)) # adds values to the size submenu and associates lambda functions for value in range(1,31): ssubmenu.add_command(label=str(value), command = lambda: font.configure(size=value)) # adds commands to the menus menubar.add_cascade(label="File",underline=0, menu=fileMenu) menubar.add_cascade(label="Edit",underline=0, menu=editMenu) fileMenu.add_command(label="New", underline=1,command=self.new, accelerator="Ctrl+N") fileMenu.add_command(label="Open", command=self.open, accelerator="Ctrl+O") fileMenu.add_command(label="Save", command=self.save, accelerator="Ctrl+S") fileMenu.add_command(label="Exit", underline=1,command=exit, accelerator="Ctrl+Q") editMenu.add_command(label="Copy", command=self.copy, accelerator="Ctrl+C") editMenu.add_command(label="Cut", command=self.cut, accelerator="Ctrl+X") editMenu.add_command(label="Paste", command=self.paste, accelerator="Ctrl+V") editMenu.add_cascade(label="Font", underline=0, menu=fsubmenu) editMenu.add_cascade(label="Size", underline=0, menu=ssubmenu) editMenu.add_command(label="Color", command=self.color) editMenu.add_command(label="Bold", command=self.bold, accelerator="Ctrl+B") editMenu.add_command(label="Italic", command=self.italic, accelerator="Ctrl+I") editMenu.add_command(label="Underline", command=self.underline, accelerator="Ctrl+U") editMenu.add_command(label="Overstrike", command=self.overstrike, accelerator="Ctrl+T") editMenu.add_command(label="Undo", command=self.undo, accelerator="Ctrl+Z") editMenu.add_command(label="Redo", command=self.redo, accelerator="Ctrl+Y") self.config(menu=menubar) self.bind_all("<Control-n>", self.new) self.bind_all("<Control-o>", self.open) self.bind_all("<Control-s>", self.save) self.bind_all("<Control-q>", self.exit) self.bind_all("<Control-b>", self.bold) self.bind_all("<Control-i>", self.italic) self.bind_all("<Control-u>", self.underline) self.bind_all("<Control-T>", self.overstrike) self.bind_all("<Control-z>", self.undo) self.bind_all("<Control-y>", self.redo) self.text = ScrolledText(self, state='normal', height=80, wrap='word', font = font, pady=2, padx=3, undo=True) self.text.grid(column=0, row=0, sticky='NSEW') # Frame configuration self.grid_columnconfigure(0, weight=1) self.resizable(True, True) def new(self, *args): """Creates a new window.""" app = Application() app.title('Python Text Editor') app.option_add('*tearOff', False) app.mainloop() def color(self): """Changes selected text color.""" try: (rgb, hx) = tkinter.colorchooser.askcolor() self.text.tag_add('color', 'sel.first', 'sel.last') self.text.tag_configure('color', foreground=hx) except TclError: pass def bold(self, *args): """Toggles bold for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "bold" in current_tags: self.text.tag_remove("bold", "sel.first", "sel.last") else: self.text.tag_add("bold", "sel.first", "sel.last") bold_font = Font(self.text, self.text.cget("font")) bold_font.configure(weight="bold") self.text.tag_configure("bold", font=bold_font) except TclError: pass def italic(self, *args): """Toggles italic for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "italic" in current_tags: self.text.tag_remove("italic", "sel.first", "sel.last") else: self.text.tag_add("italic", "sel.first", "sel.last") italic_font = Font(self.text, self.text.cget("font")) italic_font.configure(slant="italic") self.text.tag_configure("italic", font=italic_font) except TclError: pass def underline(self, *args): """Toggles underline for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "underline" in current_tags: self.text.tag_remove("underline", "sel.first", "sel.last") else: self.text.tag_add("underline", "sel.first", "sel.last") underline_font = Font(self.text, self.text.cget("font")) underline_font.configure(underline=1) self.text.tag_configure("underline", font=underline_font) except TclError: pass def overstrike(self, *args): """Toggles overstrike for selected text.""" try: current_tags = self.text.tag_names("sel.first") if "overstrike" in current_tags: self.text.tag_remove("overstrike", "sel.first", "sel.last") else: self.text.tag_add("overstrike", "sel.first", "sel.last") overstrike_font = Font(self.text, self.text.cget("font")) overstrike_font.configure(overstrike=1) self.text.tag_configure("overstrike", font=overstrike_font) except TclError: pass def undo(self, *args): """Undo function""" try: self.text.edit_undo() except TclError: pass def redo(self, *args): """Redo function""" try: self.text.edit_redo() except TclError: pass def copy(self, *args): """Copy text""" self.clipboard_clear() self.clipboard_append(self.text.selection_get()) def cut(self, *args): """Cut text""" self.copy self.text.delete("sel.first", "sel.last") def paste(self, *args): """Paste text""" insertion = self.selection_get(selection = "CLIPBOARD") self.text.insert(0.0, insertion) def open(self, *args): """Opens a file dialog to open a plain text file.""" filename = tkinter.filedialog.askopenfilename() with open(filename) as f: text = f.read() self.text.delete("1.0", "end") self.text.insert('insert', text) def save(self, *args): try: """Opens a file dialog to save the text in plain text format.""" text = self.text.get("1.0", "end") filename = tkinter.filedialog.asksaveasfilename() with open(filename, 'w') as f: f.write(text) except FileNotFoundError: pass def exit(self, *args): """Exits the program.""" self.quit()
online_index = online_indexs[0] if online_index > 0: chat = userlist.get(online_index) if chat == '-------Group chat--------': root.title(user_name) return pri_title = user_name + '->' + chat root.title(pri_title) userlist.bind('<ButtonRelease-1>', private) # 信息显示框 mesbox = ScrolledText(root, font=('微软雅黑', 11)) mesbox.place(x=190, y=5, width=480, height=320) mesbox.tag_configure('blue', foreground='blue') mesbox.tag_configure('green', foreground='green') mesbox.tag_configure('red', foreground='red') mesbox.tag_configure('grey', foreground='grey') mesbox.tag_configure('pink', foreground='pink') mesbox.insert(tkinter.END, '欢迎使用FISH聊天室!\n', 'blue') mesbox.insert(tkinter.END, '----------------------------------------------------------------------------') # 菜单功能 mflag = 0 photo_l = '' file_l = '' offline = '' def see_photo():
class DataPreProcessingWindow(Frame): # Define settings upon initialization. Here you can specify def __init__(self, master=None): Frame.__init__(self, master) #reference to the master widget, which is the tk window self.master = master self.file_list = [] #with that, we want to then run init_window, which doesn't yet exist self.init_window() #Creation of init_window def init_window(self): # changing the title of our master widget self.master.title("GUI") self.function_frame = Frame(self.master) self.function_list_frame = Frame(self.function_frame) self.file_select_frame = Frame(self.master) self.file_list_frame = Frame(self.file_select_frame) self.status_bar_label = Label(self.master, text="") function_label = Label(self.function_frame, text="Functions") function_label.grid(row=0, column=0, sticky=N) self.function_list_frame.grid(row=1, column=0) i = 0 self.selected_function_var = StringVar() for fn, f in function_dict.items(): rb = Radiobutton(self.function_list_frame, indicatoron=0, text=fn, variable=self.selected_function_var, value=fn) rb.pack(anchor="w", fill=BOTH) i = i + 1 self.file_list_text = ScrolledText(self.file_select_frame, width=50) file_select_btn = Button(self.file_select_frame, text="File Select", width=15, command=self.file_select_btn_clicked) apply_btn = Button(self.file_select_frame, width=15, text="Apply", command=self.apply_btn_clicked) clear_btn = Button(self.file_select_frame, width=15, text="Clear", command=self.clear_btn_clicked) postfix_label = Label(self.file_select_frame, text="Postfix") self.postfix_text = Entry(self.file_select_frame) self.file_list_text.grid(row=0, column=0, columnspan=2) file_select_btn.grid(row=1, column=0, columnspan=2, sticky=E + W) apply_btn.grid(row=2, column=0, columnspan=2, sticky=E + W) clear_btn.grid(row=3, column=0, columnspan=2, sticky=E + W) postfix_label.grid(row=4, column=0) self.postfix_text.grid(row=4, column=1) self.result_text = ScrolledText(self.master) self.result_text.tag_configure("bold", font="Helvetica 12 bold") self.result_text.grid(row=1, column=0, columnspan=2) self.function_frame.grid(row=0, column=0, sticky=N) self.file_select_frame.grid(row=0, column=1) self.status_bar_label.grid(row=2, column=0, columnspan=2) def file_select_btn_clicked(self): self.file_list = askopenfilenames() for f in self.file_list: self.file_list_text.insert(END, f.split("/")[-1] + "\n") def apply_btn_clicked(self): func_key = self.selected_function_var.get() func = function_dict[func_key] self.status_bar_label.config(text="Processing...") if func_key == "concat": ret = func(self.file_list) postfix = self.postfix_text.get() save_csv(ret, filename=self.file_list[0], postfix=postfix) elif func_key == "trim_shift_concat": ret = func(self.file_list) postfix = self.postfix_text.get() save_csv(ret, filename=self.file_list[0], postfix=postfix) elif func_key == "make history": for file in self.file_list: df = get_df(file) ret = func(df, [ 'roll', 'pitch', 'yaw', 'vel_x', 'vel_y', 'vel_z', 'acc_x', 'acc_y', 'acc_z', 'act_vx', 'act_vy' ], 3) postfix = self.postfix_text.get() save_csv(ret, filename=file, postfix=postfix) elif func_key == "reshape_for_rnn": for file in self.file_list: df = get_df(file) func(df) else: for file in self.file_list: df = get_df(file) ret = func(df) # if ret: if isinstance(ret, str): header = "{} {}\n".format(func_key, file.split("/")[-1]) ret = ret + "\n\n" self.result_text.insert(END, header, "bold") self.result_text.insert(END, ret) else: postfix = self.postfix_text.get() save_csv(ret, filename=file, postfix=postfix) self.status_bar_label.config(text="Done!") def clear_btn_clicked(self): self.file_list = [] self.file_list_text.delete(1.0, END) self.result_text.delete(1.0, END) self.postfix_text.delete(0, END)
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
class CMetaViz: scrParams = {} sensorsData = [] proc = Process() def Run(self): self.CreateGUI() def CreateRunButton(self): self.root1 = tk.Tk() self.scrParams = GetScreenSize() gW = 1 / 4 * self.scrParams['width'] gH = 1 / 8 * self.scrParams['height'] gX = 3 / 4 * self.scrParams['width'] gY = 0 self.root1.title("Visualize Sensors Data") self.root1.geometry('%dx%d+%d+%d' % (gW, gH, gX, gY)) myFont = font.Font(family='Helvetica', size=20, weight=font.BOLD) self.playImg = tk.PhotoImage(file="resources\\play-button.png") self.replayImg = tk.PhotoImage(file="resources\\replay-button.png") self.btn1 = tk.Button(self.root1, image=self.playImg, command=self.RunBtnCallback, height=85, width=175, compound=tk.CENTER, bg="green", font=myFont) self.btn2 = tk.Button(self.root1, image=self.replayImg, command=self.RerunBtnCallback, height=85, width=175, compound=tk.CENTER, bg="#7f7f00", font=myFont) self.btn2['state'] = 'disabled' self.btn1.place(relx=0.3, rely=0.5, anchor=tk.CENTER) self.btn2.place(relx=0.7, rely=0.5, anchor=tk.CENTER) def RunBtnCallback(self): # LoadCfg() fm = CFileMgr() dm = CDataMgr() pl = CPlot() fm.Run() sensorsRawData = fm.GetSensorsData() dm.SetCarpetFilePath(fm.GetCarpetFilePath()) dm.SetSensorsRawData(sensorsRawData) dm.Run() self.sensorsData = dm.GetSensorsData() # pl.Run(self.sensorsData) if self.proc.name == 'Plot': self.proc.kill() self.proc = Process(name='Plot', target=pl.Run, args=(self.sensorsData, )) self.proc.start() self.btn2['state'] = 'normal' def RerunBtnCallback(self): pl = CPlot() if self.proc.name == 'Plot': self.proc.kill() self.proc = Process(name='Plot', target=pl.Run, args=(self.sensorsData, )) self.proc.start() def CreateCfgEditor(self): self.cfg = toml.load("app_cfg.toml") appCfgFile = open(self.cfg["cfgFilePath"], 'r') appCfgTxt = appCfgFile.read() appCfgFile.close() gW = 0.25 * self.scrParams['width'] gH = 0.875 * self.scrParams['height'] - 105 gX = 0.75 * self.scrParams['width'] gY = 0.125 * self.scrParams['height'] + 32 self.root2 = tk.Tk() self.txt = ScrolledText(self.root2, width=80, height=80, undo=True) # self.txt.insert(tk.END, appCfgTxt) self.root2.bind_all("<Control-s>", self.CfgEditorSave) self.txt.bind('<Key>', self.TxtModifiedCallback) self.txt.bind('<Control-z>', self.UndoCallback) self.txt.tag_configure("Comment", foreground="#B27300") self.txt.tag_configure("RegularText", foreground="#000000") self.txt.tag_configure("Tags", foreground="#0000FF") self.ApplySyntaxHl(appCfgTxt) # self.txt.tag_configure("Token.Comment", foreground="#b21111") self.root2.title("CFG Editor") self.root2.geometry('%dx%d+%d+%d' % (gW, gH, gX, gY)) self.txt.pack() def ApplySyntaxHl(self, appCfgTxt): appCfgTxtLines = appCfgTxt.split('\n') for cfgLine in appCfgTxtLines: if re.search('^\\s*\\#', cfgLine, re.VERBOSE): self.txt.insert("end", cfgLine, 'Comment') elif re.search('^\\s*\\[', cfgLine, re.VERBOSE): self.txt.insert("end", cfgLine, 'Tags') else: self.txt.insert("end", cfgLine, 'RegularText') self.txt.insert("end", '\n', 'RegularText') def TxtModifiedCallback(self, event): # Save combination pressed: if event.keycode != 17: self.root2.title("CFG Editor*") def UndoCallback(self, *args): self.ApplySyntaxHl(self.txt.get("1.0", "end")) def CfgEditorSave(self, *args): txt = self.txt.get("1.0", "end") filename = self.cfg["cfgFilePath"] with open(filename, 'w') as f: f.write(txt) f.close() self.root2.title("CFG Editor") # messagebox.showinfo("Save", "CFG file saved...") def CreateGUI(self): self.CreateRunButton() self.CreateCfgEditor() self.root1.mainloop()
class RoomListDialog(tkinter.Toplevel): """Dialog with list of all rooms from drawing.""" def __init__(self, parent, drawing): """Initialize the dialog.""" tkinter.Toplevel.__init__(self, parent) self.title("Seznam místností") rooms = drawing.rooms rooms_count = len(rooms) self.add_label(0, 0, "Počet místností") self.add_value_widget(0, 1, rooms_count) self.txt = ScrolledText(self, undo=True, tabs="4c 7c 10c 24c") self.txt.grid(row=1, column=0, columnspan=2, sticky="nwse", padx=2, pady=2) self.txt.tag_configure("underlined", underline=True) self.txt.tag_configure("blue", foreground="blue") self.txt.tag_configure("green", foreground="green") self.txt.tag_configure("red", foreground="red") self.txt.insert(tkinter.INSERT, "SAP ID\tgr.ID\tzakreslena\tsouřadnic\n", "underlined") for room in rooms: if "room_id" in room: self.txt.insert(tkinter.END, room["room_id"] + "\t", "blue") else: self.txt.insert(tkinter.END, "x\t", "red") if "canvas_id" in room and room["canvas_id"] is not None: self.txt.insert(tkinter.END, str(room["canvas_id"]) + "\t") else: self.txt.insert(tkinter.END, "x\t", "red") if room["polygon"] is not None and len(room["polygon"]) > 0: self.txt.insert(tkinter.END, "ano\t", "green") else: self.txt.insert(tkinter.END, "ne\t", "red") if room["polygon"] is not None: typ = "?" if "type" in room: typ = room["type"] self.txt.insert(tkinter.END, str(len(room["polygon"])) + " (" + typ + ")\n") else: self.txt.insert(tkinter.END, "?\n") self.txt.configure(state="disabled") okButton = tkinter.Button(self, text="OK", command=self.ok) okButton.grid(row=2, column=0, sticky="WE") # close the dialog on 'x' click self.protocol("WM_DELETE_WINDOW", self.destroy) # get the focus self.grab_set() # how the buttons should behave self.bind("<Return>", lambda event: self.ok()) self.bind("<Escape>", lambda event: self.destroy()) # get the focus okButton.focus_set() def ok(self): """Handle event when Ok button is pressed.""" self.destroy() def add_label(self, row, column, text): """Add a label to dialog.""" label = tkinter.Label(self, text=text) label.grid(row=row, column=column, sticky="W", padx=5, pady=5) def add_value_widget(self, row, column, value): """Add a widget with value to dialog.""" widget = self.value_widget(value) widget.grid(row=row, column=column, sticky="W", padx=5, pady=5) def value_widget(self, value): """Create new widget with value.""" widget = tkinter.Entry(self) widget.insert(tkinter.END, value) widget.configure(state='readonly') return widget
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')
menubar.add_cascade(label="View", menu=viewmenu) colorschemes = { 'White': '000000.FFFFFF', 'Grey': '83406A.D1D4D1', 'Aqua': '5B8340.D1E7E0', } themechoice = StringVar() themechoice.set('White') for k in sorted(colorschemes): themesmenu.add_radiobutton(label=k, variable=themechoice, command=theme) bottombar = Label(textarea, text='Row : 1 | Column : 0') bottombar.pack(expand=NO, fill=None, side=RIGHT, anchor='se') textarea.tag_configure("active_line", background="yellow") textarea.bind("<Any-KeyPress>", lnupdater) textarea.bind("<Button-1>", lnupdatermouse) window.bind('<Control-n>', new_command) window.bind('<Control-o>', open_command) window.bind('<Control-s>', save_command) window.bind('<Control-Shift-KeyPress-S>', saveas_command) window.bind('<Control-q>', exit_command) window.bind('<Control-z>', undo_command) window.bind('<Control-y>', redo_command) window.bind('<Control-x>', cut_command) window.bind('<Control-c>', copy_command) window.bind('<Control-v>', paste_command) window.bind('<Control-f>', find_command) window.bind('<Control-Shift-KeyPress-F>', findnext_command)
class Console(tkinter.Frame): def __init__(self, parent, settings, max_lines=200, **kwargs): super().__init__(parent, **kwargs) self.settings = settings self.max_lines = max_lines self.console = ScrolledText(self, bg=Theme.CONSOLE_BG, highlightbackground=Theme.BG, highlightcolor=Theme.BG, wrap=tkinter.CHAR, width=40, height=10, state='disabled', relief='flat') # Despite setting height above, this widget gets expanded fully, # if the canvas is smaller than the height, will look odd. self.console.pack(fill=tkinter.BOTH, expand=True) self.font = ('Helvetica', 11, 'bold') # Text color self.console.tag_config('TEXT', foreground=Theme.CONSOLE_TEXT, font=('Helvetica', 11), spacing1=5, spacing3=5) self.console.tag_config('TEXT_ALT', foreground=Theme.CONSOLE_TEXT, background=Theme.CONSOLE_BG_ALT, selectbackground='SystemHighlight', font=('Helvetica', 11), spacing1=5, spacing3=5) # Why does setting 'background' causes highlighted text color to be transparent? # https://web.archive.org/web/20201112014139id_/https://effbot.org/tkinterbook/tkinter-widget-styling.htm self.alt_bg = False # Logging colors self.console.tag_config('INFO', foreground=Theme.LOG_INFO) self.console.tag_config('DEBUG', foreground=Theme.LOG_DEBUG) self.console.tag_config('ERROR', foreground=Theme.LOG_ERROR) self.console.tag_config('WARNING', foreground=Theme.LOG_WARNING) self.console.tag_config('CRITICAL', foreground=Theme.LOG_CRITICAL) self.console.focus() if not self.settings['irc']['username']: self.welcome() self.after(100, self.pooling) def pooling(self): while 1: try: message = QUEUE.get(block=False) self.insert(message) except queue.Empty: break self.after(100, self.pooling) def insert(self, text): self.console.configure(state='normal') # Allow writing try: # Tcl can't render some characters if isinstance(text, Message): self.alt_bg = not self.alt_bg user_color = 'lightblue1' if not text.tags.get('color') else text.tags.get('color') username_tag = f'{text.sender}{"alt_bg" if self.alt_bg else ""}' self.console.tag_config(username_tag, font=self.font, foreground=user_color, background=Theme.CONSOLE_BG_ALT if self.alt_bg else Theme.CONSOLE_BG, selectbackground='SystemHighlight', spacing1=5, spacing3=5) self.console.insert(tkinter.END, text.sender, username_tag) self.console.insert(tkinter.END, f': {text.message}\n', 'TEXT_ALT' if self.alt_bg else 'TEXT') else: message = LOGGER.handlers[1].format(text) # This is not a good way to access this self.console.insert(tkinter.END, f'{message}\n', text.levelname) except tkinter.TclError as e: if isinstance(text, Message): # Replace every char outside of Tcl's allowed range with the ? char. text.message = ''.join((ch if ord(ch) <= 0xFFFF else '\uFFFD') for ch in text.message) self.console.insert(tkinter.END, f': {text.message}\n', 'TEXT') else: self.console.insert(tkinter.END, f'{e}\n', 'ERROR') #https://stackoverflow.com/questions/4609382/getting-the-total-number-of-lines-in-a-tkinter-text-widget self.line_count = int(self.console.index('end-2c').split('.')[0]) if self.line_count > self.max_lines: self.console.delete(1.0, 2.0) self.console.configure(state='disabled') # Disallow writing self.console.yview(tkinter.END) def welcome(self): self.font = ('TkDefaultFont', 11, 'bold') self.console.tag_configure('lightblue', foreground='lightblue1', font=self.font, justify='center') self.console.tag_configure('white', foreground='white', font=self.font) self.console.tag_configure('orange', foreground='orange', font=self.font) self.console.tag_configure('pink', foreground='#FFC8D7', font=self.font) self.console.tag_configure('red', foreground='red', font=self.font, spacing1=2, spacing3=2) self.console.tag_config('grey', foreground='grey', font=('TkDefaultFont', 8, 'bold')) self.console.configure(state='normal') self.console.insert(tkinter.END, '~ Welcome to parky\'s twitch bot! ~\n\n', 'lightblue') self.console.insert(tkinter.END, '\n', 'white') self.console.insert(tkinter.END, 'Quick setup:\n', 'orange') self.console.insert(tkinter.END, '\n', 'white') self.console.insert(tkinter.END, '1', 'red') self.console.insert(tkinter.END, '. Click on the "', 'white') self.settings_img = tkinter.PhotoImage(data=Theme.SETTINGS_ICON) self.console.image_create(tkinter.END, image=self.settings_img) self.console.insert(tkinter.END, '" button.\n', 'white') self.console.insert(tkinter.END, '2', 'red') self.console.insert(tkinter.END, '. Fill in IRC fields to gain chat access!\n', 'white') self.console.insert(tkinter.END, '3', 'red') self.console.insert(tkinter.END, '. ', 'white') self.console.insert(tkinter.END, 'Fill in Twitch API to gain access to channel metadata, such as current title, game, uptime, followers... ', 'white') self.console.insert(tkinter.END, '(optional)\n', 'grey') self.console.insert(tkinter.END, '\n', 'TEXT') self.console.configure(state='disabled')
class DisplayImageLabelPlace(): def __init__(self, master, **kwargs): self.word_edited = 0 # false self.master = master frame = tk.Frame(master) frame.configure(bg='#dddddd') frame.grid() self.img_lbl = tk.Label(self.master, width=400, height=6, bg="light gray") self.img_lbl.place(anchor='nw', relwidth=0.35, relheight=0.94) self.page_no_var = tk.IntVar() text_font = tkinter.font.Font(family="Calibri (Body)", size=13, weight="normal") self.page_raw = ScrolledText(self.master, width=50, height=16, wrap=tk.WORD, background='white') self.page_raw.tag_configure('tag-right', justify='right') self.page_raw.configure(font=text_font) # self.page_raw.config (state ='disabled') self.page_raw.place(relx=0.36, rely=0) self.page_edited = ScrolledText(self.master, width=50, height=16, wrap=tk.WORD, background='light gray') self.page_edited.tag_configure('tag-right', justify='right') self.page_edited.configure(font=text_font) self.page_edited.place(relx=0.36, rely=.47) cols = ('#', 'pdf', 'Dic', 'Type') self.listBox = ttk.Treeview(self.master, columns=cols, show='headings', height=25, selectmode="browse") self.listBox.column("#", minwidth=0, width=40, stretch=tk.NO) self.listBox.column("pdf", minwidth=0, width=90, stretch=tk.NO) self.listBox.column("Dic", minwidth=0, width=90, stretch=tk.NO) self.listBox.column("Type", minwidth=0, width=100, stretch=tk.NO) self.listBox.place(relx=0.73, rely=0) for col in cols: self.listBox.heading(col, text=col) verscrlbar = ttk.Scrollbar(self.master, orient="vertical", command=self.listBox.yview) verscrlbar.place(relx=0.97, rely=0, height=530) self.listBox.configure(yscrollcommand=verscrlbar.set) self.listBox.bind("<Double-1>", self.listBox_OnDoubleClick) self.listBox.bind("<ButtonRelease-1>", self.listBox_OnClick) self.listBox.bind("<KeyRelease-Up>", self.listBox_UpArrow) self.listBox.bind("<KeyRelease-Down>", self.listBox_DownArrow) self.edit_word_var = tk.StringVar() self.dict_entry = tk.Entry(self.master, textvariable=self.edit_word_var, width=20, justify='right').place(relx=0.74, rely=0.80) self.word_pdf_type = tk.IntVar() tk.Radiobutton(self.master, text='Specific', variable=self.word_pdf_type, value=0).place(relx=0.85, rely=0.80) tk.Radiobutton(self.master, text='Dict', variable=self.word_pdf_type, value=1).place(relx=0.85, rely=0.84) tk.Button(self.master, text="Save ", fg="red", command=self.save_dict_word).place(relx=0.95, rely=0.80) tk.Button(self.master, text="Save Page", fg="red", command=self.save_dict_page).place(relx=0.95, rely=0.94) tk.Button(self.master, text="GO", command=self.draw_page).place(relx=0.2, rely=0.94) tk.Button(self.master, text="Prev ", command=self.prev_page).place(relx=0.25, rely=0.94) tk.Entry(self.master, textvariable=self.page_no_var, width=4).place(relx=0.3, rely=0.94) tk.Button(self.master, text="Next ", command=self.next_page).place(relx=0.33, rely=0.94) tk.Button(self.master, text="Copy ", command=self.copy_clipboard).place(relx=0.37, rely=0.94) tk.Button(self.master, text="reEdit ", command=self.reedit_page).place(relx=0.41, rely=0.94) tk.Button(self.master, text="Quit ", fg="red", command=quit).place(relx=0.55, rely=0.94) self.page_no_var.set(4) self.draw_page() def draw_page(self): self.word_edited = 0 # False page_no = self.page_no_var.get() page = 'ABH-' + format(page_no, '03') + '.png' # image_path = f'.\\data\\books\\ABH\\pages\\{page}' image_path = os.path.join('.', 'data', 'books', 'ABH', 'pages', page) img_file = Image.open(image_path) img_file.thumbnail((600, 650), Image.ANTIALIAS) self.img_lbl.img = ImageTk.PhotoImage(img_file) self.img_lbl.config(image=self.img_lbl.img) # words= str(((pytesseract.image_to_string(Image.open(image_path), lang='ara')))) page_raw, page_edited = get_db_page(page_no) self.page_raw.config(state='normal') self.page_raw.delete('1.0', 'end') # clear text self.page_raw.insert('end', page_raw, 'tag-right') self.page_raw.config(state='disabled') self.page_edited.config(state='normal') self.page_edited.delete('1.0', 'end') # clear text self.page_edited.insert('end', page_edited, 'tag-right') self.page_edited.config(state='disabled') self.word_pdf_type.set(0) # default Specific for i in self.listBox.get_children(): self.listBox.delete(i) # clear text rows = get_page_dict(page_no) for i, row in enumerate(rows, start=1): self.listBox.insert("", "end", iid=i, values=(i, row[0], row[1], (row[3] if row[3] != None else ''), 0)) self.listBox.selection_set(['1']) # select first line def next_page(self): if self.word_edited: if tk.messagebox.askyesno("Save?", "Save Changes?"): self.save_dict_page() self.page_no_var.set(self.page_no_var.get() + 1) self.draw_page() def prev_page(self): if self.word_edited: if tk.messagebox.askyesno("Save?", "Save Changes?"): self.save_dict_page() self.page_no_var.set(self.page_no_var.get() - 1) self.draw_page() def copy_clipboard(self): pyperclip.copy(self.page_edited.get("1.0", tk.END)) def reedit_page(self): page_no = self.page_no_var.get() page_reedited = rebuild_page_text(page_no) # page_raw, page_reedited = get_db_page(page_no) self.page_edited.config(state='normal') self.page_edited.delete('1.0', 'end') # clear text self.page_edited.insert('end', page_reedited, 'tag-right') self.page_edited.config(state='disabled') def listBox_DictLineChange(self, event): # item = self.self.listBox.item(item,"values") item = self.listBox.focus() # print (event,":", item, self.listBox.selection(), self.listBox.item(item,"values")) items = self.listBox.item(item, "values") self.edit_word_var.set(items[2]) if items[3] in ['', 'Specific', 'None']: self.word_pdf_type.set(0) else: self.word_pdf_type.set(1) def listBox_OnClick(self, event): self.listBox_DictLineChange(event) def listBox_OnDoubleClick(self, event): self.listBox_DictLineChange(event) def listBox_UpArrow(self, event): self.listBox_DictLineChange(event) def listBox_DownArrow(self, event): self.listBox_DictLineChange(event) def save_dict_word(self): # update on the TreeView self.word_edited = 1 word_types = ['Specific', 'Dict'] # item = self.listBox.focus() word_type = word_types[self.word_pdf_type.get()] word_dict = self.edit_word_var.get() selected = self.listBox.focus() temp = self.listBox.item(selected, 'values') self.listBox.item(selected, values=(temp[0], temp[1], word_dict, word_type, 1)) def save_dict_page(self): # save changes in the page's dict to DB page_edited = False for w in self.listBox.get_children(): row = self.listBox.item(w, 'values') if int(row[4]): # row got modified # update_book_word(pdf_word, dict_word, page_no, word_type) update_book_word(row[1], row[2], self.page_no_var.get(), row[3]) page_edited = True self.word_edited = 0 if page_edited: # refresh edited page text page_reedited = rebuild_page_text(self.page_no_var.get()) self.page_edited.config(state='normal') self.page_edited.delete('1.0', 'end') # clear text self.page_edited.insert('end', page_reedited, 'tag-right') self.page_edited.config(state='disabled')
t.pack(expand='y', fill='both', padx=1) textFrame.pack(expand='yes', fill='both') if root._windowingsystem == 'aqua': pass # Create a bunch of tags to use in the text widget, such as those for section # titles and demo descriptions. Also define the bindings for tags. ##.t tag configure title -font titleFont ##.t tag configure subtitle -font titleFont ##.t tag configure bold -font boldFont ##if {[tk windowingsystem] eq "aqua"} { ## .t tag configure title -spacing1 8 ## .t tag configure subtitle -spacing3 3 ##} t.tag_configure('title', font=titleFont) t.tag_configure('subtitle', font=titleFont) t.tag_configure('bold', font=boldFont) if root._windowingsystem == 'aqua': t.tag_configure('title', spacing1=8) t.tag_configure('subtitle', spacing1=3) # We put some "space" characters to the left and right of each demo # description so that the descriptions are highlighted only when the mouse # cursor is right over them (but not when the cursor is to their left or # right). # ##.t tag configure demospace -lmargin1 1c -lmargin2 1c t.tag_configure('demospace', lmargin1='1c', lmargin2='1c') ##if {[winfo depth .] == 1} {