class Liste(Frame): def __init__(self, parent, utilisateurs): Frame.__init__(self, parent) self.parent = parent self.Liste_users = utilisateurs self.Liste = Listbox(self.parent, relief='sunken', bg='lightgrey') self.afficher_liste() self.Liste.pack(expand=1, fill=BOTH) self.pack(side=RIGHT, fill=BOTH, expand=1) def afficher_liste(self): self.Liste.delete(0, END) for user in self.Liste_users: self.Liste.insert('end', user.pseudo) self.Liste.itemconfig('end', foreground=user.couleur) def maj_liste(self, user, commande='ajouter'): if commande == 'ajouter': self.Liste_users.append(Utilisateur(user)) self.Liste_users.sort(key=lambda x: x.pseudo) elif commande == 'enlever': try: for k in self.Liste_users: if user == k.pseudo: self.Liste_users.remove(k) break except KeyError: print("L'utilisateur {} n'est pas dans la liste.".format(user)) self.afficher_liste()
class liste_mots: """Définit un cadre contenant une liste de mot avec un ascenseur""" def __init__(self,parent,titre,compare): police_mots=font.Font(parent, size=12, family='Courier') self.cadre = LabelFrame(parent, borderwidth=2, relief=GROOVE,text=titre) self.ascenseur=Scrollbar(self.cadre,orient=VERTICAL) self.mots=Listbox(self.cadre, font=police_mots, width=LARGEUR_LISTE_MOTS,yscrollcommand = self.ascenseur.set ) self.mots.bind('<<ListboxSelect>>', self.selection) self.mots.grid(column=0,row=0) self.ascenseur.grid(column=1,row=0,sticky=S+N) self.ascenseur.config( command = self.mots.yview ) self.liste_mots=[] self.compare=compare def ajoute_mot_couleur(self,mot,couleur): fin=self.mots.size() self.mots.insert(fin,mot) self.mots.itemconfig(fin,fg=couleur) self.liste_mots.append(mot) def selection(self,e): mot=self.liste_mots[self.mots.curselection()[0]] self.compare.modifie_mot1(mot) self.parent.infos.delete("0.0",END) valeur=self.parent.dict_moyennes[mot] texte="Selon ce modèle, le mot '"+mot+"' a été lu en moyenne "+str(round(valeur,NB_DECIMALES))+ "fois par un élève de ce profil au cours de l'année écoulée." self.parent.infos.insert(END,texte)
class App: WIDTH = 600 HEIGHT = 800 def __init__(self, root, funcs): self.root = root self.root.title("Plotki Migotki") self.root.geometry("%dx%d%+d%+d" % (App.WIDTH, App.HEIGHT, 0, 0)) self.main_frame = Frame(root, width=App.WIDTH, height=App.HEIGHT) self.main_frame.pack_propagate(0) self.main_frame.pack() self.list_map = funcs self.listbox = Listbox(self.main_frame, height=4, width=15, selectbackground="orange") for ix, (entry, _f) in enumerate(self.list_map): plot_type, title = entry self.listbox.insert(ix, title) if plot_type == BARCHART: self.listbox.itemconfig(ix, bg='green') elif plot_type == BOXPLOT: self.listbox.itemconfig(ix, bg='yellow') elif plot_type == SCATTERPLOT: self.listbox.itemconfig(ix, bg='grey') elif plot_type == HISTOGRAM: self.listbox.itemconfig(ix, bg='magenta') self.listbox.bind("<Double-Button-1>", self.call_back) self.listbox.bind("<Return>", self.call_back) self.listbox.pack(expand=1, fill=tk.BOTH) def call_back(self, event): zones = self.listbox.curselection() assert len(zones) == 1 ix = zones[0] ix, cb = self.list_map[ix] cb()
class ChatWindow(MessageSubscriber): def __init__(self, root, username, sender): self.frame = Frame(root) self.username = username self.sender = sender self.put_message_lock = Lock() Grid.columnconfigure(self.frame, 0, weight=2) Grid.columnconfigure(self.frame, 1, weight=0) Grid.rowconfigure(self.frame, 0, weight=2) Grid.rowconfigure(self.frame, 1, weight=0) self.scrollbar = Scrollbar(self.frame) self.messages = Listbox(self.frame, yscrollcommand=self.scrollbar.set, height=15, width=50) self.scrollbar.grid(row=0, column=1, sticky=N + S) self.messages.grid(row=0, column=0, sticky=N + S + W + E) self.scrollbar.config(command=self.messages.yview) self.input_user = StringVar() self.input_field = Entry(self.frame, text=self.input_user) self.input_field.grid(row=1, column=0, sticky=W + E + S) self.send_button = Button(self.frame, text="Send", command=self.send_message) self.send_button.grid(row=1, column=1, sticky=S) self.input_field.bind("<Return>", lambda key: self.send_message()) self.frame.pack(fill=BOTH, expand=YES) self.input_field.focus() def send_message(self): input_val = self.input_field.get() date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') if input_val == "": return if self.sender(input_val, date, self.username): self.input_user.set("") def put_message_in_chat(self, message, date, username, color="red"): with self.put_message_lock: self.messages.insert(END, date + " " + username + ": " + message) self.messages.itemconfig(END, {"fg": color}) self.messages.yview(END) def receive_message(self, text, date, name): self.put_message_in_chat(text, date, name)
def show_items(self, list_of_items: list, target_box: Listbox, check_original: bool): target_box.delete(0, END) index = 0 for item in list_of_items: target_box.insert(END, item) if check_original and not self.files_map.get(item): self.source_files_box.itemconfig(index, {'fg': 'gray50'}) target_box.itemconfig(index, {'fg': 'red'}) elif check_original and self.files_map.get(item): self.source_files_box.itemconfig(index, {'fg': 'black'}) target_box.itemconfig(index, {'fg': 'black'}) index += 1 scroll_position = ('moveto', self.scroll_bar_position[0]) self.source_files_box.yview(*scroll_position) self.result_files_box.yview(*scroll_position)
class liste_mots: """Définit un cadre contenant une liste de mot avec un ascenseur""" def __init__(self, parent, titre): police_mots = font.Font(parent, size=12, family='Courier') self.cadre = LabelFrame(parent, borderwidth=2, relief=GROOVE, text=titre) self.ascenseur = Scrollbar(self.cadre, orient=VERTICAL) self.mots = Listbox(self.cadre, font=police_mots, width=LARGEUR_LISTE_MOTS, yscrollcommand=self.ascenseur.set) self.mots.grid(column=0, row=0) self.ascenseur.grid(column=1, row=0, sticky=S + N) self.ascenseur.config(command=self.mots.yview) def ajoute_mot_couleur(self, mot, couleur): fin = self.mots.size() self.mots.insert(fin, mot) self.mots.itemconfig(fin, fg=couleur)
class HistoryWindow: MAX_QUERY_SIZE = 64 def __init__(self, parent, win, hist_dict): self.window = win self.parent_window = parent self.hist_dict = hist_dict self.window.title("Full history") # self.window.resizable(False, False) frm_top = Frame(win) frm_bottom = Frame(win) self.btn_test = Button(frm_top, text="Test", command=self.on_test) self.btn_test.grid(row=1, column=1, sticky=W + E) self.progress = ttk.Progressbar(frm_top, orient=HORIZONTAL, length=30, mode='indeterminate') self.btn_test_next = Button(frm_top, text="Test Next", command=self.on_test_next) self.btn_test_next.grid(row=1, column=4, sticky=W + E) self.search = StringVar() self.search.trace( "w", lambda name, index, mode, sv=self.search: self.on_search(sv)) self.entry_search = Entry(frm_top, textvariable=self.search, width=52) self.entry_search.grid(row=2, column=1, columnspan=3, sticky=W + E) self.btn_clear = Button(frm_top, text="Clear", command=self.on_clear) self.btn_clear.grid(row=2, column=4, sticky=W + E) self.list_box = Listbox(frm_bottom, width=60, height=40, selectmode=SINGLE) self.list_box.pack(side=LEFT, fill=BOTH, expand=1) scroll = Scrollbar(frm_bottom, command=self.list_box.yview, orient=VERTICAL) scroll.pack(side=RIGHT, fill=Y) self.list_box.config(yscrollcommand=scroll.set) self.list_box.bind('<<ListboxSelect>>', self.on_listbox_select) frm_top.pack() frm_bottom.pack() self.window.bind("<FocusIn>", self.focus_callback) self.window.protocol("WM_DELETE_WINDOW", self.on_close) self.test_online_start = 0 self.fill_list_box() def on_clear(self): self.search.set("") self.on_search(self.search) def on_search(self, search): query = search.get().strip().lower() if len(query) < 2: self.fill_list_box() return self.list_box.delete(0, END) search_results = [] for key in self.hist_dict: pos = key.lower().find(query) if pos == -1: continue search_results.append((key, pos)) search_results.sort(key=lambda x: x[1]) self.list_box.insert(END, *[x[0] for x in search_results]) def fill_list_box(self): self.list_box.delete(0, END) hist = sorted(self.hist_dict.items(), key=lambda x: x[1], reverse=True) self.list_box.insert(END, *[x[0] for x in hist]) def on_listbox_select(self, event): w = event.widget selected = w.curselection() if len(selected) == 0: return index = selected[0] value = w.get(index) self.parent_window.load_model(value, True) def lift(self): self.window.lift() def on_close(self): self.parent_window.hist_window = None self.window.update_idletasks() self.window.destroy() def focus_callback(self, event): self.entry_search.selection_range(0, END) root.lift() def test_online(self, model_list): global root update_models_bps(model_list, 1) root.after_idle(self.update_listbox, model_list) def update_listbox(self, model_list): for model in model_list: self.list_box.itemconfig( model.pos, {'fg': 'red' if model.is_online else 'blue'}) self.set_controls_state(NORMAL) def on_test(self): self.test_online_start = 0 for i in range(self.list_box.size()): self.list_box.itemconfig(i, {'fg': 'black'}) self.on_test_next() def on_test_next(self): items = self.list_box.get( self.test_online_start, self.test_online_start + HistoryWindow.MAX_QUERY_SIZE - 1) model_list = [] for i, name in zip( range(self.test_online_start, self.test_online_start + len(items)), items): model_list.append(Model(i, name)) self.test_online_start += HistoryWindow.MAX_QUERY_SIZE self.set_controls_state(DISABLED) executor.submit(self.test_online, model_list) def set_controls_state(self, state): self.btn_test.config(state=state) self.btn_test_next.config(state=state) self.btn_clear.config(state=state) self.entry_search.config(state=state) if state == DISABLED: self.progress.grid(row=1, column=2, columnspan=2, sticky=W + E) self.progress.start() else: self.progress.grid_forget() self.progress.stop()
class Home(TkPage): Name = 'Home' #name of the class (attributes) Font = lambda Size: ('Courier', Size) #font of the page def __init__(self, Parent, *args, **kwargs): super().__init__(Parent, *args, **kwargs) #constructor of super class self.Songs = [Song.replace('.mid', '') for Song in DirList('Songs') if Song.endswith('.mid')] #mappable songs self.MappedSongs = [Song for Song in DirList('MappedSongs') if Song.endswith('.cmid')] #mapped and compiled song self.Playing = ThreadEvent() #pause state self.Stop = ThreadEvent() #playing state self.Stop.set() TopLabel = Label(self, text = 'Genshin Lyre Player', font= Home.Font(24), bd = 10) #top label with a title for the page TopLabel.place(anchor= 'n', relx= 0.5, rely = 0.015, relwidth = 1, relheight=0.15) #placing the label self.ItemList = ListBox(self) #item list of the song for Index,Item in enumerate(self.MappedSongs): #for loop for every compiled comiled song self.ItemList.insert(Index, Item) #indexing the song in the list self.ItemList.itemconfig(Index, {'bg' : '#C2C2C2'}) #background of itemlist self.ItemList.place(anchor= 'n', relx= 0.5, rely = 0.19, relwidth = 1, relheight = 0.46) #placing the item list #RefreshLogo = Photo(file = 'Res/Refresh.png') #logo of refresh button (not showing at the moment) self.RefreshButton = Button\ ( self, text = 'Refresh', command = lambda : self.Refresh() ) #button to refresh the song list #self.RefreshButton.image = RefreshLogo ######## self.RefreshButton.place(anchor= 'nw', relx = 0.01, rely = 0.7, relwidth = 0.18, relheight = 0.2) #placing the button self.StopButton = Button\ ( self, text = 'Stop', command = lambda : self.StopSong() ) self.StopButton.place(anchor= 'nw', relx= 0.21, rely = 0.7, relwidth = 0.18, relheight = 0.2) #PlayLogo = Photo(file = 'Res/Play.png') #logo of play button (not showing at the moment) self.PlayButton = Button\ ( self, text = 'Play', )#button to play the song selected self.PlayButton.config\ ( command =\ lambda: [ Thread(target = self.PlayTrack, args = (Track,), name = f'{self.ItemList.get("active")}[{i}]', daemon = True).start() for i, Track in enumerate(self.LoadSong()) ]#lambda: self.Play() ) #self.PlayButton.image = PlayLogo ########## self.PlayButton.place(anchor= 'nw', relx= 0.41, rely = 0.7, relwidth = 0.18, relheight = 0.2) #placing the button #PauseLogo = Photo(file = '') #logo of the pause button self.PauseButton = Button\ ( self, text = 'Pause', command = lambda : self.PauseSong() ) #button to pause a song self.PauseButton.place(anchor= 'nw', relx= 0.61, rely = 0.7, relwidth = 0.18, relheight = 0.2) #placing the button self.CompileButton = Button\ ( self, text = 'Compilation\n Screen', command = lambda : self.Compile(), ) self.CompileButton.place(anchor = 'nw', relx= 0.81, rely = 0.7, relwidth = 0.18, relheight = 0.2) #placing the button def Refresh(self): #this function refresh the song list self.MappedSongs = [Song for Song in DirList('MappedSongs') if Song.endswith('.cmid')] #check the folder for the songs self.ItemList.delete('0','end') #delete every item of the list for Index, Item in enumerate(self.MappedSongs): #loop for every song in the folder self.ItemList.insert(Index, Item) #index the song in the item list self.ItemList.itemconfig(Index, {'bg' : '#C2C2C2'}) #background of the itemlist def Countdown(self): #this function create an initial countdown for i in range(3): #3...2...1 print(3-i) self.after(1000) def LoadSong(self): self.PlayButton.state(['disabled']) #disable the play button (might cause some unexpected behaviours) Song = self.ItemList.get('active') #getting the selected song from the list self.Stop.clear() #reset the stop state self.Playing.set() with open('MappedSongs/' + Song, 'rb') as InputFile: #opening the compiled midi file Music = Load(InputFile) #load the searialized object self.Countdown() #initial countdown to give user time to switch to genshin return Music def PlayTrack(self, Part = None): #this (THREADED) function play a single part (track) of the selected song if Part == None: raise ValueError('Part cannot be None') else: print(f'{Identity()} ready') global Notes global DXCodes global NotesFlags Elements = len(Part) #keystrokes to execute Actual = 0 #element counter def PlayNote(Sound, Duration): #this function play a single note of the part NotesFlags[Sound] = False #make the resource unavailable for other threads (to avoid deadlock) PressKey(DXCodes[Notes[Sound]]) #press note-corresponding key Sleep(abs(Duration)) #wait the duration of the note ReleaseKey(DXCodes[Notes[Sound]]) #release note-corresponding key NotesFlags[Sound] = True #make the resource available for other threads def PlayChord(Sounds, Duration): # function play a single chord of the part #print(Duration) for Sound in Sounds: #for loop to make every note of the chord unavailable for other threads (to avoid deadlock) NotesFlags[Sound] = False #lock single resource for Sound in Sounds: #for loop to press chord-corresponding keys PressKey(DXCodes[Notes[Sound]]) #press the note-corresponding key of the chord Sleep(abs(Duration)) #wait the duration of the notes for Sound in Sounds: #for loop to release chord-corresponding keys ReleaseKey(DXCodes[Notes[Sound]]) #release the note-corresponding key of the chord for Sound in Sounds:#for loop to make every note of the chord available for other threads NotesFlags[Sound] = True #unlock single resource while not self.Stop.is_set() and Actual < Elements: if IsPressed('ctrl+space'): if not PauseFunction.locked(): PauseFunction.acquire() self.StopSong() PauseFunction.release() break if IsPressed('shift'): print('resume trigger') Sleep(1) self.Playing.set() while self.Playing.is_set() and Actual < Elements: if IsPressed('ctrl+space'): if not PauseFunction.locked(): PauseFunction.acquire() self.StopSong() PauseFunction.release() break if IsPressed('shift'): print('pause trigger') Sleep(1) self.Playing.clear() break Counter = 0 if Part[Actual]['Type'] == 'Note': #check if the element is a note Duration = float(Part[Actual]['Duration']) PartialDuration = Duration / 10 #duration splitted to check multiple times Note = f'{Part[Actual]["Sound"]}{Part[Actual]["Octave"]}' #extract the note if NotesFlags[Note] and IsMainAlive(): #check if the resource is available PlayNote(Note, Duration) #if the reseourse plays the note at full duration else: #if the resource is not available at the moment while not NotesFlags[Note] or Counter < 10: #check if the note is still playable Sleep(PartialDuration) #waiting the partial duration to check availability Counter += 1 #increasing wastd times if NotesFlags[Note] and Counter < 10: #check if the resource are available and the note is still playable RemainingDuration = Duration - (PartialDuration * Counter) #calculate remaining duration PlayNote(Note, RemainingDuration) #play the note at partial duration elif Part[Actual]['Type'] == 'Chord': # check if the element is a chord (multiple notes together) NotesList = Part[Actual]['Sound'] #extract notes of the chord Octaves = Part[Actual]['Octave'] #extract respective octaves of the notes Chord = [f'{Note}{Octave}' for Note, Octave in zip(NotesList, Octaves)] # combine notes and octaves together Duration = float(Part[Actual]['Duration']) PartialDuration = Duration / 10 #duration splitted to check multiple times if all([NotesFlags[Note] for Note in Chord]) and IsMainAlive(): #check if all the notes in the chord are available (otherwise the cord wouldn't make sense) PlayChord(Chord, Duration) #play the chord at full duration else: while not all([NotesFlags[Note] for Note in Chord]): #check if the chord is stil playable Sleep(PartialDuration) #waiting the partial duration to check availability Counter += 1 #increasing wasted times if all([NotesFlags[Note] for Note in Chord]) and IsMainAlive(): #check if the resources are available and the chors is still playable RemainingDuration = Duration - (PartialDuration * Counter) #calculate remaining duration PlayChord(Chord, RemainingDuration) #play the chord at partial duration elif Part[Actual]['Type'] == 'Rest': #check if the element is a rest Duration = float(Part[Actual]['Duration']) Sleep(abs(Duration)) #wait the rest Actual += 1 #increase the played notes Sleep(5) print(f'{Identity()} ended') def PauseSong(self): #this fucntion pause the song playing Sleep(2) #delay to get rid of function call besides the first if self.Playing.is_set(): #check if the song is playing print(f'{Identity()} is pausing') self.Playing.clear() #clear the playing state if not self.Playing.is_set(): #check if the song is not playing print(f'{Identity()} is resuming') self.Playing.set() #set the song as playing def StopSong(self): #this fucntion stop the song if not StopFunction.locked(): #check if the fucntion has called by multiple thread print('Stop called') Sleep(1) self.Stop.set() #set the stop state self.Playing.clear() #clear the playing state self.PlayButton.state(['!disabled']) #enable the play button self.PlayButton.state(['!pressed']) #reset the play button to the default state ReleaseResources() #release possible hanging resources def Compile(self): #this function switch to compilation screen GenshinLyrePlayer.Raise(CompilationScreen.Name)
class FileChoice(object): def __init__(self, master=None, title=None, prefix=None, list=[], start='', ext="txt", new=False): self.master = master self.value = None self.prefix = prefix self.list = list if prefix and start: self.start = relpath(start, prefix) else: self.start = start self.ext = ext self.new = new self.modalPane = Toplevel(self.master, highlightbackground=BGCOLOR, background=BGCOLOR) if master: logger.debug('winfo: {0}, {1}; {2}, {3}'.format( master.winfo_rootx(), type(master.winfo_rootx()), master.winfo_rooty(), type(master.winfo_rooty()))) self.modalPane.geometry( "+%d+%d" % (master.winfo_rootx() + 50, master.winfo_rooty() + 50)) self.modalPane.transient(self.master) self.modalPane.grab_set() self.modalPane.bind("<Return>", self._choose) self.modalPane.bind("<Escape>", self._cancel) if title: self.modalPane.title(title) if new: nameFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) nameFrame.pack(side="top", padx=18, pady=2, fill="x") nameLabel = Label(nameFrame, text=_("file:"), bd=1, relief="flat", anchor="w", padx=0, pady=0, highlightbackground=BGCOLOR, background=BGCOLOR) nameLabel.pack(side="left") self.fileName = StringVar(self.modalPane) self.fileName.set("untitled.{0}".format(ext)) self.fileName.trace_variable("w", self.onSelect) self.fname = Entry(nameFrame, textvariable=self.fileName, bd=1, highlightbackground=BGCOLOR) self.fname.pack(side="left", fill="x", expand=1, padx=0, pady=0) self.fname.icursor(END) self.fname.bind("<Up>", self.cursorUp) self.fname.bind("<Down>", self.cursorDown) filterFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) filterFrame.pack(side="top", padx=18, pady=4, fill="x") filterLabel = Label(filterFrame, text=_("filter:"), bd=1, relief="flat", anchor="w", padx=0, pady=0, highlightbackground=BGCOLOR, background=BGCOLOR) filterLabel.pack(side="left") self.filterValue = StringVar(self.modalPane) self.filterValue.set("") self.filterValue.trace_variable("w", self.setMatching) self.fltr = Entry(filterFrame, textvariable=self.filterValue, bd=1, highlightbackground=BGCOLOR) self.fltr.pack(side="left", fill="x", expand=1, padx=0, pady=0) self.fltr.icursor(END) prefixFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) prefixFrame.pack(side="top", padx=8, pady=2, fill="x") self.prefixLabel = Label(prefixFrame, text=_("{0}:").format(prefix), bd=1, highlightbackground=BGCOLOR, background=BGCOLOR) self.prefixLabel.pack(side="left", expand=0, padx=0, pady=0) buttonFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) buttonFrame.pack(side="bottom", padx=10, pady=2) chooseButton = Button(buttonFrame, text="Choose", command=self._choose, highlightbackground=BGCOLOR, background=BGCOLOR, pady=2) chooseButton.pack(side="right", padx=10) cancelButton = Button(buttonFrame, text="Cancel", command=self._cancel, highlightbackground=BGCOLOR, background=BGCOLOR, pady=2) cancelButton.pack(side="left") selectionFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) selectionFrame.pack(side="bottom", padx=8, pady=2, fill="x") self.selectionValue = StringVar(self.modalPane) self.selectionValue.set("") self.selection = Label(selectionFrame, textvariable=self.selectionValue, bd=1, highlightbackground=BGCOLOR, background=BGCOLOR) self.selection.pack(side="left", fill="x", expand=1, padx=0, pady=0) listFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR, width=40) listFrame.pack(side="top", fill="both", expand=1, padx=5, pady=2) scrollBar = Scrollbar(listFrame, width=8) scrollBar.pack(side="right", fill="y") self.listBox = Listbox(listFrame, selectmode=BROWSE, width=36) self.listBox.pack(side="left", fill="both", expand=1, ipadx=4, padx=2, pady=0) self.listBox.bind('<<ListboxSelect>>', self.onSelect) self.listBox.bind("<Double-1>", self._choose) self.modalPane.bind("<Return>", self._choose) self.modalPane.bind("<Escape>", self._cancel) # self.modalPane.bind("<Up>", self.cursorUp) # self.modalPane.bind("<Down>", self.cursorDown) self.fltr.bind("<Up>", self.cursorUp) self.fltr.bind("<Down>", self.cursorDown) scrollBar.config(command=self.listBox.yview) self.listBox.config(yscrollcommand=scrollBar.set) self.setMatching() def ignore(self, e=None): return "break" def onSelect(self, *args): # Note here that Tkinter passes an event object to onselect() if self.listBox.curselection(): firstIndex = self.listBox.curselection()[0] value = self.matches[int(firstIndex)] r = value[1] p = os.path.join(self.prefix, r) if self.new: if os.path.isfile(p): p = os.path.split(p)[0] r = os.path.split(r)[0] f = self.fileName.get() r = os.path.join(r, f) p = os.path.join(p, f) self.selectionValue.set(r) self.value = p return "break" def cursorUp(self, event=None): cursel = int(self.listBox.curselection()[0]) newsel = max(0, cursel - 1) self.listBox.select_clear(cursel) self.listBox.select_set(newsel) self.listBox.see(newsel) self.onSelect() return "break" def cursorDown(self, event=None): cursel = int(self.listBox.curselection()[0]) newsel = min(len(self.list) - 1, cursel + 1) self.listBox.select_clear(cursel) self.listBox.select_set(newsel) self.listBox.see(newsel) self.onSelect() return "break" def setMatching(self, *args): # disabled = "#BADEC3" # disabled = "#91CC9E" disabled = "#62B374" match = self.filterValue.get() if match: self.matches = matches = [ x for x in self.list if x and match.lower() in x[1].lower() ] else: self.matches = matches = self.list self.listBox.delete(0, END) index = 0 init_index = 0 for item in matches: if type(item) is tuple: # only show the label # (label, value, disabled)FF self.listBox.insert(END, item[0]) if self.new: if not item[-1]: self.listBox.itemconfig(index, fg=disabled) else: self.listBox.itemconfig(index, fg="blue") if self.start and item[1] == self.start: init_index = index else: if item[-1]: self.listBox.itemconfig(index, fg=disabled) else: self.listBox.itemconfig(index, fg="blue") if self.start and item[1] == self.start: init_index = index # elif files: else: self.listBox.insert(END, item) index += 1 self.listBox.select_set(init_index) self.listBox.see(init_index) self.fltr.focus_set() self.onSelect() def _choose(self, event=None): try: if self.listBox.curselection(): firstIndex = self.listBox.curselection()[0] if self.new: if not self.value or os.path.isfile(self.value): return else: tup = self.matches[int(firstIndex)] if tup[-1]: return self.value = os.path.join(self.prefix, tup[1]) else: return except IndexError: self.value = None self.modalPane.destroy() def _cancel(self, event=None): self.value = None self.modalPane.destroy() def returnValue(self): self.master.wait_window(self.modalPane) return self.value
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent, background="#8080FF") self.parent = parent self.initUI() def initUI(self): self.parent.title("EQ GuildViewer 0.1") fontb = Font(size=12, weight="bold") # inicializo variables self.ant = None self.lastLine = 0 self.name = "" # frame padre area = Frame(self) area.pack(side=BOTTOM, fill=BOTH, expand=1) areab = Frame(self) areab.pack(side=TOP, fill=BOTH, expand=1) # scroll players self.scrollbar2 = Scrollbar(areab, orient=VERTICAL) # construimos un menu con todos los nombres del diccionario y un boton self.refreshButton = Button(areab, text="""PARSEA!""", command=self.onRefresh, bd=2, relief="groove") self.listboxLogs = Listbox( areab, width=50, activestyle="none", highlightthickness=0, yscrollcommand=self.scrollbar2.set, relief=RIDGE ) self.listboxLogs.pack(side=LEFT, fill=Y) self.scrollbar2.pack(side=LEFT, fill=Y) self.refreshButton.pack(side=LEFT, fill=BOTH, expand=1) for player in optionsDictionary: self.listboxLogs.insert(END, player) # scroll self.scrollbar = Scrollbar(area, orient=VERTICAL) self.scrollbar.pack(side=RIGHT, fill=Y) # area1 area1 = Frame(area) area1.pack(side=LEFT, fill=Y) lbl = Label(area1, text="Name") self.listbox = Listbox( area1, yscrollcommand=self.scrollbar.set, font=fontb, relief=FLAT, highlightthickness=0, activestyle="none" ) lbl.pack(side=TOP) self.listbox.pack(side=BOTTOM, fill=Y, expand=1) # area2 area2 = Frame(area) area2.pack(side=LEFT, fill=Y) lbl2 = Label(area2, text="Level") self.listbox2 = Listbox( area2, yscrollcommand=self.scrollbar.set, font=fontb, relief=FLAT, highlightthickness=0, activestyle="none" ) lbl2.pack(side=TOP) self.listbox2.pack(side=BOTTOM, fill=Y, expand=1) # area3 area3 = Frame(area) area3.pack(side=LEFT, fill=Y) lbl3 = Label(area3, text="Class") self.listbox3 = Listbox( area3, yscrollcommand=self.scrollbar.set, font=fontb, relief=FLAT, highlightthickness=0, activestyle="none" ) lbl3.pack(side=TOP) self.listbox3.pack(side=BOTTOM, fill=Y, expand=1) # area4 area4 = Frame(area) area4.pack(side=LEFT, fill=Y) lbl4 = Label(area4, text="Race") self.listbox4 = Listbox( area4, yscrollcommand=self.scrollbar.set, font=fontb, relief=FLAT, highlightthickness=0, activestyle="none" ) lbl4.pack(side=TOP) self.listbox4.pack(side=BOTTOM, fill=Y, expand=1) # area3 area5 = Frame(area) area5.pack(side=LEFT, fill=Y) lbl5 = Label(area5, text="Zone") self.listbox5 = Listbox( area5, yscrollcommand=self.scrollbar.set, font=fontb, relief=FLAT, highlightthickness=0, activestyle="none" ) lbl5.pack(side=TOP) self.listbox5.pack(side=BOTTOM, fill=Y, expand=1) self.pack(fill=BOTH, expand=1) # config-scrollbar self.scrollbar.config(command=self.yview) self.scrollbar2["command"] = self.listboxLogs.yview # bindeos de acciones self.listbox.bind("<<ListboxSelect>>", self.onSelect) self.listbox.bind("<MouseWheel>", self.onTest) self.listbox2.bind("<<ListboxSelect>>", self.onSelect) self.listbox2.bind("<MouseWheel>", self.onTest) self.listbox3.bind("<<ListboxSelect>>", self.onSelect) self.listbox3.bind("<MouseWheel>", self.onTest) self.listbox4.bind("<<ListboxSelect>>", self.onSelect) self.listbox4.bind("<MouseWheel>", self.onTest) self.listbox5.bind("<<ListboxSelect>>", self.onSelect) self.listbox5.bind("<MouseWheel>", self.onTest) self.listboxLogs.bind("<<ListboxSelect>>", self.onSelectPlayer) # mostrar la barra de scroll def yview(self, *args): self.listbox.yview(*args) self.listbox2.yview(*args) self.listbox3.yview(*args) self.listbox4.yview(*args) self.listbox5.yview(*args) # accion de la rueda del raton def onTest(self, val): return "break" # seleccionar un elementos de una listbox def onSelect(self, val): try: if self.ant != None: self.listbox.itemconfig(self.ant, background="#FFFFFF") self.listbox2.itemconfig(self.ant, background="#FFFFFF") self.listbox3.itemconfig(self.ant, background="#FFFFFF") self.listbox4.itemconfig(self.ant, background="#FFFFFF") self.listbox5.itemconfig(self.ant, background="#FFFFFF") self.listbox.itemconfig(val.widget.curselection(), background="#C0C0C0") self.listbox2.itemconfig(val.widget.curselection(), background="#C0C0C0") self.listbox3.itemconfig(val.widget.curselection(), background="#C0C0C0") self.listbox4.itemconfig(val.widget.curselection(), background="#C0C0C0") self.listbox5.itemconfig(val.widget.curselection(), background="#C0C0C0") self.ant = val.widget.curselection() except: None # print('No hay valores') # dependiendo de que nombre se elija en el menu cargamos en lastLine la linea de ese nombre del diccionario def onSelectPlayer(self, val): try: self.name = val.widget.get(val.widget.curselection()) self.lastLine = optionsDictionary[self.name] # print(self.name, ' ', self.lastLine) except: None # print('No hay valores') # recorremos el fichero log al clickar sobre el boton 'Refresh!' def onRefresh(self): if self.name != "": yes = False count = 0 dictionary = {} dictionaryAuxiliar = {} stringLog = "../eqlog_" + str(self.name) + "_project1999.txt" with open(stringLog, "r") as log: for i in range(int(self.lastLine)): next(log) count = count + 1 for line in log: match = re.match("\[.*\] \[(.*) (.*)\] (.*) \((.*)\) <.*> ZONE: (.*)", line) matchRole = re.match("\[.*\] \[(.*)\] (.*) <.*>", line) matchToken = re.match("\[.*\] You say, 't0000'", line) matchTokenI = re.match("\[.*\] You say, 't0001'", line) if matchTokenI != None: yes = True elif match != None and yes: dictionaryAuxiliar[match.group(3)] = ( match.group(1), match.group(2), match.group(4), match.group(5), ) elif matchRole != None and yes: dictionaryAuxiliar[matchRole.group(2)] = [(matchRole.group(1))] elif matchToken != None and yes: dictionary = dictionaryAuxiliar.copy() dictionaryAuxiliar.clear() yes = False count = count + 1 # bucle para sacar datos, primero eliminamos todo lo que haya self.listbox.delete(0, self.listbox.size()) self.listbox2.delete(0, self.listbox2.size()) self.listbox3.delete(0, self.listbox3.size()) self.listbox4.delete(0, self.listbox4.size()) self.listbox5.delete(0, self.listbox5.size()) for member in dictionary: self.listbox.insert(END, member) self.listbox2.insert(END, dictionary[member][0]) try: self.listbox3.insert(END, dictionary[member][1]) self.listbox4.insert(END, dictionary[member][2]) self.listbox5.insert(END, dictionary[member][3]) except IndexError as error: self.listbox3.insert(END, "-") self.listbox5.insert(END, "-") self.listbox4.insert(END, "-") # print(dictionary) # print('Longitud', len(dictionary)) # guardamos la linea ultima leida en el diccionario # self.lastLine = count # optionsDictionary[self.name] = count # print('Despues:', optionsDictionary) # guardamos el diccionario en el archivo options options = open("options.txt", "w") for player in optionsDictionary: options.write(str(player) + ":" + str(optionsDictionary[player])) options.close()
class OSCRemote(object): def __init__(self): self.editor_issue = "1.3" # get command options self.command_options = remote_options() # get directory holding the code self.pp_dir = sys.path[0] if not os.path.exists(self.pp_dir + os.sep + "pp_oscremote.py"): tkinter.messagebox.showwarning("Pi Presents", "Bad Application Directory") exit() # Initialise logging Monitor.log_path = self.pp_dir self.mon = Monitor() self.mon.init() Monitor.classes = ['OSCRemote', 'OSCConfig', 'OSCEditor'] Monitor.log_level = int(self.command_options['debug']) self.mon.log(self, "Pi Presents Remote is starting") self.mon.log(self, " OS and separator " + os.name + ' ' + os.sep) self.mon.log(self, "sys.path[0] - location of code: code " + sys.path[0]) self.root = Tk() # OSC config class self.osc_config = OSCConfig() self.osc_config_file = self.pp_dir + os.sep + 'pp_config' + os.sep + 'pp_oscremote.cfg' self.read_create_osc() self.setup_gui() if self.osc_config.this_unit_ip == '': self.mon.err(self, 'IP of own unit must be provided in oscremote.cfg') self.init() #and start the system self.root.after(1000, self.run_app) self.root.mainloop() def init(self): #self.osc_config_file = self.pp_dir + os.sep + 'pp_config' + os.sep + 'pp_oscremote.cfg' #self.read_create_osc() self.pp_home_dir = self.command_options['home'] + '/pp_home' self.mon.log(self, "Data Home from options is " + self.pp_home_dir) self.pp_profile_dir = '' self.current_showlist = None self.current_show = None self.current_show_ref = '' self.shows_display.delete(0, END) self.results.set('') self.desc.set('Listening to replies from Slave on: ' + self.osc_config.this_unit_ip + ':' + self.osc_config.reply_listen_port) def add_status(self, text): self.status_display.insert(END, text + '\n') self.status_display.see(END) def run_app(self): self.output_client = None self.output_reply_server = None self.output_reply_thread = None if self.osc_config.master_enabled != 'yes': self.mon.err(self, 'OSC Master is not enabled in oscremote.cfg') return if self.osc_config.reply_listen_port == '': self.mon.err(self, 'Reply Listen port is not set in oscremote.cfg') return self.prefix = '/pipresents' self.this_unit = '/' + self.osc_config.this_unit_name self.add_status("This unit's OSC address is: " + self.this_unit) self.slave_unit = '/' + self.osc_config.slave_units_name self.add_status('Slave unit OSC address is: ' + self.slave_unit) #connect client sending commands to slave unit then start server to listen for replies self.output_client = self.init_client() self.add_status('Listening for replies from slave on: ' + self.osc_config.this_unit_ip + ':' + self.osc_config.reply_listen_port) self.output_reply_server = self.init_server( self.osc_config.this_unit_ip, self.osc_config.reply_listen_port, self.output_client) self.add_output_reply_handlers() self.output_reply_thread = self.start_server(self.output_reply_server) # *************************************** # RESPOND TO BUTTONS # *************************************** def open_show(self): self.msg_path = '/core/open ' self.msg_arg_text = self.current_show_ref self.display_msg_text() def close_show(self): self.msg_path = '/core/close ' self.msg_arg_text = self.current_show_ref self.display_msg_text() def exit_pipresents(self): self.msg_path = '/core/exitpipresents' self.msg_arg_text = '' self.display_msg_text() def play_event(self): self.msg_path = '/core/event' self.msg_arg_text = 'pp-play' self.display_msg_text() def pause_event(self): self.msg_path = '/core/event' self.msg_arg_text = 'pp-pause' self.display_msg_text() pass def stop_event(self): self.msg_path = '/core/event' self.msg_arg_text = 'pp-stop' self.display_msg_text() pass def up_event(self): self.msg_path = '/core/event' self.msg_arg_text = 'pp-up' self.display_msg_text() def down_event(self): self.msg_path = '/core/event' self.msg_arg_text = 'pp-down' self.display_msg_text() def animate(self): self.msg_path = '/core/animate' self.msg_arg_text = '' self.display_msg_text() def display_control(self): self.msg_path = '/core/monitor' self.msg_arg_text = '' self.display_msg_text() def loopback(self): self.msg_path = '/system/loopback' self.msg_arg_text = '' self.display_msg_text() def server_info(self): self.msg_path = '/system/server-info' self.msg_arg_text = '' self.display_msg_text() # and put the created text in the results box in the gui def display_msg_text(self): self.results.set(self.prefix + self.slave_unit + self.msg_path + ' ' + self.msg_arg_text) #respond to the Send button # parses the message string into fields and sends - NO error checking def send_message(self): if self.slave_unit == '/': self.mon.err(self, 'slave unit OSC name not set') return if self.osc_config.slave_units_ip == '': self.mon.err(self, 'slave unit IP not set') return msg_text = self.results.get() if msg_text == '': return fields = msg_text.split() osc_address = fields[0] arg_list = fields[1:] dest = (self.osc_config.slave_units_ip, int(self.osc_config.reply_listen_port)) self.add_status('Send message:' + msg_text + ' to ' + str(dest)) self.mon.log(self, 'send message: ' + msg_text) self.sendto(self.output_client, dest, osc_address, arg_list) # *************************************** # OSC CLIENT TO SEND MESSAGES # *************************************** def init_client(self): return OSC.OSCClient() def sendto(self, client, dest, address, arg_list): #print (' message to send',address,arg_list) msg = OSC.OSCMessage() msg.setAddress(address) for arg in arg_list: msg.append(arg) try: client.sendto(msg, dest) except Exception as e: self.mon.err(self, 'error in client when sending OSC command: ' + str(e)) def disconnect_client(self, client): if client != None: client.close() return # *************************************** # OSC SERVER TO LISTEN TO REPLIES # *************************************** def init_server(self, ip, port_text, client): self.mon.log(self, 'Start Server: ' + ip + ':' + port_text) return OSC.OSCServer((ip, int(port_text)), client) def start_server(self, server): st = threading.Thread(target=server.serve_forever) st.start() return st def close_server(self, server, st): if server != None: server.close() self.mon.log(self, 'Waiting for Server-thread to finish') if st != None: st.join() ##!!! self.mon.log(self, 'server thread closed') def add_output_reply_handlers(self): self.output_reply_server.addMsgHandler('default', self.no_match_handler) self.output_reply_server.addMsgHandler( self.prefix + "/system/loopback-reply", self.loopback_reply_handler) self.output_reply_server.addMsgHandler( self.prefix + "/system/server-info-reply", self.server_info_reply_handler) def no_match_handler(self, addr, tags, stuff, source): text = "No handler for message from %s" % OSC.getUrlStr(source) + '\n' text += " %s" % addr + self.pretty_list(stuff, '') self.add_status(text + '\n') def loopback_reply_handler(self, addr, tags, stuff, source): self.add_status('Loopback reply received from: ' + OSC.getUrlStr(source)) def server_info_reply_handler(self, addr, tags, stuff, source): unit = stuff[0] commands = stuff[1:] self.add_status('Server Information from: ' + OSC.getUrlStr(source)) self.add_status('OSC name: ' + unit) self.add_status('Commands:\n' + self.pretty_list(commands, '\n')) def pretty_list(self, fields, separator): text = ' ' for field in fields: text += str(field) + separator return text # *************************************** # INIT EXIT MISC # *************************************** def e_edit_osc(self): self.disconnect_client(self.output_client) self.output_client = None self.close_server(self.output_reply_server, self.output_reply_thread) self.output_reply_server = None self.output_reply_thread = None self.edit_osc() self.read_create_osc() self.init() self.add_status('\n\n\nRESTART') self.run_app() def app_exit(self): self.disconnect_client(self.output_client) self.close_server(self.output_reply_server, self.output_reply_thread) if self.root is not None: self.root.destroy() self.mon.finish() sys.exit() def show_help(self): tkinter.messagebox.showinfo("Help", "Read 'manual.pdf'") def about(self): tkinter.messagebox.showinfo( "About", "Simple Remote Control for Pi Presents\n" + "Author: Ken Thompson" + "\nWebsite: http://pipresents.wordpress.com/") def setup_gui(self): # set up the gui # root is the Tkinter root widget self.root.title("OSC Remote Control for Pi Presents") # self.root.configure(background='grey') self.root.resizable(False, False) # define response to main window closing self.root.protocol("WM_DELETE_WINDOW", self.app_exit) # bind some display fields self.desc = StringVar() self.filename = StringVar() self.display_show = StringVar() self.results = StringVar() self.status = StringVar() # define menu menubar = Menu(self.root) profilemenu = Menu(menubar, tearoff=0, bg="grey", fg="black") profilemenu.add_command(label='Select', command=self.open_existing_profile) menubar.add_cascade(label='Profile', menu=profilemenu) osc_configmenu = Menu(menubar, tearoff=0, bg="grey", fg="black") menubar.add_cascade(label='Options', menu=osc_configmenu) osc_configmenu.add_command(label='Edit', command=self.e_edit_osc) helpmenu = Menu(menubar, tearoff=0, bg="grey", fg="black") menubar.add_cascade(label='Help', menu=helpmenu) helpmenu.add_command(label='Help', command=self.show_help) helpmenu.add_command(label='About', command=self.about) self.root.config(menu=menubar) #top frame top_frame = Frame(self.root, padx=5, pady=5) top_frame.pack(side=TOP) # output info frame info_frame = Frame(top_frame, padx=5, pady=5) info_frame.pack(side=TOP, fill=BOTH, expand=1) info_name = Label(info_frame, text="Master's Name: " + self.osc_config.this_unit_name, font="arial 12 bold") info_name.pack(side=TOP) info_reply_address = Label(info_frame, textvariable=self.desc, font="arial 12 bold") info_reply_address.pack(side=TOP) results_label = Label(top_frame, text="Message to Send", font="arial 12 bold") results_label.pack(side=LEFT) results_display = Entry(top_frame, textvariable=self.results, width=70) results_display.pack(side=LEFT, fill=BOTH, expand=1) send_button = Button(top_frame, width=5, height=1, text='Send', fg='black', command=self.send_message, bg="light grey") send_button.pack(side=RIGHT) #bottom frame bottom_frame = Frame(self.root, padx=5, pady=5) bottom_frame.pack(side=TOP, fill=BOTH, expand=1) left_frame = Frame(bottom_frame, padx=5) left_frame.pack(side=LEFT) right_frame = Frame(bottom_frame, padx=5, pady=5) right_frame.pack(side=LEFT) suplabel_frame = Frame(right_frame, pady=5) suplabel_frame.pack(side=TOP) commands_label = Label(suplabel_frame, text="Show Control", font="arial 12 bold") commands_label.pack() supervisor_frame = Frame(right_frame, pady=5) supervisor_frame.pack(side=TOP) # supervisor buttons add_button = Button(supervisor_frame, width=5, height=1, text='Open\nShow', fg='black', command=self.open_show, bg="light grey") add_button.pack(side=LEFT) add_button = Button(supervisor_frame, width=5, height=1, text='Close\nShow', fg='black', command=self.close_show, bg="light grey") add_button.pack(side=LEFT) add_button = Button(supervisor_frame, width=10, height=1, text='Exit\nPi Presents', fg='black', command=self.exit_pipresents, bg="light grey") add_button.pack(side=LEFT) # events buttons oplabel_frame = Frame(right_frame, pady=5) oplabel_frame.pack(side=TOP) operations_label = Label(oplabel_frame, text="Input Events", font="arial 12 bold") operations_label.pack() operations_frame = Frame(right_frame, pady=5) operations_frame.pack(side=TOP) add_button = Button(operations_frame, width=5, height=1, text='Play', fg='black', command=self.play_event, bg="light grey") add_button.pack(side=LEFT) add_button = Button(operations_frame, width=5, height=1, text='Pause', fg='black', command=self.pause_event, bg="light grey") add_button.pack(side=LEFT) add_button = Button(operations_frame, width=5, height=1, text='Stop', fg='black', command=self.stop_event, bg="light grey") add_button.pack(side=LEFT) add_button = Button(operations_frame, width=5, height=1, text='Up', fg='black', command=self.up_event, bg="light grey") add_button.pack(side=LEFT) add_button = Button(operations_frame, width=5, height=1, text='Down', fg='black', command=self.down_event, bg="light grey") add_button.pack(side=LEFT) # animate buttons others_label_frame = Frame(right_frame, pady=5) others_label_frame.pack(side=TOP) others_label = Label(others_label_frame, text="Others", font="arial 12 bold") others_label.pack() others_frame = Frame(right_frame, pady=5) others_frame.pack(side=TOP) add_button = Button(others_frame, width=5, height=1, text='Animate', fg='black', command=self.animate, bg="light grey") add_button.pack(side=LEFT) add_button = Button(others_frame, width=8, height=1, text='Monitor on/off', fg='black', command=self.display_control, bg="light grey") add_button.pack(side=LEFT) # system buttons systemlabel_frame = Frame(right_frame, pady=5) systemlabel_frame.pack(side=TOP) system_label = Label(systemlabel_frame, text="System", font="arial 12 bold") system_label.pack() system_frame = Frame(right_frame, pady=5) system_frame.pack(side=TOP) add_button = Button(system_frame, width=5, height=1, text='Loopback', fg='black', command=self.loopback, bg="light grey") add_button.pack(side=LEFT) add_button = Button(system_frame, width=10, height=1, text='Server Info', fg='black', command=self.server_info, bg="light grey") add_button.pack(side=LEFT) # define display of showlist shows_title_frame = Frame(left_frame) shows_title_frame.pack(side=TOP) shows_label = Label(shows_title_frame, text="Shows") shows_label.pack() shows_frame = Frame(left_frame) shows_frame.pack(side=TOP) scrollbar = Scrollbar(shows_frame, orient=VERTICAL) self.shows_display = Listbox(shows_frame, selectmode=SINGLE, height=12, width=40, bg="white", activestyle=NONE, fg="black", yscrollcommand=scrollbar.set) scrollbar.config(command=self.shows_display.yview) scrollbar.pack(side=RIGHT, fill=Y) self.shows_display.pack(side=LEFT, fill=BOTH, expand=1) self.shows_display.bind("<ButtonRelease-1>", self.e_select_show) # status_frame status_frame = Frame(self.root, padx=5, pady=5) status_frame.pack(side=TOP, fill=BOTH, expand=1) status_label = Label(status_frame, text="Status", font="arial 12 bold") status_label.pack(side=LEFT) scrollbar = Scrollbar(status_frame, orient=VERTICAL) self.status_display = Text(status_frame, height=10, yscrollcommand=scrollbar.set) scrollbar.config(command=self.status_display.yview) scrollbar.pack(side=RIGHT, fill=Y) self.status_display.pack(side=LEFT, fill=BOTH, expand=1) # *************************************** # SHOWLIST # *************************************** def open_existing_profile(self): initial_dir = self.pp_home_dir + os.sep + "pp_profiles" if os.path.exists(initial_dir) is False: self.mon.err( self, "Profiles directory not found: " + initial_dir + "\n\nHint: Data Home option must end in pp_home") return dir_path = tkinter.filedialog.askdirectory(initialdir=initial_dir) # dir_path="C:\Users\Ken\pp_home\pp_profiles\\ttt" if len(dir_path) > 0: self.open_profile(dir_path) def open_profile(self, dir_path): showlist_file = dir_path + os.sep + "pp_showlist.json" if os.path.exists(showlist_file) is False: self.mon.err( self, "Not a Profile: " + dir_path + "\n\nHint: Have you opened the profile directory?") return self.pp_profile_dir = dir_path self.root.title("Remote for Pi Presents - " + self.pp_profile_dir) self.open_showlist(self.pp_profile_dir) def open_showlist(self, profile_dir): showlist_file = profile_dir + os.sep + "pp_showlist.json" if os.path.exists(showlist_file) is False: self.mon.err( self, "showlist file not found at " + profile_dir + "\n\nHint: Have you opened the profile directory?") self.app_exit() self.current_showlist = ShowList() self.current_showlist.open_json(showlist_file) # if float(self.current_showlist.sissue()) != float(self.editor_issue): # self.mon.err(self,"Version of profile does not match Remote: "+self.editor_issue) # self.app_exit() self.refresh_shows_display() def refresh_shows_display(self): self.shows_display.delete(0, self.shows_display.size()) for index in range(self.current_showlist.length()): self.shows_display.insert( END, self.current_showlist.show(index)['title'] + " [" + self.current_showlist.show(index)['show-ref'] + "]") if self.current_showlist.show_is_selected(): self.shows_display.itemconfig( self.current_showlist.selected_show_index(), fg='red') self.shows_display.see(self.current_showlist.selected_show_index()) def e_select_show(self, event): # print 'select show', self.current_showlist.length() if self.current_showlist is not None and self.current_showlist.length( ) > 0: mouse_item_index = int(event.widget.curselection()[0]) self.current_showlist.select(mouse_item_index) self.current_show_ref = self.current_showlist.selected_show( )['show-ref'] self.refresh_shows_display() else: self.current_show_ref = '' # *************************************** # OSC CONFIGURATION # *************************************** def read_create_osc(self): if self.osc_config.read(self.osc_config_file) is False: self.osc_config.create(self.osc_config_file, 'master') eosc = OSCEditor(self.root, self.osc_config_file, 'remote', 'Create OSC Remote Configuration') self.osc_config.read(self.osc_config_file) def edit_osc(self): if self.osc_config.read(self.osc_config_file) is False: self.osc_config.create(self.osc_config_file) eosc = OSCEditor(self.root, self.osc_config_file, 'remote', 'Edit OSC Reomote Configuration')
class InputDevice(object): def __init__(self): # root is the Tkinter root widget self.root = Tk() self.root.title("Input Device Utility") # self.root.configure(background='grey') self.root.resizable(False, False) # define response to main window closing self.root.protocol("WM_DELETE_WINDOW", self.app_exit) self.my_device = '' self.my_device_display = StringVar() self.device_list = [] self.matches = 0 # overall display root_frame = Frame(self.root) root_frame.pack(side=LEFT) devices_frame = Frame(root_frame, padx=5, pady=10) devices_frame.pack(side=LEFT) devices_label = Label(devices_frame, text="Devices in dev/input") devices_label.pack(side=TOP) devices_list_frame = Frame(devices_frame, padx=5, pady=10) devices_list_frame.pack(side=TOP) selected_device_title = Label(devices_frame, text='Selected device') selected_device_title.pack(side=TOP) self.selected_device_var = StringVar() selected_device = Label(devices_frame, textvariable=self.selected_device_var, fg="red") selected_device.pack(side=TOP) events_frame = Frame(root_frame, padx=5, pady=10) events_frame.pack(side=LEFT) events_title = Label(events_frame, text='Received Events') events_title.pack(side=TOP) events_list_frame = Frame(events_frame, padx=5, pady=10) events_list_frame.pack(side=TOP) # list of devices scrollbar = Scrollbar(devices_list_frame, orient=VERTICAL) self.devices_display = Listbox(devices_list_frame, selectmode=SINGLE, height=20, width=60, bg="white", activestyle=NONE, fg="black", yscrollcommand=scrollbar.set) scrollbar.config(command=self.devices_display.yview) scrollbar.pack(side=RIGHT, fill=Y) self.devices_display.pack(side=LEFT, fill=BOTH, expand=1) self.devices_display.bind("<ButtonRelease-1>", self.e_select_device) # events display scrollbar = Scrollbar(events_list_frame, orient=VERTICAL) self.events_display = Text(events_list_frame, width=40, height=20, wrap='word', font="arial 11", padx=5, yscrollcommand=scrollbar.set) scrollbar.config(command=self.events_display.yview) scrollbar.pack(side=RIGHT, fill=Y) self.events_display.pack(side=LEFT, fill=BOTH, expand=1) self.events_display.config(state=NORMAL) self.events_display.delete(1.0, END) self.events_display.config(state=DISABLED) self.selected_device_index = -1 self.matches = 0 self.get_all_devices() self.refresh_devices_display() self.root.after(10, self.event_loop) # and enter Tkinter event loop self.root.mainloop() # *************************************** # INIT AND EXIT # *************************************** def app_exit(self): self.root.destroy() exit() def event_loop(self): if self.matches > 0: self.get_events() self.root.after(10, self.event_loop) def refresh_devices_display(self): self.devices_display.delete(0, self.devices_display.size()) for device in self.all_devices: self.devices_display.insert(END, device[0] + ' ' + device[1]) if self.selected_device_index >= 0: self.devices_display.itemconfig(self.selected_device_index, fg='red') self.devices_display.see(self.selected_device_index) def e_select_device(self, event): self.selected_device_index = -1 if len(self.all_devices) > 0: self.selected_device_index = int(event.widget.curselection()[0]) selected_device = self.all_devices[self.selected_device_index] self.selected_device_name = selected_device[0] self.selected_device_var.set(self.selected_device_name) self.get_matching_devices() self.refresh_devices_display() def get_all_devices(self): self.all_devices = [] devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()] for device in devices: self.all_devices.append([device.name, device.path]) def get_matching_devices(self): self.matches = 0 self.matching_devices = [] devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()] for device in devices: if self.selected_device_name in device.name: device_ref = evdev.InputDevice(device.path) self.matching_devices.append(device_ref) self.matches += 1 def get_events(self): r, w, x = select(self.matching_devices, [], [], 0) if r == []: return for event in r[0].read(): if event.type == evdev.ecodes.EV_KEY: key_event = evdev.categorize(event) if key_event.keystate == 1: key_text = 'Down' else: key_text = 'Up' # print key_event.keycode,key_text if type(key_event.keycode) is list: code_text = ', '.join(key_event.keycode) else: code_text = key_event.keycode self.events_display.config(state=NORMAL) self.events_display.insert(END, '\n' + code_text + ' ' + key_text) self.events_display.config(state=DISABLED) self.events_display.see(END)
class TVW(Frame): def __init__(self, master, *args, **kwargs): Frame.__init__(self, master) ## Variables ## self.grid() self.master = master master.title("TVW") self.showList = readData(showLocation) if self.showList == '': self.showList = [] self.showData = readData(showInfoLocation) if self.showData == '': self.showData = {} self.auto_updater = True self.run_thread = True self.cur_show = '' self.auto_progress_text = StringVar() self.update_progress_text = StringVar() self.auto_update() self.forceUpdate() ## Specialty Progress Bar ## # I somewhat understand this, but pulled offline to make it work self.style = ttk.Style(master) # add label in the layout self.style.layout('text.Horizontal.TProgressbar', [('Horizontal.Progressbar.trough', { 'children': [('Horizontal.Progressbar.pbar', { 'side': 'left', 'sticky': 'ns' })], 'sticky': 'nswe' }), ('Horizontal.Progressbar.label', { 'sticky': '' })]) # set initial text #got arround using this to change the label of all status bars, while wanting to change each individually #oh well, it works self.style.configure('text.Horizontal.TProgressbar', text='') ## Widgets ## #Details self.details = Details(self) #Out Of Date Buttons, to be set per show self.ood_buttons = [] self.list_frame = Frame(self) #list Box# self.list_scrollbar = Scrollbar(self.list_frame, orient="vertical") self.show_lb = Listbox(self.list_frame, width=30, height=15, yscrollcommand=self.list_scrollbar.set) self.show_lb.bind('<<ListboxSelect>>', self.showSelect) self.list_scrollbar.config(command=self.show_lb.yview) #Add to List# self.add_entry = Entry(self.list_frame, text="Enter Show Name") self.add_button = Button(self.list_frame, text="+", command=self.newShow) self.delete_show = Button(self.list_frame, text="Delete This Show", command=self.deleteShow) #updates# self.update_frame = Frame(self, bg='#D0D0D0') self.update_align = Frame(self.update_frame, bg='#D0D0D0') self.update_button = Button(self.update_align, text='Refresh', command=self.forceUpdate) self.auto_progress = ttk.Progressbar( self.update_align, style='text.Horizontal.TProgressbar', variable=self.auto_progress_text, length=100, mode='determinate') self.update_progress = ttk.Progressbar( self.update_align, style='text.Horizontal.TProgressbar', variable=self.update_progress_text, length=100, mode='determinate') ## LAYOUT ## #details# self.details.grid(row=0, column=1, sticky=N + E + W, padx=5, pady=5) #show list# self.list_frame.grid(row=0, column=0, rowspan=2) self.show_lb.grid(row=0, column=0, sticky=W) self.list_scrollbar.grid(row=0, column=1, sticky=N + S) self.add_entry.grid(row=1, column=0, sticky=E + W, pady=2) self.add_button.grid(row=1, column=1, sticky=W) self.delete_show.grid(row=2, column=0, columnspan=2, sticky=E + W) #update# self.update_frame.grid(row=1, column=1, sticky=S + E + W) self.update_align.pack(anchor=E) self.update_button.grid(row=0, column=1, sticky=E) self.auto_progress.grid(row=0, column=0, sticky=E) # have this appear only when running update #self.update_progress.grid(row=1,column=1, sticky=E) ### Aditional Functions ### # get show selection from Listbox def showSelect(self, evt): select = self.show_lb.curselection() show = self.showList[int(select[0])] self.cur_show = show self.details.updateDetails() # remove an out of date episode. Be up to date. def removeOOD(self, ep): print("remove", ep) self.showData[self.cur_show]['Out-of-Date'].remove(ep) self.fillListBox() self.details.updateDetails() writeData(showInfoLocation, self.showData) # Add new name to list of shows, update showLocation file, Run scrubbing script for new show, rerun FillListBox def newShow(self): #show_name = simpledialog.askstring("Name of new show","Please input Show Name") show_name = self.add_entry.get() if show_name != '': self.update([show_name]) # progress bar in lower right. always repeats. When it completes, run update function def auto_update(self): def thread_auto_update(): try: while self.run_thread: x = 0 while (x <= update_timer and self.auto_updater): x += progress_interval time.sleep(progress_interval) self.auto_progress.step( 100 / (update_timer / progress_interval)) self.style.configure( 'text.Horizontal.TProgressbar', text='{:.0f} Seconds'.format(update_timer - x)) if self.run_thread != False: self.update(self.showList) self.auto_updater = True else: print('Ending Thread') except: print( "Error in thread. Likely program ended while it was running" ) threading.Thread(target=thread_auto_update).start() # ends the current thread on auto_update, immediately forcing an update. Will reassign and restart in auto_update def forceUpdate(self): self.auto_updater = False def killUpdate(self): self.auto_updater = False self.run_thread = False # run all steps to update data. Scrub info from web, update list/new show times, ect def update(self, show_list): # Setup Variables self.add_button['state'] = 'disabled' self.update_button['state'] = 'disabled' self.update_progress.grid(row=0, column=0, sticky=W) progress = (100 / (1 + len(show_list))) self.update_progress["value"] = progress self.style.configure('text.Horizontal.TProgressbar', text="Updating") temp_show_data = {} #run Update on List of Shows for show in show_list: # check if program has closed if self.run_thread != True: break #Get data for Each Show, check if 404 or missing in list self.style.configure('text.Horizontal.TProgressbar', text=show) showInfo = updateData([show]) if showInfo == "404": print("Server Error on '", show, "', getting 404") else: temp_show_data[show] = showInfo[show] if show not in self.showList: self.showList.append(show) writeData(showLocation, self.showList) self.update_progress.step(progress) #Writing data and updating List #self.style.configure('text.Horizontal.TProgressbar', text='Updating List') self.showData = temp_show_data writeData(showInfoLocation, self.showData) self.fillListBox() self.update_progress.step(progress) #Update is complete, user can edit things again self.add_button['state'] = 'normal' self.update_button['state'] = 'normal' self.update_progress.grid_forget() # fill in the list box elements, along with Out of Date Episode Count def fillListBox(self): #### while updating list, check for out of date episodes, and include number for size next to name #### self.show_lb.delete(0, 'end') showCount = 1 state = 'none' for show in self.showList: clip = '' clip += show try: ood = len(self.showData[show]['Out-of-Date']) if ood > 0: clip += ' (' + str(ood) + ')' state = 'ood' except: print('Error Getting Out-of-Date on ' + show) self.show_lb.insert(showCount, clip) if state != 'none': self.show_lb.itemconfig(showCount - 1, foreground="red") showCount += 1 state = 'none' #delete show from all logs. Remove from show names and from info def deleteShow(self): try: self.showList.remove(self.cur_show) del self.showData[self.cur_show] writeData(showLocation, self.showList) writeData(showInfoLocation, self.showData) except: print("No Show Specified. Cannot delete.") self.fillListBox()
class vis_tool: def __init__(self): self.args = parse_args() cfg = mmcv.Config.fromfile(self.args.config) self.window = Tk() self.menubar = Menu(self.window) self.info = StringVar() self.info_label = Label( self.window, bg='yellow', width=4, textvariable=self.info) self.listBox_img = Listbox( self.window, width=50, height=25, font=('Times New Roman', 10)) self.listBox_obj = Listbox( self.window, width=50, height=12, font=('Times New Roman', 10)) self.scrollbar_img = Scrollbar( self.window, width=15, orient='vertical') self.scrollbar_obj = Scrollbar( self.window, width=15, orient='vertical') self.listBox_img_info = StringVar() self.listBox_img_label = Label( self.window, font=('Arial', 11), bg='yellow', width=4, height=1, textvariable=self.listBox_img_info) self.listBox_obj_info = StringVar() self.listBox_obj_label1 = Label( self.window, font=('Arial', 11), bg='yellow', width=4, height=1, textvariable=self.listBox_obj_info) self.listBox_obj_label2 = Label( self.window, font=('Arial', 11), bg='yellow', width=4, height=1, text='Object Class : Score (IoU)') if cfg.dataset_type == 'VOCDataset': self.data_info = VOC_dataset(cfg, self.args) elif cfg.dataset_type == 'CocoDataset': self.data_info = COCO_dataset(cfg, self.args) self.info.set('DATASET: {}'.format(self.data_info.dataset)) # load image and show it on the window self.img = self.data_info.get_img_by_index(0) self.photo = ImageTk.PhotoImage(self.img) self.label_img = Label(self.window, image=self.photo) self.show_det_txt = IntVar(value=1) self.checkbn_det_txt = Checkbutton( self.window, text='Text', font=('Arial', 10, 'bold'), variable=self.show_det_txt, command=self.change_img, fg='#0000FF') self.show_dets = IntVar(value=1) self.checkbn_det = Checkbutton( self.window, text='Detections', font=('Arial', 10, 'bold'), variable=self.show_dets, command=self.change_img, fg='#0000FF') self.show_gt_txt = IntVar(value=1) self.checkbn_gt_txt = Checkbutton( self.window, text='Text', font=('Arial', 10, 'bold'), variable=self.show_gt_txt, command=self.change_img, fg='#FF8C00') self.show_gts = IntVar(value=1) self.checkbn_gt = Checkbutton( self.window, text='Groundtruth', font=('Arial', 10, 'bold'), variable=self.show_gts, command=self.change_img, fg='#FF8C00') self.combo_label = Label( self.window, bg='yellow', width=10, height=1, text='Show Category', font=('Arial', 11)) self.combo_category = ttk.Combobox( self.window, font=('Arial', 11), values=self.data_info.aug_category.combo_list) self.combo_category.current(0) self.th_label = Label( self.window, font=('Arial', 11), bg='yellow', width=10, height=1, text='Score Threshold') self.threshold = np.float32(0.5) self.th_entry = Entry( self.window, font=('Arial', 11), width=10, textvariable=StringVar(self.window, value=str(self.threshold))) self.th_button = Button( self.window, text='Enter', height=1, command=self.change_threshold) self.iou_th_label = Label( self.window, font=('Arial', 11), bg='yellow', width=10, height=1, text='IoU Threshold') self.iou_threshold = np.float32(0.5) self.iou_th_entry = Entry( self.window, font=('Arial', 11), width=10, textvariable=StringVar(self.window, value=str(self.iou_threshold))) self.iou_th_button = Button( self.window, text='Enter', height=1, command=self.change_iou_threshold) self.find_label = Label( self.window, font=('Arial', 11), bg='yellow', width=10, height=1, text='find') self.find_name = '' self.find_entry = Entry( self.window, font=('Arial', 11), width=10, textvariable=StringVar(self.window, value=str(self.find_name))) self.find_button = Button( self.window, text='Enter', height=1, command=self.findname) self.listBox_img_idx = 0 # ====== ohter attribute ====== self.img_name = '' self.show_img = None self.output = self.args.output if not os.path.isdir(self.output): os.makedirs(self.output) self.img_list = self.data_info.img_list # flag for find/threshold button switch focused element self.button_clicked = False def change_threshold(self, event=None): try: self.threshold = np.float32(self.th_entry.get()) self.change_img() # after changing threshold, focus on listBox for easy control if self.window.focus_get() == self.listBox_obj: self.listBox_obj.focus() else: self.listBox_img.focus() self.button_clicked = True except ValueError: self.window.title('Please enter a number as score threshold.') def change_iou_threshold(self, event=None): try: self.iou_threshold = np.float32(self.iou_th_entry.get()) self.change_img() # after changing threshold, focus on listBox for easy control if self.window.focus_get() == self.listBox_obj: self.listBox_obj.focus() else: self.listBox_img.focus() self.button_clicked = True except ValueError: self.window.title("Please enter a number as IoU threshold.") # draw groundtruth def draw_gt_boxes(self, img, objs): for obj in objs: cls_name = obj[0] # according combobox to decide whether to plot this category if self.combo_category.get() == 'All': show_category = self.data_info.aug_category.category else: show_category = [self.combo_category.get()] if cls_name not in show_category: continue box = obj[1:] xmin = max(box[0], 0) ymin = max(box[1], 0) xmax = min(box[0] + box[2], self.img_width) ymax = min(box[1] + box[3], self.img_height) font = cv2.FONT_HERSHEY_SIMPLEX if self.show_gt_txt.get(): if ymax + 30 >= self.img_height: cv2.rectangle(img, (xmin, ymin), (xmin + len(cls_name) * 10, int(ymin - 20)), (255, 140, 0), cv2.FILLED) cv2.putText(img, cls_name, (xmin, int(ymin - 5)), font, 0.5, (255, 255, 255), 1) else: cv2.rectangle(img, (xmin, ymax), (xmin + len(cls_name) * 10, int(ymax + 20)), (255, 140, 0), cv2.FILLED) cv2.putText(img, cls_name, (xmin, int(ymax + 15)), font, 0.5, (255, 255, 255), 1) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), self.args.gt_box_color, 1) return img def get_iou(self, det): iou = np.zeros_like(det) GT = self.data_info.get_singleImg_gt(self.img_name) for idx, cls_objs in enumerate(det): category = self.data_info.aug_category.category[idx] BBGT = [] for t in GT: if not t[0] == category: continue BBGT.append([t[1], t[2], t[1] + t[3], t[2] + t[4]]) BBGT = np.asarray(BBGT) d = [0] * len(BBGT) # for check 1 GT map to several det confidence = cls_objs[:, 4] BB = cls_objs[:, 0:4] # bounding box # sort by confidence sorted_ind = np.argsort(-confidence) sorted_scores = np.sort(-confidence) BB = BB[sorted_ind, :] # for returning original order ind_table = {i: sorted_ind[i] for i in range(len(sorted_ind))} iou[idx] = np.zeros(len(BB)) if len(BBGT) > 0: for i in range(len(BB)): bb = BB[i, :] # compute overlaps # intersection ixmin = np.maximum(BBGT[:, 0], bb[0]) iymin = np.maximum(BBGT[:, 1], bb[1]) ixmax = np.minimum(BBGT[:, 2], bb[2]) iymax = np.minimum(BBGT[:, 3], bb[3]) iw = np.maximum(ixmax - ixmin + 1., 0.) ih = np.maximum(iymax - iymin + 1., 0.) inters = iw * ih # union uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) + (BBGT[:, 2] - BBGT[:, 0] + 1.) * (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters) overlaps = inters / uni ovmax = np.max(overlaps) # max overlaps with all gt jmax = np.argmax(overlaps) if ovmax > self.iou_threshold: if not d[jmax]: d[jmax] = 1 else: # multiple bounding boxes map to one gt ovmax = -ovmax iou[idx][ind_table[i]] = ovmax # return to unsorted order return iou def draw_all_det_boxes(self, img, single_detection): if self.data_info.has_anno: self.iou = self.get_iou(single_detection) for idx, cls_objs in enumerate(single_detection): category = self.data_info.aug_category.category[idx] if self.combo_category.get() == 'All': show_category = self.data_info.aug_category.category else: show_category = [self.combo_category.get()] if category not in show_category: continue for obj_idx, obj in enumerate(cls_objs): [score, box] = [round(obj[4], 2), obj[:4]] if score >= self.threshold: box = list(map(int, list(map(round, box)))) xmin = max(box[0], 0) ymin = max(box[1], 0) xmax = min(box[2], self.img_width) ymax = min(box[3], self.img_height) if not self.data_info.has_anno or \ self.iou[idx][obj_idx] >= self.iou_threshold: color = self.args.det_box_color else: color = (255, 0, 0) if self.show_det_txt.get(): font = cv2.FONT_HERSHEY_SIMPLEX text = category + ' : ' + str(score) if ymax + 30 >= self.img_height: cv2.rectangle( img, (xmin, ymin), (xmin + len(text) * 9, int(ymin - 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymin - 5)), font, 0.5, (255, 255, 255), 1) else: cv2.rectangle( img, (xmin, ymax), (xmin + len(text) * 9, int(ymax + 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymax + 15)), font, 0.5, (255, 255, 255), 1) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2) return img def draw_all_det_boxes_masks(self, img, single_detection): img = np.require(img, requirements=['W']) boxes, masks = single_detection # draw segmentation masks # reference mmdetection/mmdet/models/detectors/base.py if self.combo_category.get() != 'All': show_idx = self.data_info.aug_category.category.index( self.combo_category.get()) masks = np.asarray([masks[show_idx]]) boxes = np.asarray([boxes[show_idx]]) category = self.data_info.aug_category.category[show_idx] segms = list(itertools.chain(*masks)) bboxes = np.vstack(boxes) inds = np.where(np.round(bboxes[:, -1], 2) >= self.threshold)[0] self.color_list = [] for i in inds: color_mask = np.random.randint(0, 256, (1, 3), dtype=np.uint8) mask = maskUtils.decode(segms[i]).astype(np.bool) img[mask] = img[mask] * 0.5 + color_mask * 0.5 self.color_list.append('#%02x%02x%02x' % tuple(color_mask[0])) if self.data_info.has_anno: boxes2, _ = single_detection self.iou = self.get_iou(boxes2) if self.combo_category.get() != 'All': iou = np.asarray([self.iou[show_idx]]) else: iou = self.iou # draw bounding box for idx, cls_objs in enumerate(boxes): if self.combo_category.get() == 'All': category = self.data_info.aug_category.category[idx] for obj_idx, obj in enumerate(cls_objs): [score, box] = [round(obj[4], 2), obj[:4]] if score >= self.threshold: box = list(map(int, list(map(round, box)))) xmin = max(box[0], 0) ymin = max(box[1], 0) xmax = min(box[2], self.img_width) ymax = min(box[3], self.img_height) if not self.data_info.has_anno or \ iou[idx][obj_idx] >= self.iou_threshold: color = self.args.det_box_color else: color = (255, 0, 0) if self.show_det_txt.get(): font = cv2.FONT_HERSHEY_SIMPLEX text = category + ' : ' + str(score) if ymax + 30 >= self.img_height: cv2.rectangle( img, (xmin, ymin), (xmin + len(text) * 9, int(ymin - 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymin - 5)), font, 0.5, (255, 255, 255), 1) else: cv2.rectangle( img, (xmin, ymax), (xmin + len(text) * 9, int(ymax + 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymax + 15)), font, 0.5, (255, 255, 255), 1) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2) return img def change_img(self, event=None): if len(self.listBox_img.curselection()) != 0: self.listBox_img_idx = self.listBox_img.curselection()[0] self.listBox_img_info.set('Image {:6} / {:6}'.format( self.listBox_img_idx + 1, self.listBox_img.size())) name = self.listBox_img.get(self.listBox_img_idx) self.window.title('DATASET : ' + self.data_info.dataset + ' ' + name) img = self.data_info.get_img_by_name(name) self.img_width, self.img_height = img.width, img.height img = np.asarray(img) self.img_name = name self.img = img if self.data_info.has_anno and self.show_gts.get(): objs = self.data_info.get_singleImg_gt(name) img = self.draw_gt_boxes(img, objs) if self.data_info.results is not None and self.show_dets.get(): if self.data_info.mask is False: dets = self.data_info.get_singleImg_dets(name) img = self.draw_all_det_boxes(img, dets) else: dets = self.data_info.get_singleImg_dets(name).transpose( (1, 0)) img = self.draw_all_det_boxes_masks(img, dets) self.clear_add_listBox_obj() self.show_img = img img = Image.fromarray(img) img = self.scale_img(img) self.photo = ImageTk.PhotoImage(img) self.label_img.config(image=self.photo) self.window.update_idletasks() if self.img_name in os.listdir(self.output): self.listBox_img_label.config(bg='#CCFF99') else: self.listBox_img_label.config(bg='yellow') def draw_one_det_boxes(self, img, single_detection, selected_idx=-1): idx_counter = 0 for idx, cls_objs in enumerate(single_detection): category = self.data_info.aug_category.category[idx] if self.combo_category.get() == 'All': show_category = self.data_info.aug_category.category else: show_category = [self.combo_category.get()] if category not in show_category: continue for obj_idx, obj in enumerate(cls_objs): [score, box] = [round(obj[4], 2), obj[:4]] if score >= self.threshold: if idx_counter == selected_idx: box = list(map(int, list(map(round, box)))) xmin = max(box[0], 0) ymin = max(box[1], 0) xmax = min(box[2], self.img_width) ymax = min(box[3], self.img_height) if not self.data_info.has_anno or \ self.iou[idx][obj_idx] >= self.iou_threshold: color = self.args.det_box_color else: color = (255, 0, 0) if self.show_det_txt.get(): font = cv2.FONT_HERSHEY_SIMPLEX text = category + ' : ' + str(score) if ymax + 30 >= self.img_height: cv2.rectangle( img, (xmin, ymin), (xmin + len(text) * 9, int(ymin - 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymin - 5)), font, 0.5, (255, 255, 255), 1) else: cv2.rectangle( img, (xmin, ymax), (xmin + len(text) * 9, int(ymax + 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymax + 15)), font, 0.5, (255, 255, 255), 1) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2) return img else: idx_counter += 1 def draw_one_det_boxes_masks(self, img, single_detection, selected_idx=-1): img = np.require(img, requirements=['W']) boxes, masks = single_detection # draw segmentation masks # reference mmdetection/mmdet/models/detectors/base.py if self.combo_category.get() != 'All': show_idx = self.data_info.aug_category.category.index( self.combo_category.get()) category = self.data_info.aug_category.category[ show_idx] # fixed category masks = np.asarray([masks[show_idx]]) boxes = np.asarray([boxes[show_idx]]) segms = list(itertools.chain(*masks)) bboxes = np.vstack(boxes) inds = np.where(np.round(bboxes[:, -1], 2) >= self.threshold)[0] self.color_list = [] for inds_idx, i in enumerate(inds): if inds_idx == selected_idx: color_mask = np.random.randint(0, 256, (1, 3), dtype=np.uint8) mask = maskUtils.decode(segms[i]).astype(np.bool) img[mask] = img[mask] * 0.5 + color_mask * 0.5 self.color_list.append('#%02x%02x%02x' % tuple(color_mask[0])) if self.data_info.has_anno: if self.combo_category.get() != 'All': iou = np.asarray([self.iou[show_idx]]) else: iou = self.iou # draw bounding box idx_counter = 0 for idx, cls_objs in enumerate(boxes): if self.combo_category.get() == 'All': category = self.data_info.aug_category.category[idx] for obj_idx, obj in enumerate(cls_objs): [score, box] = [round(obj[4], 2), obj[:4]] if score >= self.threshold: if idx_counter == selected_idx: box = list(map(int, list(map(round, box)))) xmin = max(box[0], 0) ymin = max(box[1], 0) xmax = min(box[2], self.img_width) ymax = min(box[3], self.img_height) if not self.data_info.has_anno or \ iou[idx][obj_idx] >= self.iou_threshold: color = self.args.det_box_color else: color = (255, 0, 0) if self.show_det_txt.get(): font = cv2.FONT_HERSHEY_SIMPLEX text = category + ' : ' + str(score) if ymax + 30 >= self.img_height: cv2.rectangle( img, (xmin, ymin), (xmin + len(text) * 9, int(ymin - 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymin - 5)), font, 0.5, (255, 255, 255), 1) else: cv2.rectangle( img, (xmin, ymax), (xmin + len(text) * 9, int(ymax + 20)), (0, 0, 255), cv2.FILLED) cv2.putText(img, text, (xmin, int(ymax + 15)), font, 0.5, (255, 255, 255), 1) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2) return img else: idx_counter += 1 # plot only one object def change_obj(self, event=None): if len(self.listBox_obj.curselection()) == 0: self.listBox_img.focus() return else: listBox_obj_idx = self.listBox_obj.curselection()[0] self.listBox_obj_info.set('Detected Object : {:4} / {:4}'.format( listBox_obj_idx + 1, self.listBox_obj.size())) name = self.listBox_img.get(self.listBox_img_idx) img = self.data_info.get_img_by_name(name) self.img_width, self.img_height = img.width, img.height img = np.asarray(img) self.img_name = name self.img = img if self.data_info.has_anno and self.show_gts.get(): objs = self.data_info.get_singleImg_gt(name) img = self.draw_gt_boxes(img, objs) if self.data_info.results is not None and self.show_dets.get(): if self.data_info.mask is False: dets = self.data_info.get_singleImg_dets(name) img = self.draw_one_det_boxes(img, dets, listBox_obj_idx) else: dets = self.data_info.get_singleImg_dets(name).transpose( (1, 0)) img = self.draw_one_det_boxes_masks(img, dets, listBox_obj_idx) self.show_img = img img = Image.fromarray(img) img = self.scale_img(img) self.photo = ImageTk.PhotoImage(img) self.label_img.config(image=self.photo) self.window.update_idletasks() if self.img_name in os.listdir(self.output): self.listBox_img_label.config(bg='#CCFF99') else: self.listBox_img_label.config(bg='yellow') # ============================================ def scale_img(self, img): [s_w, s_h] = [1, 1] # if window size is (1920, 1080), # the default max image size is (1440, 810) (fix_width, fix_height) = (1440, 810) # change image size according to window size if self.window.winfo_width() != 1: fix_width = ( self.window.winfo_width() - self.listBox_img.winfo_width() - self.scrollbar_img.winfo_width() - 5) # fix_height = int(fix_width * 9 / 16) fix_height = 750 # handle image size is too big if img.width > fix_width: s_w = fix_width / img.width if img.height > fix_height: s_h = fix_height / img.height scale = min(s_w, s_h) img = img.resize((int(img.width * scale), int(img.height * scale)), Image.ANTIALIAS) return img def clear_add_listBox_obj(self): self.listBox_obj.delete(0, 'end') if self.data_info.mask is False: single_detection = self.data_info.get_singleImg_dets( self.img_list[self.listBox_img_idx]) else: single_detection, single_mask = self.data_info.get_singleImg_dets( self.img_list[self.listBox_img_idx]).transpose((1, 0)) if self.combo_category.get() == 'All': show_category = self.data_info.aug_category.category else: show_category = [self.combo_category.get()] num = 0 for idx, cls_objs in enumerate(single_detection): category = self.data_info.aug_category.category[idx] if category not in show_category: continue for obj_idx, obj in enumerate(cls_objs): score = np.round(obj[4], 2) if score >= self.threshold: if not self.data_info.has_anno: self.listBox_obj.insert('end', category + " : " + str(score)) elif self.iou[idx][obj_idx] > self.iou_threshold: s = "{:15} : {:5.3} ( {:<6.3})".format( category, score, abs(round(self.iou[idx][obj_idx], 2))) self.listBox_obj.insert('end', s) self.listBox_obj.itemconfig(num, fg="green") else: s = "{:15} : {:5.3} ( {:<6.3})".format( category, score, abs(round(self.iou[idx][obj_idx], 2))) self.listBox_obj.insert('end', s) self.listBox_obj.itemconfig(num, fg="red") num += 1 self.listBox_obj_info.set('Detected Object : {:3}'.format(num)) def change_threshold_button(self, v): self.threshold += v if self.threshold <= 0: self.threshold = 0 elif self.threshold >= 1: self.threshold = 1 self.th_entry.delete(0, END) self.th_entry.insert(0, str(round(self.threshold, 2))) self.change_threshold() def change_iou_threshold_button(self, v): self.iou_threshold += v if self.iou_threshold <= 0: self.iou_threshold = 0 elif self.iou_threshold >= 1: self.iou_threshold = 1 self.iou_th_entry.delete(0, END) self.iou_th_entry.insert(0, str(round(self.iou_threshold, 2))) self.change_iou_threshold() def save_img(self): print('Save image to ' + os.path.join(self.output, self.img_name)) cv2.imwrite( os.path.join(self.output, self.img_name), cv2.cvtColor(self.show_img, cv2.COLOR_BGR2RGB)) self.listBox_img_label.config(bg='#CCFF99') def eventhandler(self, event): entry_list = [self.find_entry, self.th_entry, self.iou_th_entry] if self.window.focus_get() not in entry_list: if platform.system() == 'Windows': state_1key = 8 state_2key = 12 else: # 'Linux' state_1key = 16 state_2key = 20 if event.state == state_2key and event.keysym == 'Left': self.change_iou_threshold_button(-0.1) elif event.state == state_2key and event.keysym == 'Right': self.change_iou_threshold_button(0.1) elif event.state == state_1key and event.keysym == 'Left': self.change_threshold_button(-0.1) elif event.state == state_1key and event.keysym == 'Right': self.change_threshold_button(0.1) elif event.keysym == 'q': self.window.quit() elif event.keysym == 's': self.save_img() if self.button_clicked: self.button_clicked = False else: if event.keysym in ['KP_Enter', 'Return']: self.listBox_obj.focus() self.listBox_obj.select_set(0) elif event.keysym == 'Escape': self.change_img() self.listBox_img.focus() def combobox_change(self, event=None): self.listBox_img.focus() self.change_img() def clear_add_listBox_img(self): self.listBox_img.delete(0, 'end') # delete listBox_img 0 ~ end items # add image name to listBox_img for item in self.img_list: self.listBox_img.insert('end', item) self.listBox_img.select_set(0) self.listBox_img.focus() self.change_img() def findname(self, event=None): self.find_name = self.find_entry.get() new_list = [] if self.find_name == '': new_list = self.data_info.img_list else: for img_name in self.data_info.img_list: if self.find_name[0] == '!': if self.find_name[1:] not in img_name: new_list.append(img_name) else: if self.find_name in img_name: new_list.append(img_name) if len(new_list) != 0: self.img_list = new_list self.clear_add_listBox_img() self.clear_add_listBox_obj() self.button_clicked = True else: self.window.title("Can't find any image about '{}'".format( self.find_name)) def run(self): self.window.title('DATASET : ' + self.data_info.dataset) self.window.geometry('1280x800+350+100') # self.menubar.add_command(label='QUIT', command=self.window.quit) self.window.config(menu=self.menubar) # display the menu self.scrollbar_img.config(command=self.listBox_img.yview) self.listBox_img.config(yscrollcommand=self.scrollbar_img.set) self.scrollbar_obj.config(command=self.listBox_obj.yview) self.listBox_obj.config(yscrollcommand=self.scrollbar_obj.set) layer1 = 0 layer2 = 50 # ======================= layer 1 ========================= # combobox self.combo_label.grid( row=layer1 + 30, column=0, sticky=W + E + N + S, padx=3, pady=3, columnspan=6) self.combo_category.grid( row=layer1 + 30, column=6, sticky=W + E + N + S, padx=3, pady=3, columnspan=6) # show det self.checkbn_det.grid( row=layer1 + 40, column=0, sticky=N + S, padx=3, pady=3, columnspan=4) # show det text self.checkbn_det_txt.grid( row=layer1 + 40, column=4, sticky=N + S, padx=3, pady=3, columnspan=2) if self.data_info.has_anno != False: # show gt self.checkbn_gt.grid( row=layer1 + 40, column=6, sticky=N + S, padx=3, pady=3, columnspan=4) # show gt text self.checkbn_gt_txt.grid( row=layer1 + 40, column=10, sticky=N + S, padx=3, pady=3, columnspan=2) # ======================= layer 2 ========================= self.listBox_img_label.grid( row=layer2 + 0, column=0, sticky=N + S + E + W, columnspan=12) # find name self.find_label.grid( row=layer2 + 20, column=0, sticky=E + W, columnspan=4) self.find_entry.grid( row=layer2 + 20, column=4, sticky=E + W, columnspan=4) self.find_button.grid( row=layer2 + 20, column=8, sticky=E + W, pady=3, columnspan=4) self.scrollbar_img.grid(row=layer2 + 30, column=11, sticky=N + S + W) self.label_img.grid( row=layer1 + 30, column=12, sticky=N + E, padx=3, pady=3, rowspan=110) self.listBox_img.grid( row=layer2 + 30, column=0, sticky=N + S + E + W, pady=3, columnspan=11) if self.data_info.det_file != '': self.th_label.grid( row=layer2 + 40, column=0, sticky=E + W, columnspan=6) self.th_entry.grid( row=layer2 + 40, column=6, sticky=E + W, columnspan=3) self.th_button.grid( row=layer2 + 40, column=9, sticky=E + W, columnspan=3) if self.data_info.has_anno != False: self.iou_th_label.grid( row=layer2 + 50, column=0, sticky=E + W, columnspan=6) self.iou_th_entry.grid( row=layer2 + 50, column=6, sticky=E + W, columnspan=3) self.iou_th_button.grid( row=layer2 + 50, column=9, sticky=E + W, columnspan=3) self.listBox_obj_label1.grid( row=layer2 + 60, column=0, sticky=E + W, pady=3, columnspan=12) if self.data_info.has_anno != False: self.listBox_obj_label2.grid( row=layer2 + 70, column=0, sticky=E + W, pady=2, columnspan=12) self.scrollbar_obj.grid( row=layer2 + 80, column=11, sticky=N + S + W, pady=3) self.listBox_obj.grid( row=layer2 + 80, column=0, sticky=N + S + E + W, pady=3, columnspan=11) self.clear_add_listBox_img() self.listBox_img.bind('<<ListboxSelect>>', self.change_img) self.listBox_img.bind_all('<KeyRelease>', self.eventhandler) self.listBox_obj.bind('<<ListboxSelect>>', self.change_obj) self.th_entry.bind('<Return>', self.change_threshold) self.th_entry.bind('<KP_Enter>', self.change_threshold) self.iou_th_entry.bind('<Return>', self.change_iou_threshold) self.iou_th_entry.bind('<KP_Enter>', self.change_iou_threshold) self.find_entry.bind('<Return>', self.findname) self.find_entry.bind('<KP_Enter>', self.findname) self.combo_category.bind('<<ComboboxSelected>>', self.combobox_change) self.window.mainloop()
class convertTab: def __init__(self, root): self.root = root self.conversioning = False self._upperFrame() self._lowerFrame() def _upperFrame(self): frame = LabelFrame(self.root, text="Paths") frame.grid(row=0, column=0, sticky="snew", padx=(5, 5), pady=(5, 5), ipady=10, ipadx=10) frame.columnconfigure(1, weight=5) frame.columnconfigure(2, weight=1) self.targetLabel = Label(frame, text="Save to", fg="blue", cursor="hand2") self.targetLabel.grid(row=0, column=0, sticky="w", padx=(10, 10), pady=(15, 6)) self.targetLabel.bind("<Button-1>", lambda event: self._dirBrowse()) f = font.Font(self.targetLabel, self.targetLabel.cget("font")) f.configure(underline=True) self.targetLabel.configure(font=f) self.pathLabel = Label(frame, text=DDIR, fg="grey", anchor="w") self.pathLabel.grid(row=0, column=1, sticky="we", padx=(10, 10), pady=(15, 6), columnspan=2) Label(frame, text="Files").grid(row=1, column=0, sticky="wn", padx=(10, 10), pady=(15, 6)) def addListBox(): textFrame = Frame(frame) textFrame.grid(row=1, column=1, sticky="ew", padx=(10, 10), pady=(15, 6), rowspan=3) textFrame.columnconfigure(0, weight=1) self.lst = Listbox(textFrame, selectmode=MULTIPLE) self.lst.grid(row=0, column=0, sticky="snew") scrllx = Scrollbar(textFrame, orient="horizontal", command=self.lst.xview) scrlly = Scrollbar(textFrame, orient="vertical", command=self.lst.yview) self.lst["xscrollcommand"] = scrllx.set self.lst["yscrollcommand"] = scrlly.set scrllx.grid(row=1, column=0, sticky="snew") scrlly.grid(row=0, column=1, sticky="snew") addListBox() self.addBtn = Button(frame, text="add", relief="groove", command=self._addToListBox) self.removeBtn = Button(frame, text="remove", relief="groove", command=self._removeFromList) self.clearBtn = Button(frame, text="clear", relief="groove", command=self._clearList) self.addBtn.grid(row=1, column=2, sticky="ews", padx=(5, 10), pady=(15, 6)) self.removeBtn.grid(row=2, column=2, sticky="ew", padx=(5, 10), pady=(15, 6)) self.clearBtn.grid(row=3, column=2, sticky="ewn", padx=(5, 10), pady=(15, 6)) def _fileBrowse(self): get = askopenfile() if get != None: if not path.splitext(path.basename(get.name))[1][1:] in [ "mp3", "mp4", "3gp", "wav", "m4a", "flac", "wma", "acc", "ogg", "mp2", "amr", "webm", "gif" ]: messagebox.showerror("media error", "the type of the file is not allowed") else: self.lst.insert(0, get.name) def _dirBrowse(self): get = askdirectory() if get != "": self.pathLabel.config(text=get) def _clearList(self): for i in range(self.lst.size()): self.lst.delete(i, END) def _removeFromList(self): items = self.lst.curselection() pos = 0 for i in items: idx = int(i) - pos self.lst.delete(idx, idx) pos = pos + 1 self._colorListBox() def _addToListBox(self): self._fileBrowse() self._colorListBox() def _colorListBox(self): for i in range(self.lst.size()): if i % 2 == 1: self.lst.itemconfig(i, {"bg": "#e8dada"}) else: self.lst.itemconfig(i, {"bg": "#FFF"}) #mp3 wav m4a flac wma acc ogg mp2 amr def _lowerFrame(self): frame = LabelFrame(self.root, text="Conversion") frame.grid(row=1, column=0, sticky="snew", padx=(5, 5), pady=(5, 5), ipady=10, ipadx=10) #frame.columnconfigure(0,weight=1) frame.columnconfigure(1, weight=1) frame.rowconfigure(2, weight=1) text = "You can change the type of media files, by giving their path at the previous step,\nthen choose the new format of them, we have design it to be very easy for novice users it's just one click to go" lbl = Label(frame, text=text, justify="center") lbl.grid(row=0, column=0, sticky="we", padx=(10, 10), pady=(15, 20), columnspan=2) Label(frame, text="choose profile ").grid(row=1, column=0, padx=(10, 10), sticky="w") def addOptionMenu(row, col): self.format = StringVar(frame) options = [ "mp3", "mp4", "wav", "m4a", "flac", "wma", "acc", "3gp", "ogg", "mp2", "amr", "webm", "gif" ] self.format.set(options[0]) optionMenu = Combobox(frame, textvariable=self.format, state="readonly", values=options) optionMenu.grid(row=row, column=col, sticky="we", ipady=1, padx=(10, 10)) addOptionMenu(1, 1) self.convertBtn = Button( frame, text="Convert", relief="groove", command=lambda: self._startNewThread(self._conversion, ())) self.convertBtn.grid(row=2, column=1, sticky="se", columnspan=2, padx=(10, 10), pady=(10, 5), ipady=2, ipadx=3) self.convertInfo = Label(frame, text="") self.convertInfo.grid(row=2, column=0, sticky="sw", padx=(10, 10), pady=(10, 5), ipady=2, ipadx=3) def _startNewThread(self, func, args): thrd = Thread(target=func, args=args) thrd.setDaemon(True) thrd.start() def _conversion(self): total = self.lst.size() self.convertBtn.configure(state="disabled") if total == 0: return success = 0 failed = 0 files = [] f = self.format.get() for index in range(total): files.append(self.lst.get(index)) for index in range(len(files)): self.convertInfo.configure(text="please wait " + str((index + 1)) + " of " + str(total) + " ...") result = changeFormat(files[index], self.pathLabel.cget("text"), f) if result == False: failed += 1 elif result == True: success += 1 self.convertInfo.configure(text="total: " + str(total) + " success: " + str(success) + " failed: " + str(failed)) self.convertBtn.configure(state="active")
class ProjectListForm: def __init__(self, Cache, conn): self.Cache = Cache self.Connection = conn master = Tk() self.Master = master master.protocol('WM_DELETE_WINDOW', self.Quit) self.Master.title("Projects") self.AddButton = Button(master, text='Add', command=self.Add) self.AddButton.grid(row=0, column=0, sticky='NSEW') self.EditButton = Button(master, text='Edit', command=self.Edit) self.EditButton.grid(row=0, column=1, sticky='NSEW') self.DeleteButton = Button(master, text='Delete', command=self.Delete) self.DeleteButton.grid(row=0, column=2, sticky='NSEW') self.ActivationButton = Button(master, text='(De)Activate', command=self.ToggleActivation) self.ActivationButton.grid(row=0, column=3, sticky='NSEW') self.ShowOnlyActive = False self.ShowActiveOnlyButton = Button(master, text='Show Only Active', command=self.ToggleActiveProjects) self.ShowActiveOnlyButton.grid(row=0, column=4, sticky='NSEW') self.ProjectsListBox = Listbox(master, width=80) self.ProjectsListBox.grid(row=1, column=0, columnspan=10, sticky='NSEW') self.FillProjects() self.ProjectsListBox.bind('<Double-1>', lambda x: self.Edit()) # def CloseWindow(self): # self.Master.quit() def Quit(self): self.Master.quit() def Show(self): self.Master.mainloop() def ToggleActivation(self): sel = self.ProjectsListBox.curselection()[0] project = self.Cache.AllProjects[sel] if project.Active == 0: project.Active = 1 else: project.Active = 0 project.Button = None bl = BLProject.BLProject(self.Connection) bl.Update(project) self.Cache.RefreshProjects() self.FillProjects() def ToggleActiveProjects(self): self.ShowOnlyActive = not self.ShowOnlyActive self.FillProjects() def FillProjects(self): self.ProjectsListBox.delete(0, END) if self.ShowOnlyActive: projects = self.Cache.ActiveProjects else: projects = self.Cache.AllProjects for item in projects: self.ProjectsListBox.insert(END, item) for i in range(0, self.ProjectsListBox.size()): item = projects[i] active = item.Active if active == 0: self.ProjectsListBox.itemconfig(i, {'bg': 'red'}) def Add(self): pr = ProjectEditForm(self.Connection) pr.Show() self.Cache.RefreshProjects() self.FillProjects() pr.Master.destroy() def Edit(self): sel = self.ProjectsListBox.curselection()[0] project = self.GetProject(sel) pr = ProjectEditForm(self.Connection, project) pr.Show() self.Cache.RefreshProjects() self.FillProjects() pr.Master.destroy() def Delete(self): sel = self.ProjectsListBox.curselection()[0] project = self.GetProject(sel) bl = BLProject.BLProject(self.Connection) bl.DeleteByID(project.ID) self.Cache.RefreshProjects() self.FillProjects() def GetProject(self, ID): if self.ShowOnlyActive: return self.Cache.ActiveProjects[ID] else: return self.Cache.AllProjects[ID]
class StatePopup(object): def __init__(self, master, default_value, state_probs): top = self.top = Toplevel(master.canvas) self.master = master self.l = Label(top, text="New State") self.l.grid(row=0, column=0, columnspan=2) self.lb = Listbox( top ) # OptionMenu(top, Tkinter.StringVar().set(self.states[-1]), *self.states) self.lb.insert("end", "0") for i, (state, color) in enumerate(self.master.trail.colorlist.items()): str = ",".join(["{:x}".format(x) for x in state]) self.lb.insert("end", str) self.lb.itemconfig(i + 1, {"bg": color}) self.lb.grid(row=1, column=1, padx=(MARGIN_LR // 2), pady=MARGIN_TB) self.lb.config(height=5, width=8) self.lb.bind( "<Double-Button-1>", lambda x: self.set_text(self.lb.get(self.lb.curselection()))) self.e = Entry(top) self.e.insert(0, default_value) self.e.bind("<Control-KeyRelease-a>", lambda x: self.select_all()) self.e.grid(row=1, column=0, sticky=N, padx=(MARGIN_LR // 2), pady=MARGIN_TB) self.e.select_range(0, 'end') self.e.icursor('end') self.e.focus() self.b = Button(top, text='Ok', command=self.check_cleanup) self.top.protocol("WM_DELETE_WINDOW", self.close) self.b.grid(row=3, column=0, columnspan=2) self.l2 = Label(top, text="Probabilities") self.l2.grid(row=4, column=0, columnspan=2) for i, x in enumerate(state_probs): # if x > 0: # l = Label(top, text=hex(i)[2:] + ":" + str(x)) # l.pack() pass self.top.bind("<Return>", lambda x: self.check_cleanup()) self.top.bind("<Escape>", lambda x: self.close()) self.value = None self.top.wait_visibility() # stop interaction in other gui self.top.grab_set() def set_text(self, text): self.e.delete(0, 'end') self.e.insert(0, text) def select_all(event): event.e.select_range(0, 'end') # move cursor to the end event.e.icursor('end') return 'break' def check_cleanup(self): newstate = self.e.get() if newstate == "": self.value = list( range( 0, 2**(self.master.trail.statebitsize // self.master.trail.statesize))) elif newstate == "*": self.value = list( range( 1, 2**(self.master.trail.statebitsize // self.master.trail.statesize))) else: try: state = [] for x in newstate.split(","): x = x.strip() x = int(x, 16) assert x < 2**(self.master.trail.statebitsize // self.master.trail.statesize) state.append(x) assert len(state) > 0 self.value = state except Exception as e: print("Exception: " + str(e)) self.value = None return self.close() def close(self): self.top.grab_release() self.top.destroy()
def CurrentSongInfo(self): def OnPlayListClick(event): newsongtitle = PlayList.get(PlayList.curselection()) for i in range(0, int(length)): try: if (songlist[i]['title'] == newsongtitle): newsongindex = i break except KeyError: if (songlist[i]['artist'] == newsongtitle): newsongindex = i break rpi.playid(songlist[newsongindex]['id']) rpi.update() def ftime(time): time = int(time) return str(int(time / 60)) + ':' + '%.2d' % int(time % 60) self.currentsong = StringVar(self) rpi.update() cs = rpi.currentsong() ss = rpi.status() try: artist = cs['artist'] except KeyError: artist = '**' try: album = cs['album'] except KeyError: album = '**' try: title = cs['title'] except KeyError: title = '**' #track = cs['track'] try: num = str(int(ss['song']) + 1) except KeyError: num = '' length = ss['playlistlength'] try: cur_time = ftime(ss['time'].split(':')[0]) except KeyError: cur_time = "0:00" # total time try: total_time = ftime(cs['time']) except KeyError: total_time = "0:00" self.currentsong.set(artist + ' - ' + title + '\n' + album + '\n' + num + '/' + length + '\n\n' + cur_time + '/' + total_time) lblframe = LabelFrame(self, text="Now Playing", width=600, height=100) lblframe.grid(row=1, column=0, columnspan=7, pady=40) #lblframe.grid(row=0, column=1) lblframe.grid_propagate(0) lbl = Label(lblframe, textvariable=self.currentsong, font=('Tahoma', (9))) lbl.grid(row=1, column=0) lbl.grid_propagate(0) PlayList = Listbox(self, width=80) PlayList.grid(row=3, column=1, columnspan=5, padx=20) songlist = rpi.playlistid() for i in range(0, int(length)): try: PlayList.insert(i, songlist[i]['title']) except KeyError: PlayList.insert(i, songlist[i]['artist']) if (len(cs) != 0): if (cs['id'] == songlist[i]['id']): PlayList.itemconfig(i, background='blue', foreground='white') PlayList.bind('<<ListboxSelect>>', OnPlayListClick)
class ListFrame(Frame): def __init__(self, master, root, recursive, regex, repl, options): Frame.__init__(self, master) self._left_list = Listbox(self) self._left_list.pack(side=LEFT, fill=BOTH, expand=True) self._right_list = Listbox(self) self._right_list.pack(side=LEFT, fill=BOTH, expand=True) self._right_scroll = Scrollbar(self._right_list, orient=VERTICAL) self._right_list.config(yscrollcommand=self._right_scroll.set) self._right_scroll.config(command=self._right_list.yview) self._scrollbar = Scrollbar(self, orient=VERTICAL, command=self._scroll_scrollbar) self._scrollbar.pack(side=RIGHT, fill=Y) self._left_list.config(yscrollcommand=self._scroll_left) self._right_list.config(yscrollcommand=self._scroll_right) self._regex = regex self._repl = repl self._settings = options self._root = None self._recursive = None self._names = None self._mapping = None self._errors = None self._update_root(root, recursive) master.bind('<<RootUpdate>>', self._on_root_update) master.bind('<<RegexUpdate>>', self._on_regex_update) master.bind('<<OptionsUpdate>>', self._on_options_update) master.bind('<<Refresh>>', self._on_refresh) def _scroll_left(self, sfrom, sto): self._scrollbar.set(sfrom, sto) self._right_list.yview('moveto', sfrom) def _scroll_right(self, sfrom, sto): self._scrollbar.set(sfrom, sto) self._left_list.yview('moveto', sfrom) def _scroll_scrollbar(self, *args): self._left_list.yview(*args) self._right_list.yview(*args) def _on_root_update(self, event): self._update_root(event.widget.root, event.widget.recursive) def _on_regex_update(self, event): self._update_regex(event.widget.regex, event.widget.repl) def _on_refresh(self, event): self._update_root(self._root, self._recursive) def _on_options_update(self, event): self._settings = event.widget.options self._update_lists() def _update_regex(self, regex, repl): self._regex = regex self._repl = repl self._update_lists() def _is_type_enabled(self, ftype): if ftype is True: return self._settings.files elif ftype is False: return self._settings.dirs else: return self._settings.others def _walk(self): for root, dirs, files in os.walk(self._root): for name in files + dirs: path = os.path.join(root, name) yield os.path.relpath(path, self._root) def _entries(self): if self._recursive: return self._walk() else: return os.listdir(self._root) def _update_root(self, root, recursive): self._root = root self._recursive = recursive self._left_list.delete(0, END) self._names = [] if self._root: for name in sorted(self._entries()): path = os.path.join(self._root, name) ftype = None if os.path.isfile(path): ftype = True if os.path.isdir(path): ftype = False self._names.append((name, ftype)) self._update_lists() def _insert_name_both(self, name, color, color_right_only=False): idx = self._left_list.size() self._left_list.insert(END, name) if not color_right_only: self._left_list.itemconfig(idx, dict(fg=color)) self._right_list.insert(END, name) self._right_list.itemconfig(idx, dict(fg=color)) def _update_lists(self): self._mapping = [] self._errors = [] rev_mapping = {} self._left_list.delete(0, END) self._right_list.delete(0, END) if not self._repl: self._errors.append('Invalid replacement string') for name, ftype in self._names: enabled = self._is_type_enabled(ftype) if enabled or not self._settings.hide_wrong_type: if not enabled or not self._regex: self._insert_name_both(name, 'gray') elif self._regex and not self._regex.match(name): if not self._settings.hide_mismatches: self._insert_name_both(name, 'gray') elif not self._repl: self._insert_name_both(name, 'gray', color_right_only=True) else: idx = self._left_list.size() right_name = self._regex.sub(self._repl, name) self._left_list.insert(END, name) self._right_list.insert(END, right_name) if name != right_name: self._mapping.append((name, right_name)) right_path = os.path.join(self._root, right_name) if os.path.exists(right_path): error = 'File already exists: %s' % right_name elif right_name in rev_mapping: other_name, other_idx = rev_mapping[right_name] colliding_sources = name, other_name error = 'Name collision: %s <- %s | %s' % (right_name, *colliding_sources) self._right_list.itemconfig(other_idx, dict(fg='red')) else: error = None rev_mapping[right_name] = name, idx if error: self._errors.append(error) self._right_list.itemconfig(idx, dict(fg='red')) @property def mapping(self): if not self._errors: return self._mapping @property def errors(self): return self._errors
class MyFirstGUI: def __init__(self, tkRoot): self.tkRoot = tkRoot self.con = pyodbc.connect(driver="{SQL Server}", server=".", database="DomoticaDB") self.dbCmd = "SELECT * FROM [dbo].[Items]" tkRoot.title("SQL monitor") # Top Frame --- --- --- self.labelsFrame = Frame(tkRoot) self.labelsFrame.pack(fill="both", expand='YES') self.listbox = Listbox(self.labelsFrame) self.listbox.pack(fill="both", expand='YES') self.listbox.config(font='Consolas', justify='center') # Bottom Frame --- --- --- self.bottomFrame = Frame(tkRoot) self.bottomFrame.pack(fill="both", expand='YES') self.label = Label(self.bottomFrame, text="Placeholder") self.label.pack(side="left", expand='yes') self.entry = Entry(self.bottomFrame, width=0) self.entry.insert(0, self.dbCmd) self.entry.pack(side="left", expand='yes') # Root Frame --- --- --- self.greet_button = Button(tkRoot, text="Update Query", command=self.update_query) self.greet_button.pack() self.close_button = Button(tkRoot, text="Close", command=tkRoot.quit) self.close_button.pack() self.tkRoot.after(1000, self.update) def update_query(self): self.label.configure(text=self.entry.get()) self.dbCmd = self.entry.get() def update(self): msg = self.get_sql(self.dbCmd) self.listbox.delete(0, END) [self.listbox.insert(END, item) for item in msg] for each in range(0, self.listbox.size()): self.listbox.itemconfig(each, bg=self.tkRoot['bg']) self.listbox.config(width=0) self.tkRoot.after(1000, self.update) #self.entry.delete(0, "end") #self.entry.insert(0, self.dbCmd) def get_sql(self, cmd): cur = self.con.cursor() res = cur.execute(cmd) ret = [] for r in res: for each in [0, 3, 4]: if (r[each] is None): r[each] = "" ret.append( f"Id: {r[0]:>10} \tName: {r[3][:20] : <25} \tNice name: {r[4][:20]:<25}" ) #" \tknown_device_id: {r[10]}") # if( "zwave" in r[4]): # if(r[3] is not None and r[9] is not None): # ret.append() # else: # if r[3] is None: # r[3] = "None" # if r[9] is None: # r[9] = "None" # ret.append(f"Id: {r[0]} \tName: {r[3][:20]:<25} \tNice name: {r[9][:20]:<25} \tknown_device_id: {r[11]}") return ret
class Gui(Tk): biome_listbox = None biome_listbox_lbl = None biome_filter_var = None biome_filter_box = None biome_select_btn = None study_listbox = None study_listbox_lbl = None study_select_btn = None study_filter_var = None study_filter_box = None study_id_disp = None study_id_var = None study_title_disp = None study_title_var = None study_desc_disp = None study_desc_var = None study_scientific_names = None study_sci_names_var = None biome_selection_btn = None biome_selection = None biome_selection_lbl = None biome_tag_btn = None tagging_confirmation_lbl = None tagging_confirmation_var = None suggested_biomes = [] ena_view_btn = None def __init__(self, biome_classifier=None): # Create the menu super().__init__() args = parse_args() self.btc = BiomeTaggingTool(args.db) self.biome_classifier = biome_classifier self.list_frame = Frame() self.list_frame.grid(row=1, column=0, padx=10, pady=3) self.details_frame = Frame() self.details_frame.grid(row=3, column=0, padx=10, pady=3) header = Label(self, text='Tagging biomes on db: ' + args.db) header.grid(row=0, column=0, padx=10, pady=3) self.title = 'Biome tagging!' self.biomes_list = get_biomes() self.init_biome_list() self.init_study_list() self.init_study_display() self.init_biome_conf_display() self.init_confirmation_line() def init_biome_list(self): self.biome_listbox_lbl = Label(self.list_frame, text='List of biomes (click to select)') self.biome_listbox_lbl.grid(row=0, column=1, padx=10, pady=3) self.biome_listbox = Listbox(self.list_frame, width=75) self.biome_listbox.grid(row=1, column=1, padx=10, pady=3) self.biome_listbox.bind('<Double-Button>', self.select_biome) for b in self.biomes_list: self.biome_listbox.insert(END, b) self.biome_filter_var = StringVar() self.biome_filter_var.trace( "w", lambda name, index, mode: self.filter_biome_list()) biome_filter_row = Frame(self.list_frame) biome_filter_row.grid(row=2, column=1, padx=10, pady=3) biome_filter_lbl = Label(biome_filter_row, text='Search biomes: ') biome_filter_lbl.grid(row=0, column=0, padx=10, pady=3) self.biome_match_case = IntVar() self.biome_filter_caps_checkbox = Checkbutton( biome_filter_row, text='Match case', variable=self.biome_match_case, command=self.filter_biome_list) self.biome_filter_caps_checkbox.grid(row=1, column=0, padx=10, pady=3) self.biome_filter_box = Entry(biome_filter_row, textvariable=self.biome_filter_var, width=50) self.biome_select_btn = Button(biome_filter_row, text='Select biome', command=self.select_biome) self.biome_filter_box.grid(row=0, column=1, padx=10, pady=3) self.biome_select_btn.grid(row=0, column=2, padx=10, pady=3) self.filter_biome_list() def filter_study_list(self): search_term = self.study_filter_var.get() self.study_listbox.delete(0, END) list_studies = [] # Append non-suggested biomes which pass filter for s in self.btc.studies: accessions = (s.primary_accession + ' ' + s.secondary_accession).lower() if search_term.lower() in accessions: list_studies.append(s.secondary_accession) # Insert into listbox and color items if needed for i, s in enumerate(list_studies): self.study_listbox.insert(END, s) def filter_biome_list(self): search_term = self.biome_filter_var.get() self.biome_listbox.delete(0, END) list_biomes = [] index_colors = {} # Insert suggested biomes at top of list IF they match the filter text, and store indeces to colour them later for b in self.suggested_biomes: s = '{} ({} match)'.format(b[0], "{0:.2f}".format(b[1])) is_match = search_term.lower() in b[0].lower( ) if not self.biome_match_case.get() else search_term in b[0] if is_match: i = len(list_biomes) list_biomes.append(s) b_color = fmt_font_intensity(b[1]) index_colors[i] = _from_rgb((255 - b_color, 0, b_color)) # Append non-suggested biomes which pass filter for b in self.biomes_list: is_match = search_term.lower() in b.lower( ) if not self.biome_match_case.get() else search_term in b if is_match and b not in self.suggested_biomes: list_biomes.append(b) # Insert into listbox and color items if needed for i, b in enumerate(list_biomes): self.biome_listbox.insert(END, b) if i in index_colors: self.biome_listbox.itemconfig(i, {'fg': index_colors[i]}) def init_study_list(self): self.study_listbox = Listbox(self.list_frame, width=75) self.update_study_list() self.study_listbox_lbl = Label( self.list_frame, text='List of studies that need tagging') self.study_listbox_lbl.grid(row=0, column=0, padx=10, pady=3) self.study_listbox.grid(row=1, column=0, padx=10, pady=3) study_filter_row = Frame(self.list_frame) study_filter_row.grid(row=2, column=0, padx=10, pady=3) study_filter_lbl = Label(study_filter_row, text='Search Study accession: ') study_filter_lbl.grid(row=0, column=0, padx=10, pady=3) self.study_filter_var = StringVar() self.study_filter_var.trace( "w", lambda name, index, mode: self.filter_study_list()) self.study_filter_box = Entry(study_filter_row, textvariable=self.study_filter_var, width=50) self.study_filter_box.grid(row=0, column=1, padx=10, pady=3) self.study_select_btn = Button(study_filter_row, text='Select study', command=self.select_study) self.study_listbox.bind('<Double-Button>', self.select_study) self.study_select_btn.grid(row=0, column=3, padx=10, pady=3) self.ena_view_btn = Button(self.list_frame, text='View study in ENA', command=self.view_in_ena) self.ena_view_btn.grid(row=3, column=0, padx=10, pady=3) def view_in_ena(self): webbrowser.open_new("https://www.ebi.ac.uk/ena/data/view/" + self.study_id_var.get().replace('Study id: ', '')) def init_study_display(self): self.study_id_var = StringVar(self) self.study_title_var = StringVar(self) self.study_desc_var = StringVar(self) self.study_sci_names_var = StringVar(self) self.study_id_disp = Label(self.details_frame, textvariable=self.study_id_var, wraplength=750) self.study_id_disp.grid(row=0, column=0, padx=10, pady=3) self.study_title_disp = Label(self.details_frame, textvariable=self.study_title_var, wraplength=750) self.study_title_disp.grid(row=1, column=0, padx=10, pady=3) self.study_desc_frame = Frame(self.details_frame) self.study_desc_frame.grid(row=2, column=0) self.study_desc_disp = tkscrolled.ScrolledText(self.study_desc_frame, height=20, width=140, wrap='word') self.study_desc_disp.insert(0.0, '\n' + self.study_desc_var.get()) self.study_desc_disp['font'] = ('consolas', '14') self.study_desc_disp.pack(expand=True, fill='both') self.study_scientific_names = Label( self.details_frame, textvariable=self.study_sci_names_var, wraplength=750) self.study_scientific_names.grid(row=3, column=0, padx=10, pady=3) def fetch_study(self, study_id): if study_id not in study_cache: study = self.btc.studies.filter(secondary_accession=study_id)[0] d = self.btc.fetch_info(study) study_cache[study_id] = d else: d = study_cache[study_id] print('Fetched ' + study_id) return d def select_study(self, *args, **kwargs): try: print('selecting') study_id = self.study_listbox.get( self.study_listbox.curselection()) d = self.fetch_study(study_id) self.study_id_var.set('Study id: {}'.format(study_id)) self.study_title_var.set('Title: {}'.format(d['title'])) text = 'Abstract: {}'.format(d['abstract']) self.study_desc_disp.delete(1.0, END) self.study_desc_disp.insert(1.0, '\n' + text) self.study_desc_disp.see(0.0) # self.study_sci_names_var.set('Environment variable names: {}'.format(", ".join(d['scientific_names']))) self.reset_confirmation_line() self.suggested_biomes = self.biome_classifier.pred_input( (d['title'] or '') + ' ' + (d['abstract'] or '')) self.filter_biome_list() except TclError as e: logging.error(e) pass def reset_study_display(self): self.study_id_var.set('Study id:') self.study_title_var.set('Title:') self.study_desc_var.set('Description:') self.study_sci_names_var.set('Environment variable names:') def init_biome_conf_display(self): self.biome_selection = StringVar(value='Selected biome: ') self.biome_selection_lbl = Label(self.details_frame, textvariable=self.biome_selection) self.biome_selection_lbl.grid(row=0, column=1, padx=10, pady=3) self.biome_tag_btn = Button(self.details_frame, text='Tag biome', command=self.tag_biome_handler) self.biome_tag_btn.grid(row=1, column=1, padx=10, pady=3) def select_biome(self, *args, **kwargs): try: biome = self.biome_listbox.get(self.biome_listbox.curselection()) self.biome_selection.set('Selected biome: {}'.format(biome)) logging.info('Selected biome: ' + biome) except TclError: print('err') pass def tag_biome_handler(self, *args, **kwargs): study_id = self.study_id_var.get().replace('Study id: ', '') biome = self.biome_selection.get().replace('Selected biome: ', '') logging.info('Tagging {} with biome {}'.format(study_id, biome)) lineage = re.sub('(\(\d\.\d+ match\))', '', biome) self.btc.tag_study(study_id, lineage) self.remove_study_from_list(study_id) self.reset_study_display() self.set_confirmation_line(study_id, biome) self.suggested_biomes = [] self.filter_biome_list() def remove_study_from_list(self, study_id): logging.info('Removing study {} from list.'.format(study_id)) self.btc.update_taggable_studies() self.update_study_list() def update_study_list(self): for i, s in enumerate( sorted([s.secondary_accession for s in self.btc.studies])): if self.study_listbox.get(i) != s: self.study_listbox.insert(i, s) self.study_listbox.delete(len(self.btc.studies), END) def init_confirmation_line(self): self.tagging_confirmation_var = StringVar(value='') self.tagging_confirmation_lbl = Label( self, textvariable=self.tagging_confirmation_var, fg="red") self.tagging_confirmation_lbl.grid(row=4, column=0, padx=10, pady=3) def set_confirmation_line(self, study_id, biome): s = 'Study {} was tagged with biome {}'.format(study_id, biome) self.tagging_confirmation_var.set(s) def reset_confirmation_line(self): self.tagging_confirmation_var.set('')
class MainScreen: def __init__(self, master, connection): #Reset Database if necessary Globals.ClearUserTables(connection) self.Config = configparser.ConfigParser() self.Config.read('config.ini') #Main Window self.Master = master self.Master.title("Hour Registration") #Database connection self.dbConnection = connection #Initialize Cache self.Cache = Cache.Cache(connection) #Initialize String Vars self.RecordTypeValue = StringVar() self.ProjectValue = StringVar() self.DescriptionValue = StringVar() self.LastLogon = StringVar() self.LastLogon.set(Globals.GetLastLogon()) #Designer self.DaysCombo = ttk.Combobox(master) self.DaysCombo.grid(row=0, column=0, sticky='NSEW', columnspan=3) self.RecordButton = Button(master, text="Start Recording", command=self.StartRecording) self.RecordButton.grid(row=1, column=0, sticky='NSEW') self.RecordIcon = PhotoImage(file=".\\Resources\\add.png") self.RecordButton.config(image=self.RecordIcon, width="32", height="32") self.DeleteRecordButton = Button(master, text="Delete Record", command=self.DeleteRecord) self.DeleteRecordButton.grid(row=1, column=1, sticky='NSEW') self.DeleteRecordIcon = PhotoImage(file=".\\Resources\\delete.png") self.DeleteRecordButton.config(image=self.DeleteRecordIcon, width="32", height="32") self.StopRecordButton = Button(master, text="Stop Recording", command=self.StopRecording) self.StopRecordButton.grid(row=1, column=2, sticky='NSEW') self.StopRecordIcon = PhotoImage(file=".\\Resources\\stop.png") self.StopRecordButton.config(image=self.StopRecordIcon, width="32", height="32") self.CopyToCodexButton = Button(master, text="Copy To Codex", command=self.CopyToCodex) self.CopyToCodexButton.grid(row=2, column=0, sticky='NSEW') self.CopyIcon = PhotoImage(file=".\\Resources\\copyCodex.png") self.CopyToCodexButton.config(image=self.CopyIcon, width="32", height="32") self.ExcelButton = Button(master, text="Export", command=self.ExportToExcel) self.ExcelButton.grid(row=2, column=1, sticky='NSEW') self.ExcelIcon = PhotoImage(file=".\\Resources\\excel.png") self.ExcelButton.config(image=self.ExcelIcon, width="32", height="32") self.ProjectButton = Button(master, text="Project", command=self.OpenProjectListForm) self.ProjectButton.grid(row=2, column=2, sticky='NSEW') self.ProjectIcon = PhotoImage(file=".\\Resources\\add_project.png") self.ProjectButton.config(image=self.ProjectIcon, width="32", height="32") self.CopyRecordButton = Button(master, text="CopyRecord", command=self.CopyRecord) self.CopyRecordButton.grid(row=3, column=0, sticky='NSEW') self.CopyRecordIcon = PhotoImage(file=".\\Resources\\copy.png") self.CopyRecordButton.config(image=self.CopyRecordIcon, width="32", height="32") self.OneNoteButton = Button(master, text="OneNote", command=self.OpenInOneNote) self.OneNoteButton.grid(row=3, column=1, sticky='NSEW') self.OneNoteIcon = PhotoImage(file=".\\Resources\\onenote.png") self.OneNoteButton.config(image=self.OneNoteIcon, width="32", height="32") self.AddTimeRecordButton = Button(master, text="AddTimeRecordButton", command=self.ShowNewEditForm) self.AddTimeRecordButton.grid(row=3, column=2, sticky="NSEW") self.AddTimeRecordIcon = PhotoImage( file=".\\Resources\\application_add.png") self.AddTimeRecordButton.config(image=self.AddTimeRecordIcon, width="32", height="32") self.BackupButton = Button(master, text="BackupButton", command=self.DatabaseBackup) self.BackupButton.grid(row=4, column=0, sticky="NSEW") self.BackupButtonIcon = PhotoImage(file=".\\Resources\\angel.png") self.BackupButton.config(image=self.BackupButtonIcon, width="32", height="32") self.RecordTypeButton = Button(master, text="RecordType", command=self.OpenRecordTypeListForm) self.RecordTypeButton.grid(row=4, column=1, sticky="NSEW") self.RecordTypeButtonIcon = PhotoImage( file=".\\Resources\\recordType.png") self.RecordTypeButton.config(image=self.RecordTypeButtonIcon, width="32", height="32") self.ExportToGraphsButton = Button(master, text="ExportToGraphs", command=self.ExportToGraph) self.ExportToGraphsButton.grid(row=4, column=2, sticky="NSEW") self.ExportToGraphsButtonIcon = PhotoImage( file=".\\Resources\\chart.png") self.ExportToGraphsButton.config(image=self.ExportToGraphsButtonIcon, width="32", height="32") self.ProjectsCombo = ttk.Combobox(master, textvariable=self.ProjectValue) self.ProjectsCombo.grid(row=0, column=3, columnspan=2, sticky='NSEW') self.RecordTypeCombo = ttk.Combobox(master, textvariable=self.RecordTypeValue) self.RecordTypeCombo.grid(row=1, column=3, columnspan=2, sticky='NSEW') self.DescriptionTextBox = Entry(master, textvariable=self.DescriptionValue) self.DescriptionTextBox.grid(row=2, column=3, columnspan=2, sticky='NSEW') self.RecordsListBox = Listbox(master, width=50) self.RecordsListBox.grid(row=3, column=3, rowspan=7, columnspan=1, sticky='NSEW') self.CommentListBox = Listbox(master, width=70) self.CommentListBox.grid(row=3, column=4, rowspan=7, columnspan=2, sticky='NSEW') self.CommentListBox.bindtags((self.CommentListBox, master, "all")) self.EventLogExplanationLabel = Label(master, text="Laatst aangemeld op: ") self.EventLogExplanationLabel.grid(row=0, column=5) self.EventLogLabel = Label(master, textvariable=self.LastLogon) self.EventLogLabel.grid(row=1, column=5) self.DaysCombo.bind("<<ComboboxSelected>>", self.DaysCombo_SelectedItemChanged) self.RecordsListBox.bind("<<ListboxSelect>>", self.RecordsListBox_SelectedItemChanged) self.RecordsListBox.bind('<Double-1>', lambda x: self.ShowEditForm()) #End Designer #Set Form Controls self.FillCombos() self.SetButtonsEnabled() self.Queue = queue.Queue(10) self.KillEvent = threading.Event() self.ControllerThread = threading.Thread(target=self.ctrl, args=(self.Queue, self.KillEvent)) self.ControllerThread.start() Logger.LogInfo(self.ControllerThread.getName() + ' started.') self.CheckForUpdatesFromController() def ctrl(self, queue, killEvent): dac = DAController.DAController(queue, killEvent) dac.Listen() def DatabaseBackup(self): source = self.Config['DEFAULT']['databasename'] destination = self.Config['DEFAULT'][ 'databasebackuplocation'] + '{}.db'.format( time.strftime('%Y%m%d%H%M')) copyfile(source, destination) messagebox.showinfo('Backup', 'Database backup made') def CheckForUpdatesFromController(self): if not self.Queue.empty(): queue = self.Queue.get() blPr = BLProject.BLProject(self.dbConnection) project = blPr.GetByButton(queue) if project is not None: print(project.Description) recordType = 1 blTr = BLTimeRecord.BLTimeRecord(self.dbConnection) for record in self.Cache.TimeRecords: if record.StatusID == TimeRecordStatusEnum.TimeRecordStatusEnum.Gestart.value: record.StatusID = TimeRecordStatusEnum.TimeRecordStatusEnum.Gestopt.value record.EndHour = Globals.GetCurrentTime() blTr.Update(record) timeRecord = TimeRecord.TimeRecord( None, Globals.GetCurrentTime(), None, project.ID, recordType, 'Automatically generated', TimeRecordStatusEnum.TimeRecordStatusEnum.Gestart.value, 0, None, None) valid = TimeRecordValidation.TimeRecordValidation() validationMessage = valid.ValidateOnCreation(timeRecord) if not len(validationMessage) == 0: errorMessage = '' for i in validationMessage: errorMessage = errorMessage + i + '\n' messagebox.showerror('Error', errorMessage) else: index = self.DaysCombo.current() blTr.Create(timeRecord) self.Cache.RefreshAllStaticData() self.FillCombos() if index == -1: index = 0 self.DaysCombo.current(index) self.RefreshTimeRecords() self.Master.after(500, self.CheckForUpdatesFromController) def OpenInOneNote(self): sel = self.RecordsListBox.curselection()[0] timeRecordView = self.Cache.TimeRecordViews[sel] os.system("start " + timeRecordView.OneNoteLink) def CopyRecord(self): blTr = BLTimeRecord.BLTimeRecord(self.dbConnection) sel = self.RecordsListBox.curselection()[0] timeRecordView = self.Cache.TimeRecordViews[sel] timeRecord = blTr.GetById(timeRecordView.ID) blTr.CopyTimeRecord(timeRecord) self.Refresh() def Refresh(self): index = self.DaysCombo.current() self.DaysCombo.current(0) self.Cache.RefreshAllStaticData() self.FillCombos() self.DaysCombo.current(index) self.RefreshTimeRecords() self.SetButtonsEnabled() def RecordsListBox_SelectedItemChanged(self, eventObject): self.SetButtonsEnabled() def DaysCombo_SelectedItemChanged(self, eventObject): self.RefreshTimeRecords() self.SetButtonsEnabled() def RefreshTimeRecords(self): index = self.DaysCombo.current() if not index == -1: date = self.Cache.DayViews[index].Date self.Cache.RefreshTimeRecordsForDate(date) self.FillTimeRecords(self.Cache.TimeRecordViews) else: self.RecordsListBox.delete(0, END) self.CommentListBox.delete(0, END) def Show(self): self.Master.mainloop() def FillCombos(self): self.FillProjectCombo() self.FillRecordTypeCombo() self.FillDays() def FillProjectCombo(self): self.ProjectsCombo['value'] = self.Cache.ActiveProjects def FillRecordTypeCombo(self): self.RecordTypeCombo['value'] = self.Cache.RecordTypes def FillDays(self): self.DaysCombo['value'] = self.Cache.DayViews def FillTimeRecords(self, timeRecordViews): self.RecordsListBox.delete(0, END) self.CommentListBox.delete(0, END) for item in timeRecordViews: self.RecordsListBox.insert(END, item) self.CommentListBox.insert(END, item.Description) for i in range(0, self.RecordsListBox.size()): item = timeRecordViews[i] itemStatus = item.Status if itemStatus == 'Gestart': self.RecordsListBox.itemconfig(i, {'bg': 'red'}) elif itemStatus == 'Gestopt': self.RecordsListBox.itemconfig(i, {'bg': 'green'}) elif itemStatus == 'Gekopieerd': self.RecordsListBox.itemconfig(i, {'bg': 'orange'}) def StartRecording(self): recordIndex = self.RecordTypeCombo.current() projectIndex = self.ProjectsCombo.current() if recordIndex == -1: recordType = '' else: recordType = self.Cache.RecordTypes[recordIndex].ID if projectIndex == -1: project = None else: project = self.Cache.ActiveProjects[projectIndex].ID timeRecord = TimeRecord.TimeRecord( None, Globals.GetCurrentTime(), None, project, recordType, self.DescriptionValue.get(), TimeRecordStatusEnum.TimeRecordStatusEnum.Gestart.value, 0, None, None) valid = TimeRecordValidation.TimeRecordValidation() validationMessage = valid.ValidateOnCreation(timeRecord) if not len(validationMessage) == 0: errorMessage = '' for i in validationMessage: errorMessage = errorMessage + i + '\n' messagebox.showerror('Error', errorMessage) else: index = self.DaysCombo.current() blTr = BLTimeRecord.BLTimeRecord(self.dbConnection) blTr.Create(timeRecord) self.Cache.RefreshAllStaticData() self.FillCombos() if index == -1: index = 0 self.DaysCombo.current(index) self.RefreshTimeRecords() def StopRecording(self): blTr = BLTimeRecord.BLTimeRecord(self.dbConnection) sel = self.RecordsListBox.curselection()[0] timeRecordView = self.Cache.TimeRecordViews[sel] timeRecord = blTr.GetById(timeRecordView.ID) timeRecord.EndHour = Globals.GetCurrentTime() timeRecord.StatusID = TimeRecordStatusEnum.TimeRecordStatusEnum.Gestopt.value blTr.Update(timeRecord) index = self.DaysCombo.current() self.DaysCombo.current(0) self.Cache.RefreshAllStaticData() self.FillCombos() self.DaysCombo.current(index) self.RefreshTimeRecords() self.SetButtonsEnabled() def CopyToCodex(self): self.Master.clipboard_clear() index = self.DaysCombo.current() date = self.Cache.DayViews[index].Date self.Master.clipboard_append( Globals.CopyToCodex(self.dbConnection, date)) self.RefreshTimeRecords() def ShowEditForm(self): timeRecordView = self.Cache.TimeRecordViews[ self.RecordsListBox.curselection()[0]] edit = TimeRecordEditForm(self.dbConnection, timeRecordView, self.Cache) edit.Show() index = self.DaysCombo.current() self.DaysCombo.current(0) self.Cache.RefreshAllStaticData() self.FillCombos() self.DaysCombo.current(index) self.RefreshTimeRecords() edit.Master.destroy() def ShowNewEditForm(self): tr = TimeRecordView.TimeRecordView(None, None, None, None, None, None, None, None, None, None, None) index = self.DaysCombo.current() tr.Date = self.Cache.DayViews[index].Date edit = TimeRecordEditForm(self.dbConnection, tr, self.Cache) edit.Show() index = self.DaysCombo.current() self.DaysCombo.current(0) self.Cache.RefreshAllStaticData() self.FillCombos() self.DaysCombo.current(index) self.RefreshTimeRecords() edit.Master.destroy() def OpenProjectListForm(self): projectListForm = ProjectListForm(self.Cache, self.dbConnection) projectListForm.Show() self.Cache.RefreshAllStaticData() self.FillCombos() projectListForm.Master.destroy() def OpenRecordTypeListForm(self): recordTypeListForm = RecordTypeListForm(self.Cache, self.dbConnection) recordTypeListForm.Show() self.Cache.RefreshAllStaticData() self.FillCombos() recordTypeListForm.Master.destroy() def ExportToExcel(self): excel = ExportToExcelForm(self.dbConnection) excel.Show() excel.Master.destroy() def ExportToGraph(self): graph = ExportToGraphsForm(self.dbConnection, self.Cache) graph.Show() graph.Master.destroy() def DeleteRecord(self): bl = BLTimeRecord.BLTimeRecord(self.dbConnection) indexRecordsListBox = self.RecordsListBox.curselection()[0] record = self.Cache.TimeRecordViews[indexRecordsListBox] bl.DeleteByID(record.ID) index = self.DaysCombo.current() self.Cache.RefreshAllStaticData() self.FillCombos() #Hier schiet nog 1 record over; het is nog niet verwijderd uit Cache op dit moment if len(self.Cache.TimeRecordViews) == 1: self.DaysCombo.set('') else: self.DaysCombo.current(index) self.RefreshTimeRecords() self.SetButtonsEnabled() def SetButtonsEnabled(self): enableStop = True enableCopyToCodex = True enableDelete = True enableCopyRecord = True enableOpenOneNote = True indexDaysCombo = self.DaysCombo.current() indexRecordsListBox = self.RecordsListBox.curselection() current = Globals.GetCurrentDay() if indexDaysCombo == -1: enableStop = False enableCopyToCodex = False else: date = self.Cache.DayViews[indexDaysCombo].Date if not current == date: enableStop = False bl = BLTimeRecord.BLTimeRecord(self.dbConnection) records = bl.GetAllForDate(date) for record in records: if record.StatusID == TimeRecordStatusEnum.TimeRecordStatusEnum.Gestart.value: enableCopyToCodex = False if len(indexRecordsListBox) == 0: enableStop = False enableDelete = False enableCopyRecord = False enableOpenOneNote = False else: trView = self.Cache.TimeRecordViews[indexRecordsListBox[0]] if trView.OneNoteLink == 'None' or trView.OneNoteLink == "": enableOpenOneNote = False self.SetButton(enableStop, self.StopRecordButton) self.SetButton(enableCopyToCodex, self.CopyToCodexButton) self.SetButton(enableDelete, self.DeleteRecordButton) self.SetButton(enableCopyRecord, self.CopyRecordButton) self.SetButton(enableOpenOneNote, self.OneNoteButton) def SetButton(self, enabled, button): if enabled: button.config(state=NORMAL) else: button.config(state=DISABLED)
class OutletSelection(Frame): def __init__(self, root): Frame.__init__(self, root) self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) ## Search bar search = Frame(self) search.grid(row=0, column=0, columnspan=2, padx=8) self.title = Label(search, text='Location: ').grid(row=0, column=0) self.outletVariable = StringVar(self) self.outletFilter = Entry(search, textvariable=self.outletVariable) self.outletFilter.grid(row=0, column=1, pady=10) self.outletFilter.bind('<Return>', lambda e: self._search_callback()) self.searchButton = Button(search, text="Search", command=self._search_callback) self.searchButton.grid(row=0, column=2, padx=(8, 0)) ## Results list # Listbox with search results self.outlets = Listbox(self, height=20, width=30) self.outlets.grid(row=1, column=0, sticky='nsew') self.outlets.bind('<<ListboxSelect>>', self._select_callback) # Y scrollbar self.yscrollbar = Scrollbar(self, orient="vertical") self.yscrollbar.config(command=self.outlets.yview) self.yscrollbar.grid(row=1, column=1, sticky="ns") self.outlets.config(yscrollcommand=self.yscrollbar.set) # X scrollbar self.xscrollbar = Scrollbar(self, orient="horizontal") self.xscrollbar.config(command=self.outlets.xview) self.xscrollbar.grid(row=2, column=0, sticky="ew") self.outlets.config(xscrollcommand=self.xscrollbar.set) self.locations = [] ## Option to filter invalid locations toggle = Frame(self) toggle.grid(row=3, column=0, sticky='w') Label(toggle, text='Hide invalid locations').grid(row=0, column=0) self.filterInvalid = IntVar(self) self.filterInvalid.set(0) Checkbutton(toggle, variable=self.filterInvalid, command=self._search_callback ).grid(row=0, column=1, sticky='w') self.refresh() def refresh(self): '''Refresh the search content''' self.outletVariable.set('') self._search_callback() def _select_callback(self, event): '''Select the outlet to be used for creating a projection''' if len(self.locations) == 0: return widget = event.widget selection = widget.curselection() location = self.locations[selection[0]] pInputs = gb.main_window.getComponent(GUI.projectionInputs) pInputs.setOutlet(location.get_abbreviation()) def _search_callback(self): '''Get and display the relevant search results''' self.outlets.delete(0, END) t = str(self.outletVariable.get()) self.locations = location.search_locations(t) if self.filterInvalid.get(): rm = [] for loc in self.locations: if not loc.get_valid(): rm.append(loc) for loc in rm: self.locations.remove(loc) for i in range(len(self.locations)): loc = self.locations[i] self.outlets.insert(END, loc) if not loc.get_valid(): self.outlets.itemconfig(i, selectbackground='grey80', selectforeground='grey', fg='grey80')
class LabelTool(): """Simple YOLO format annotation tool based on tkinter""" def __init__(self, master): # set up the main frame self.cur_cls_id = -1 self.parent = master self.parent.title("Yolo Annotation Tool") self.frame = Frame(self.parent) self.frame.pack(fill=BOTH, expand=1) self.parent.resizable(width=False, height=False) # initialise global state self.imageDir = '' self.imageList = [] self.egDir = '' self.egList = [] self.outDir = '' self.cur = 0 self.total = 0 self.category = 0 self.imagename = '' self.labelfilename = '' self.tkimg = None self.img = None self.classes = [] # initialise mouse state self.STATE = {} self.STATE['click'] = 0 self.STATE['x'], self.STATE['y'] = 0, 0 # reference to bbox self.bboxIdList = [] self.bboxId = None self.bboxList = [] self.bboxListCls = [] self.hl = None self.vl = None # ----------------- GUI thing --------------------- # dir entry & load self.label = Label(self.frame, text="Image Dir:") self.label.grid(row=0, column=0, sticky=E) self.entry = Entry(self.frame) # self.entry.focus_set() #self.entry.bind('<Return>', self.loadEntry) self.entry.grid(row=0, column=1, sticky=W + E) self.ldBtn = Button(self.frame, text="Load", command=self.load_dir_dialog) self.ldBtn.grid(row=0, column=2, sticky=W + E) # main panel for labelling self.mainPanel = Canvas(self.frame, cursor='tcross') self.mainPanel.bind("<Button-1>", self.mouse_click) self.mainPanel.bind("<Motion>", self.mouse_move) self.mainPanel.bind("<Configure>", self.resize_image_event) self.parent.bind( "<Escape>", self.cancel_bbox) # press <Espace> to cancel current bbox self.parent.bind("s", self.cancel_bbox) self.parent.bind("<Left>", self.previous_image) # press 'a' to go backforward self.parent.bind("<Right>", self.next_image) # press 'd' to go forward self.mainPanel.grid(row=1, column=1, rowspan=4, sticky=W + N) # showing bbox info & delete bbox self.tkvar = StringVar(self.parent) self.cur_cls_id = 0 self.popupMenu = OptionMenu(self.frame, self.tkvar, "None") self.popupMenu.grid(row=1, column=2, sticky=E + S) self.chooselbl = Label(self.frame, text='Choose Class:') self.chooselbl.grid(row=1, column=2, sticky=W + S) self.lb1 = Label(self.frame, text='Bounding boxes:') self.lb1.grid(row=2, column=2, sticky=W + N) self.listbox = Listbox(self.frame, width=30, height=12) self.listbox.grid(row=3, column=2, sticky=N) self.btnDel = Button(self.frame, text='Delete', command=self.delete_bbox) self.btnDel.grid(row=4, column=2, sticky=W + E + N) self.btnClear = Button(self.frame, text='ClearAll', command=self.clear_all_bbox) self.btnClear.grid(row=5, column=2, sticky=W + E + N) # control panel for image navigation self.ctrPanel = Frame(self.frame) self.ctrPanel.grid(row=6, column=1, columnspan=2, sticky=W + E) self.prevBtn = Button(self.ctrPanel, text='<< Prev', width=10, command=self.previous_image) self.prevBtn.pack(side=LEFT, padx=5, pady=3) self.nextBtn = Button(self.ctrPanel, text='Next >>', width=10, command=self.next_image) self.nextBtn.pack(side=LEFT, padx=5, pady=3) self.progLabel = Label(self.ctrPanel, text="Progress: / ") self.progLabel.pack(side=LEFT, padx=5) self.tmpLabel = Label(self.ctrPanel, text="Go to Image No.") self.tmpLabel.pack(side=LEFT, padx=5) self.idxEntry = Entry(self.ctrPanel, width=5) self.idxEntry.pack(side=LEFT) self.goBtn = Button(self.ctrPanel, text='Go', command=self.goto_image) self.goBtn.pack(side=LEFT) # example pannel for illustration self.egPanel = Frame(self.frame, border=10) self.egPanel.grid(row=1, column=0, rowspan=5, sticky=N) self.tmpLabel2 = Label(self.egPanel, text="Examples:") self.tmpLabel2.pack(side=TOP, pady=5) self.egLabels = [] for _ in range(3): self.egLabels.append(Label(self.egPanel)) self.egLabels[-1].pack(side=TOP) # display mouse position self.disp = Label(self.ctrPanel, text='') self.disp.pack(side=RIGHT) self.frame.columnconfigure(1, weight=1) self.frame.rowconfigure(4, weight=1) def load_dir_dialog(self): """Open a directory browsing dialog to select a dataset within ./Images to annotate""" dirpath = filedialog.askdirectory() if dirpath: # Make dirpath relative to images directory subdir_path = Path(dirpath) if IMAGES_ROOT not in subdir_path.parents: tkMessageBox.showerror( "Error!", message="The directory should be within {0}".format( IMAGES_ROOT)) return self.entry.delete(0, END) self.entry.insert(0, str(subdir_path.relative_to(IMAGES_ROOT))) self.load_dir() def load_classes(self): """Load dataset specific classes, if do not exist fallback to defaults""" try: print(IMAGES_ROOT) print(self.category) print(CLASSES_FILENAME) classes_fullpath = os.path.join(IMAGES_ROOT, self.category, CLASSES_FILENAME) if os.path.exists(classes_fullpath): print("Loading dataset specific classes file {0}".format( classes_fullpath)) else: print("No dataset classes file {0}, loading default".format( classes_fullpath)) classes_fullpath = CLASSES_FILENAME with open(classes_fullpath, 'r') as cls: classes = cls.readlines() self.classes = [cls.strip() for cls in classes] menu = self.popupMenu["menu"] menu.delete(0, "end") for cls in self.classes: menu.add_command(label=cls, command=lambda v=cls: self.change_dropdown(v)) self.tkvar.set(self.classes[0]) except IOError: print("[ERROR] Please create {0} and put your all classes".format( classes_fullpath)) sys.exit(1) assert len(self.classes) <= len(COLOURS) def load_dir(self, dbg=False): """Load annotation dataset in selected sub directory""" if not dbg: try: subdir = self.entry.get() self.parent.focus() self.category = subdir except ValueError: tkMessageBox.showerror("Error!", message="The folder should be numbers") return if not os.path.isdir(os.path.join(IMAGES_ROOT, self.category)): tkMessageBox.showerror("Error!", message="The specified dir doesn't exist!") return # get image list self.imageDir = os.path.join(IMAGES_ROOT, self.category) self.imageList = [ file for imageType in SUPPORTED_IMAGE_TYPES for file in glob.glob(os.path.join(self.imageDir, imageType)) ] if len(self.imageList) == 0: tkMessageBox.showerror( "Error!", message="No {0} images found in the specified dir!".format( SUPPORTED_IMAGE_TYPES)) return # default to the 1st image in the collection self.cur = 1 self.total = len(self.imageList) self.load_classes() # set up output dir if not os.path.exists('./Labels'): os.mkdir('./Labels') self.outDir = os.path.join(r'./Labels', '%s' % (self.category)) if not os.path.exists(self.outDir): os.mkdir(self.outDir) self.load_image() print('%d images loaded from %s' % (self.total, self.category)) def load_image(self): """Load the current image into the canvas and render any existing labels""" # load image imagepath = self.imageList[self.cur - 1] self.img = PImage.open(imagepath) self.tkimg = ImageTk.PhotoImage(self.img) self.mainPanel.config(width=max(self.tkimg.width(), 400), height=max(self.tkimg.height(), 400)) self.mainPanel.create_image(0, 0, image=self.tkimg, anchor=NW, tags="IMG") self.progLabel.config(text="%04d/%04d" % (self.cur, self.total)) self.mainPanel.update() self.resize_image(self.mainPanel.winfo_width(), self.mainPanel.winfo_height()) # load labels self.clear_all_bbox() # self.imagename = os.path.split(imagepath)[-1].split('.')[0] self.imagename = os.path.splitext(os.path.basename(imagepath))[0] labelname = self.imagename + '.txt' self.labelfilename = os.path.join(self.outDir, labelname) if os.path.exists(self.labelfilename): with open(self.labelfilename) as label_file: for line in label_file: yolo_data = line.strip().split() tl_br_bbox = yolo_bbox_to_tl_br_bbox( [float(data) for data in yolo_data[1:]]) self.bboxList.append(tl_br_bbox) self.bboxListCls.append(yolo_data[0]) abs_bbox = rel_bbox_to_abs_bbox( tl_br_bbox, (self.tkimg.width(), self.tkimg.height())) tmpId = self.mainPanel.create_rectangle( abs_bbox[0], abs_bbox[1], abs_bbox[2], abs_bbox[3], width=2, outline=COLOURS[int(yolo_data[0])]) self.bboxIdList.append(tmpId) self.listbox.insert( END, '(%.2f, %.2f) -> (%.2f, %.2f) -> (%s)' % (tl_br_bbox[0], tl_br_bbox[1], tl_br_bbox[2], tl_br_bbox[3], self.classes[int(yolo_data[0])])) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg=COLOURS[int(yolo_data[0])]) def resize_image(self, width, height): """Resize the current image to fit the canvas""" if self.tkimg: size = (width, height) resized = self.img.resize(size, PImage.ANTIALIAS) self.tkimg = ImageTk.PhotoImage(resized) self.mainPanel.delete("IMG") self.mainPanel.create_image(0, 0, image=self.tkimg, anchor=NW, tags="IMG") self.bboxIdList.clear() for tl_br_bbox, bboxcls in zip(self.bboxList, self.bboxListCls): abs_bbox = rel_bbox_to_abs_bbox( tl_br_bbox, (self.tkimg.width(), self.tkimg.height())) tmpId = self.mainPanel.create_rectangle( abs_bbox[0], abs_bbox[1], abs_bbox[2], abs_bbox[3], width=2, outline=COLOURS[int(bboxcls)]) self.bboxIdList.append(tmpId) def resize_image_event(self, event): """Resize the current image to fit the canvas""" self.resize_image(event.width, event.height) def save_image_labels(self): """Save labels for current image to disk""" with open(self.labelfilename, 'w') as f: for tl_br_bbox, bboxcls in zip(self.bboxList, self.bboxListCls): yolo_bbox = tl_br_bbox_to_yolo_bbox(tl_br_bbox) f.write( str(bboxcls) + " " + " ".join([str(a) for a in yolo_bbox]) + '\n') print('Image No. %d saved' % (self.cur)) def mouse_click(self, event): """On mouse click event finalise and save bounding box""" if self.tkimg: if self.STATE['click'] == 0: self.STATE['x'], self.STATE['y'] = event.x, event.y else: tl_x = min(self.STATE['x'], event.x) / self.tkimg.width() br_x = max(self.STATE['x'], event.x) / self.tkimg.width() tl_y = min(self.STATE['y'], event.y) / self.tkimg.height() br_y = max(self.STATE['y'], event.y) / self.tkimg.height() self.bboxList.append((tl_x, tl_y, br_x, br_y)) self.bboxListCls.append(self.cur_cls_id) self.bboxIdList.append(self.bboxId) self.bboxId = None self.listbox.insert( END, '(%.2f, %.2f) -> (%.2f, %.2f) -> (%s)' % (tl_x, tl_y, br_x, br_y, self.classes[self.cur_cls_id])) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg=COLOURS[self.cur_cls_id]) self.STATE['click'] = 1 - self.STATE['click'] def mouse_move(self, event): """On mouse move event continually update shape of bounding box""" if self.tkimg: self.disp.config( text='x: %.2f, y: %.2f' % (event.x / self.tkimg.width(), event.y / self.tkimg.height())) if self.tkimg: if self.hl: self.mainPanel.delete(self.hl) self.hl = self.mainPanel.create_line(0, event.y, self.tkimg.width(), event.y, width=2) if self.vl: self.mainPanel.delete(self.vl) self.vl = self.mainPanel.create_line(event.x, 0, event.x, self.tkimg.height(), width=2) if self.STATE['click'] == 1: if self.bboxId: self.mainPanel.delete(self.bboxId) self.bboxId = self.mainPanel.create_rectangle( self.STATE['x'], self.STATE['y'], event.x, event.y, width=2, outline=COLOURS[self.cur_cls_id]) def cancel_bbox(self, event): """On cancel bbox event (HIT ESCAPE DURING SELECTION) reset active selection bounding box""" if self.STATE['click'] == 1: if self.bboxId: self.mainPanel.delete(self.bboxId) self.bboxId = None self.STATE['click'] = 0 def delete_bbox(self): """On delete bounding box event (DELETE BUTTON CLICK), delete selected bounding box""" sel = self.listbox.curselection() if len(sel) != 1: return idx = int(sel[0]) self.mainPanel.delete(self.bboxIdList[idx]) self.bboxIdList.pop(idx) self.bboxList.pop(idx) self.bboxListCls.pop(idx) self.listbox.delete(idx) def clear_all_bbox(self): """On clear all bounding box event (CLEAR ALL BUTTON CLICK), remove ALL bounding boxes""" for idx in range(len(self.bboxIdList)): self.mainPanel.delete(self.bboxIdList[idx]) self.listbox.delete(0, len(self.bboxList)) self.bboxIdList = [] self.bboxList = [] self.bboxListCls = [] def previous_image(self, event=None): """Load previous image in annotation queue""" self.save_image_labels() if self.cur > 1: self.cur -= 1 self.load_image() else: tkMessageBox.showerror("Information!", message="This is first image") def next_image(self, event=None): """Load next image in annotation queue""" self.save_image_labels() if self.cur < self.total: self.cur += 1 self.load_image() else: tkMessageBox.showerror("Information!", message="All images annotated") def goto_image(self): """Go to specific image in annotation queue""" idx = int(self.idxEntry.get()) if 1 <= idx <= self.total: self.save_image_labels() self.cur = idx self.load_image() def change_dropdown(self, cls): """Update currently selected annotation class from dropdown selection""" self.tkvar.set(cls) self.cur_cls_id = self.classes.index(cls)
class AddProducts: def __init__(self, service, top_level): self.service = service self.top_level = top_level # Gui elements self.name_entry = None self.shops_combo = None self.category_combo = None self.search_button = None self.listbox = None # Last searched products list self.products_found = None # List self.products_found_positions = None # Dictionary self.existing = None # Set self.init_gui() def init_gui(self): self.top_level.geometry("600x750") self.name_entry = Entry(self.top_level) self.name_entry.grid(row=0, column=0, columnspan=2, sticky=W + E) self.name_entry.insert(0, 'Product name') self.name_entry.bind("<FocusIn>", lambda args: self.name_entry.delete('0', 'end')) # shop_choices = ['Emag', 'Altex', 'Media Galaxy'] shop_choices = ['Emag'] self.shops_combo = Combobox(self.top_level, values=shop_choices) self.shops_combo.grid(row=1, column=0, sticky=W + E) self.shops_combo.current(0) # Make it configurable from config file category_choices = [ 'Laptops', 'Phones', 'Tablets', 'Tvs', 'Portable speakers', 'Headphones', 'Consoles' ] self.category_combo = Combobox(self.top_level, values=category_choices) self.category_combo.grid(row=1, column=1, sticky=W + E) self.category_combo.current(0) # Search bu self.search_button = Button(self.top_level, text='Search', command=self.on_search_event) self.search_button.grid(row=2, column=0, columnspan=2, sticky=W + E + S + N) # Frame to encapsulate the listbox and scrollbar frame = Frame(self.top_level, bd=2, relief=SUNKEN) scrollbar = Scrollbar(frame) scrollbar.pack(side=RIGHT, fill=Y) self.listbox = Listbox(frame, bd=0, yscrollcommand=scrollbar.set) self.listbox.bind('<Double-Button-1>', self.on_product_inspect) self.listbox.bind('<Return>', self.on_product_inspect) self.listbox.pack(fill=BOTH, expand=1) frame.grid(row=3, column=0, columnspan=2, sticky=W + E + N + S) scrollbar.config(command=self.listbox.yview) for x in range(3): Grid.rowconfigure(self.top_level, x, pad=10) Grid.rowconfigure(self.top_level, 3, weight=1) for x in range(2): Grid.columnconfigure(self.top_level, x, weight=1) def on_product_inspect(self, event): w = event.widget index = int(w.curselection()[0]) new_win = Toplevel(self.top_level) ex = ExamineNewProduct(self.service, self.products_found[index], new_win) self.service.add_observer(ex, Events.NEW_P) new_win.protocol("WM_DELETE_WINDOW", lambda: self.destroy_examination(ex, new_win)) def destroy_examination(self, ex, new_win): self.service.remove_observer(ex, Events.NEW_P) new_win.destroy() def on_search_event(self): self.products_found = self.service.search_products( self.name_entry.get(), self.category_combo.get(), 'Emag') if self.products_found is None: return self.listbox.delete(0, 'end') self.products_found_positions = {} self.existing = set() for index, product in enumerate(self.products_found): self.listbox.insert(END, product.title) self.products_found_positions[product.id] = index if self.service.product_already_exists(product.id): self.listbox.itemconfig(index, foreground='orange') self.existing.add(product.id) def update(self, data, event): if event == Events.NEW_P: id = data if self.products_found_positions is not None and id in self.products_found_positions: index = self.products_found_positions[id] self.listbox.itemconfig(index, foreground='orange')
class ListboxVidget(Vidget, Eventor): """ ListboxVidget contains a Listbox widget. It adds the following abilities: - Store items of any type, unlike Listbox widget that only stores texts. - Remember selected item even if the listbox widget lost focus. - Notify pre-change and post-change events. """ # Error raised when trying to change the listbox while a change is going on class CircularCallError(ValueError): pass # Error raised when trying to change the listbox while it is disabled class DisabledError(ValueError): pass # Event notified when the listbox's items are to be changed ITEMS_CHANGE_SOON = 'ITEMS_CHANGE_SOON' # Event notified when the listbox's items are changed ITEMS_CHANGE_DONE = 'ITEMS_CHANGE_DONE' # Event notified when the listbox's active item is to be changed ITEMCUR_CHANGE_SOON = 'ITEMCUR_CHANGE_SOON' # Event notified when the listbox's active item is changed ITEMCUR_CHANGE_DONE = 'ITEMCUR_CHANGE_DONE' # Events list EVENTS = ( ITEMS_CHANGE_SOON, ITEMS_CHANGE_DONE, ITEMCUR_CHANGE_SOON, ITEMCUR_CHANGE_DONE, ) def __init__( self, items=None, item_to_text=None, normal_bg='', normal_fg='', active_bg='sky blue', active_fg='white', selected_bg='steel blue', selected_fg='white', master=None, ): """ Initialize object. @param items: Items list. @param item_to_text: Item-to-text function. Default is `str`. @param normal_bg: Unselected item background color. @param normal_fg: Unselected item foreground color. @param active_bg: Active item background color. `Active` means the item is selected (in general meaning) but the listbox has no focus. @param active_fg: Active item foreground color. `Active` means the item is selected (in general meaning) but the listbox has no focus. @param selected_bg: Selected item background color. `Selected` means the item is selected (in general meaning) and the listbox has focus. @param selected_fg: Selected item foreground color. `Selected` means the item is selected (in general meaning) and the listbox has focus. @param master: Master widget. @return: None. """ # Initialize Vidget. # Create main frame widget. Vidget.__init__( self, master=master, ) # Initialize Eventor Eventor.__init__(self) # If items list is given if items is not None: # If items list is not list if not isinstance(items, list): # Raise error raise TypeError(items) # If items list is list. # If items list is not given, or items list is given and is list # Items list self._items = items if items is not None else [] # Item-to-text function. Default is `str`. self._item_to_text = item_to_text if item_to_text is not None else str # Unselected item background color self._normal_fg = normal_fg # Unselected item foreground color self._normal_bg = normal_bg # Active item background color self._active_fg = active_fg # Active item foreground color self._active_bg = active_bg # Selected item background color self._selected_fg = selected_fg # Selected item foreground color self._selected_bg = selected_bg # Whether the listbox is changing self._is_changing = False # Active index. `-1` means void, i.e. no item is active. self._indexcur = -1 # Whether active index is being reset to same value self._is_resetting = False # Create listbox widget self._listbox = Listbox( master=self.widget(), relief='groove', activestyle='none', highlightthickness=0, # Active index cache only supports single-selection mode for now. # See 2N6OR. selectmode='single', ) # Set the listbox widget as config target self.config_target_set(self._listbox) # Create x-axis scrollbar self._scrollbar_xview = _HiddenScrollbar( self.widget(), orient=HORIZONTAL, ) # Create y-axis scrollbar self._scrollbar_yview = _HiddenScrollbar( self.widget(), orient=VERTICAL, ) # Mount scrollbars self._listbox.config(xscrollcommand=self._scrollbar_xview.set) self._listbox.config(yscrollcommand=self._scrollbar_yview.set) self._scrollbar_xview.config(command=self._listbox.xview) self._scrollbar_yview.config(command=self._listbox.yview) # Bind single-click event handler self._listbox.bind('<Button-1>', self._on_single_click) # Bind double-click event handler self._listbox.bind('<Double-Button-1>', self._on_double_click) # Update listbox widget self._listbox_widget_update(keep_active=False) # Update widget self._widget_update() def _widget_update(self): """ Update widget. @return: None. """ # Row 0 for listbox and y-axis scrollbar self.widget().rowconfigure(0, weight=1) # Row 1 for x-axis scrollbar self.widget().rowconfigure(1, weight=0) # Column 0 for listbox and x-axis scrollbar self.widget().columnconfigure(0, weight=1) # Column 1 for y-axis scrollbar self.widget().columnconfigure(1, weight=0) # Lay out listbox self._listbox.grid(row=0, column=0, sticky='NSEW') # Lay out x-axis scrollbar self._scrollbar_xview.grid(row=1, column=0, sticky='EW') # Lay out y-axis scrollbar self._scrollbar_yview.grid(row=0, column=1, sticky='NS') def is_enabled(self): """ Test whether the listbox is enabled. @return: Boolean. """ # Return whether the listbox is enabled return self._listbox.config('state')[4] != DISABLED def is_changing(self): """ Test whether the listbox is changing. @return: Boolean. """ # Return whether the listbox is changing return self._is_changing def is_resetting(self): """ Test whether the listbox is setting active index to the same value. @return: Boolean. """ # Return whether the listbox is setting active index to the same value return self._is_resetting def size(self): """ Get number of items. @return: Number of items. """ # Return number of items return len(self._items) def items(self): """ Get items list. Notice do not change the list outside. @return: Items list. """ # Return items list return self._items def items_set( self, items, notify=True, keep_active=False, ): """ Set items list. Notice do not change the list outside. @param items: Items list. @param notify: Whether notify pre-change and post-change events. @param keep_active: Whether keep or clear active index. @return: None. """ # If the items is not list if not isinstance(items, list): # Raise error raise TypeError(items) # If the items is list. # If the listbox is disabled if not self.is_enabled(): # Raise error raise ListboxVidget.DisabledError() # If the listbox is not disabled. # If the listbox is changing if self._is_changing: # Raise error raise ListboxVidget.CircularCallError() # If the listbox is not changing. # Set changing flag on self._is_changing = True # If notify events if notify: # Notify pre-change event self.handler_notify(self.ITEMS_CHANGE_SOON) # Store the new items self._items = items # Update listbox widget self._listbox_widget_update( keep_active=keep_active ) # If notify events if notify: # Notify post-change event self.handler_notify(self.ITEMS_CHANGE_DONE) # Set changing flag off self._is_changing = False def index_is_valid(self, index): """ Test whether given index is valid. Notice -1 is not valid. @param index: Index to test. @return: Boolean. """ # Test whether given index is valid return 0 <= index and index < self.size() def index_is_valid_or_void(self, index): """ Test whether given index is valid or is -1. @param index: Index to test. @return: Boolean. """ # Test whether given index is valid or is -1 return index == -1 or self.index_is_valid(index) def index_first(self): """ Get the first item's index. @return: First item's index, or -1 if the listbox is empty. """ # Return the first item's index return 0 if self.size() > 0 else -1 def index_last(self): """ Get the last item's index. @return: Last item's index, or -1 if the listbox is empty. """ # Return the last item's index return self.size() - 1 def indexcur(self, internal=False, raise_error=False): """ Get the active index. @param internal: See 2N6OR. @return: The active index. If no active active, either return -1, or raise IndexError if `raise_error` is True. """ # Get active indexes indexcurs = self._indexcurs(internal=internal) # If have active indexes if indexcurs: # Return the first active index return indexcurs[0] # If no active indexes else: # If raise error if raise_error: # Raise error raise IndexError(-1) # If not raise error else: # Return -1 return -1 def _indexcurs(self, internal=False): """ Get active indexes list. 2N6OR @param internal: Whether use listbox widget's selected indexes, instead of cached active index. Notice listbox widget has no selected indexes if it has no focus. Notice using cached active index only supports single-selection mode, which means the result list has at most one index. @return: Active indexes list. """ # If use listbox widget's selected indexes if internal: # Return listbox widget's selected indexes list return [int(x) for x in self._listbox.curselection()] # If not use listbox widget's selected indexes else: # If cached active index is valid if self.index_is_valid(self._indexcur): # Return a list with the cached active index return [self._indexcur] # If cached active index is not valid else: # Return empty list return [] def indexcur_set( self, index, focus=False, notify=True, notify_arg=None, ): """ Set active index. @param index: The index to set. @param focus: Whether set focus on the listbox widget. @param notify: Whether notify pre-change and post-change events. @param notify_arg: Event argument. @return: None. """ # If the index is not valid or -1 if not self.index_is_valid_or_void(index): # Raise error raise IndexError(index) # If the index is valid or is -1. # If the listbox is not enabled if not self.is_enabled(): # Raise error raise ListboxVidget.DisabledError() # If the listbox is enabled. # If the listbox is changing if self._is_changing: # Raise error raise ListboxVidget.CircularCallError() # If the listbox is not changing. # Set changing flag on self._is_changing = True # Get old active index old_indexcur = self._indexcur # Set resetting flag on if new and old indexes are equal self._is_resetting = (index == old_indexcur) # If notify events if notify: # Notify pre-change event self.handler_notify(self.ITEMCUR_CHANGE_SOON, notify_arg) # If old active index is valid if self.index_is_valid(old_indexcur): # Set old active item's background color to normal color self._listbox.itemconfig(old_indexcur, background=self._normal_bg) # Set old active item's foreground color to normal color self._listbox.itemconfig(old_indexcur, foreground=self._normal_fg) # Cache new active index self._indexcur = index # Clear listbox widget's selection self._listbox.selection_clear(0, END) # Set listbox widget's selection self._listbox.selection_set(index) # Set listbox widget's activated index self._listbox.activate(index) # If new active index is valid if index != -1: # Set new active item's background color to active color self._listbox.itemconfig(index, background=self._active_bg) # Set new active item's foreground color to active color self._listbox.itemconfig(index, foreground=self._active_fg) # If set focus if focus: # Set focus on the listbox widget self._listbox.focus_set() # If new active index is valid if index != -1: # Make the active item visible self._listbox.see(index) # If notify events if notify: # Notify post-change event self.handler_notify(self.ITEMCUR_CHANGE_DONE, notify_arg) # Set resetting flag off self._is_resetting = False # Set changing flag off self._is_changing = False def indexcur_set_by_event( self, event, focus=False, notify=True, notify_arg=None, ): """ Set active index using a Tkinter event object that contains coordinates of the active item. @param event: Tkinter event object. @param focus: Whether set focus on the listbox widget. @param notify: Whether notify pre-change and post-change events. @param notify_arg: Event argument. @return: None. """ # Get the event's y co-ordinate's nearest listbox item index index = self._listbox.nearest(event.y) # If the index is not valid if not self.index_is_valid_or_void(index): # Ignore the event return # If the index is valid else: # Set the index as active index self.indexcur_set( index=index, focus=focus, notify=notify, notify_arg=notify_arg, ) def item(self, index): """ Get item at given index. @return: Item at given index, or IndexError if the index is not valid. """ return self.items()[index] def itemcur(self, internal=False, raise_error=False): """ Get the active item. @param internal: See 2N6OR. @param raise_error: Whether raise error if no active item. @return: The active item. If no active item, if `raise_error` is True, raise IndexError, otherwise return None. """ # Get active index. # May raise IndexError if `raise_error` is True. indexcur = self.indexcur( internal=internal, raise_error=raise_error, ) # If no active index if indexcur == -1: # Return None return None # If have active index else: # Return the active item return self.items()[indexcur] def item_insert( self, item, index=None, notify=True, keep_active=True, ): """ Insert item at given index. @param item: Item to insert. @param index: Index to insert. `None` means active index, and if no active index, insert at the end. @param notify: Whether notify pre-change and post-change events. @param keep_active: Whether keep or clear active index. @return: None. """ # If notify events if notify: # Notify pre-change events self.handler_notify(self.ITEMCUR_CHANGE_SOON) self.handler_notify(self.ITEMS_CHANGE_SOON) # Get old active index active_index = self.indexcur() # If the index is None, # it means use active index. if index is None: # Use active index. # `-1` works and means appending. index = active_index # Insert the item to the items list self._items.insert(index, item) # If old active index is valid if active_index != -1: # If old active index is GE the inserted index if active_index >= index: # Shift active index by one active_index += 1 # If old active index is not GE the inserted index, use it as-is. # Set new active index self.indexcur_set(index=active_index, notify=False) # Update listbox widget self._listbox_widget_update( keep_active=keep_active ) # If notify events if notify: # Notify post-change events self.handler_notify(self.ITEMS_CHANGE_DONE) self.handler_notify(self.ITEMCUR_CHANGE_DONE) def item_remove( self, index, notify=True, keep_active=True, ): """ Remove item at given index. @param index: Index to remove. @param notify: Whether notify pre-change and post-change events. @param keep_active: Whether keep or clear active index. @return: None. """ # If the index is not valid if not self.index_is_valid(index): # Raise error raise ValueError(index) # If the index is valid. # If notify events if notify: # Notify pre-change events self.handler_notify(self.ITEMCUR_CHANGE_SOON) self.handler_notify(self.ITEMS_CHANGE_SOON) # Get old active index active_index = self.indexcur() # Remove item at the index del self._items[index] # If old active index is valid if active_index != -1: # Get the last index index_last = self.index_last() # If old active index is GT the last index if active_index > index_last: # Use the last index as new active index active_index = index_last # If old active index is not GT the last index, use it as-is. # Set new active index self.indexcur_set(index=active_index, notify=False) # Update listbox widget self._listbox_widget_update( keep_active=keep_active ) # If notify events if notify: # Notify post-change events self.handler_notify(self.ITEMS_CHANGE_DONE) self.handler_notify(self.ITEMCUR_CHANGE_DONE) def handler_add( self, event, handler, need_arg=False, ): """ Add event handler for an event. If the event is ListboxVidget event, add the event handler to Eventor. If the event is not ListboxVidget event, add the event handler to listbox widget. Notice this method overrides `Eventor.handler_add` in order to add non-ListboxVidget event handler to listbox widget. @param event: Event name. @param handler: Event handler. @param need_arg: Whether the event handler needs event argument. @return: None. """ # If the event is ListboxVidget event if event in self.EVENTS: # Add the event handler to Eventor return Eventor.handler_add( self, event=event, handler=handler, need_arg=need_arg, ) # If the event is not ListboxVidget event, # it is assumed to be Tkinter widget event. else: # Add the event handler to listbox widget return self.bind( event=event, handler=handler, ) def bind( self, event, handler, ): """ Add event handler to listbox widget. ListboxVidget internally uses `<Button-1>` and `<Double-Button-1>` to capture active index changes. So if the given event is `<Button-1>` or `<Double-Button-1>`, the given handler will be wrapped. @param event: Event name. @param handler: Event handler. @return: None. """ # If the event is not `<Button-1>` or `<Double-Button-1>` if event not in ['<Button-1>', '<Double-Button-1>']: # Add the event handler to listbox widget self._listbox.bind(event, handler) # If the event is `<Button-1>` or `<Double-Button-1>` else: # Create event handler wrapper def handler_wrapper(e): """ Event handler wrapper that sets new active index and then calls the wrapped event handler. Setting new active index is needed because when this handler is called by Tkinter, the active index of the listbox is still old. @param e: Tkinter event object. @return: None. """ # Set new active index self.indexcur_set_by_event(e, notify=True) # Call the wrapped event handler handler(e) # Add the event handler wrapper to the listbox widget self._listbox.bind(event, handler_wrapper) def _on_single_click(self, event): """ `<Button-1>` event handler that updates active index. @param event: Tkinter event object. @return: None. """ # Updates active index self.indexcur_set_by_event(event, notify=True) def _on_double_click(self, event): """ `<Double-Button-1>` event handler that updates active index. @param event: Tkinter event object. @return: None. """ # Updates active index self.indexcur_set_by_event(event, notify=True) def _listbox_widget_update( self, keep_active, ): """ Update listbox widget's items and selection. @param keep_active: Whether keep or clear active index. @return: None. """ # Remove old items from listbox widget self._listbox.delete(0, END) # Insert new items into listbox widget. # For each ListboxVidget items. for index, item in enumerate(self.items()): # Get item text item_text = self._item_to_text(item) # Insert the item text into listbox widget self._listbox.insert(index, item_text) # Set the item's normal background color self._listbox.itemconfig(index, background=self._normal_bg) # Set the item's normal foreground color self._listbox.itemconfig(index, foreground=self._normal_fg) # Set the item's selected background color self._listbox.itemconfig(index, selectbackground=self._selected_bg) # Set the item's selected foreground color self._listbox.itemconfig(index, selectforeground=self._selected_fg) # If keep active index if keep_active: # Use old active index indexcur = self._indexcur # If not keep active index else: # Set active index to -1 indexcur = self._indexcur = -1 # Clear old selection self._listbox.selection_clear(0, END) # Set new selection. # `-1` works. self._listbox.selection_set(indexcur) # Set new active index. # `-1` works. self._listbox.activate(indexcur) # If new active index is valid if indexcur != -1: # Set active background color self._listbox.itemconfig(indexcur, background=self._active_bg) # Set active foreground color self._listbox.itemconfig(indexcur, foreground=self._active_fg) # Make the active item visible self._listbox.see(indexcur)
class Ufd: """ Universal File Dialog - "UFD" Unopinionated, minimalist, reusable, slightly configurable, general-purpose file-dialog. """ def __init__(self, title: str = "Universal File Dialog", icon: str = "", show_hidden: bool = False, include_files: bool = True, multiselect: bool = True, select_dirs: bool = True, select_files: bool = True, unix_delimiter: bool = True, stdout: bool = False): """ Init kwargs as object attributes, save references to Tk PhotoImages, & define the widgets + layout """ if not isinstance(title, str): raise TypeError("Argument title must be type string.") self.title = title if icon: if not isinstance(icon, str): raise TypeError("Argument icon must be type string.") if not isfile(icon): raise FileNotFoundError(f"File not found: {icon}") self.icon = icon else: self.icon = "" if show_hidden: self.show_hidden = True else: self.show_hidden = False if include_files: self.include_files = True else: self.include_files = False if multiselect: self.multiselect = True else: self.multiselect = False if select_dirs: self.select_dirs = True else: self.select_dirs = False if select_files: self.select_files = True else: self.select_files = False if unix_delimiter: self.unix_delimiter = True else: self.unix_delimiter = False if stdout: self.stdout = True else: self.stdout = False # Tkinter: self.dialog = Tk() self.dialog.withdraw() self.dialog.title(self.title) self.dialog.minsize(width=300, height=200) self.dialog.geometry("500x300") self.dialog.update_idletasks() self.file_icon = PhotoImage(file=f"{dirname(__file__)}/file.gif", master=self.dialog).subsample(50) self.folder_icon = PhotoImage(file=f"{dirname(__file__)}/folder.gif", master=self.dialog).subsample(15) self.disk_icon = PhotoImage(file=f"{dirname(__file__)}/disk.gif", master=self.dialog).subsample(15) if self.icon: self.dialog.iconbitmap(self.icon) else: self.dialog.iconbitmap(f"{dirname(__file__)}/icon.ico") # Widgets: self.paneview = PanedWindow( self.dialog, sashwidth=7, bg="#cccccc", bd=0, ) self.left_pane = PanedWindow(self.paneview) self.right_pane = PanedWindow(self.paneview) self.paneview.add(self.left_pane) self.paneview.add(self.right_pane) self.treeview_x_scrollbar = Scrollbar(self.left_pane, orient="horizontal") self.treeview_y_scrollbar = Scrollbar(self.left_pane, orient="vertical") self.list_box_x_scrollbar = Scrollbar(self.right_pane, orient="horizontal") self.list_box_y_scrollbar = Scrollbar(self.right_pane, orient="vertical") # tstyle = Style().configure(".", ) self.treeview = Treeview( self.left_pane, xscrollcommand=self.treeview_x_scrollbar.set, yscrollcommand=self.treeview_y_scrollbar.set, show="tree", selectmode="browse", # style=tstyle ) self.list_box = Listbox(self.right_pane, xscrollcommand=self.list_box_x_scrollbar.set, yscrollcommand=self.list_box_y_scrollbar.set, width=34, highlightthickness=0, bd=2, relief="ridge") if self.multiselect: self.list_box.config(selectmode="extended") else: self.list_box.config(selectmode="browse") self.cancel_button = Button(self.left_pane, text="Cancel", command=self.cancel) self.submit_button = Button(self.right_pane, text="Submit", command=self.submit) self.treeview_x_scrollbar.config(command=self.treeview.xview) self.treeview_y_scrollbar.config(command=self.treeview.yview) self.list_box_x_scrollbar.config(command=self.list_box.xview) self.list_box_y_scrollbar.config(command=self.list_box.yview) #Layout: self.dialog.rowconfigure(0, weight=1) self.dialog.columnconfigure(0, weight=1) self.left_pane.grid_rowconfigure(0, weight=1) self.left_pane.grid_columnconfigure(0, weight=1) self.right_pane.grid_rowconfigure(0, weight=1) self.right_pane.grid_columnconfigure(0, weight=1) self.paneview.paneconfigure( self.left_pane, minsize=100, #Start off w/ the sash centered in the GUI: width=(self.dialog.winfo_width() / 2) - ceil( (self.paneview.cget("sashwidth") * 1.5)), ) self.paneview.paneconfigure(self.right_pane, minsize=100) self.paneview.grid(row=0, column=0, sticky="nsew") self.treeview.grid(row=0, column=0, sticky="nsew") self.treeview_y_scrollbar.grid(row=0, column=1, sticky="ns") self.treeview_x_scrollbar.grid(row=1, column=0, columnspan=2, sticky="ew") self.list_box.grid(row=0, column=0, sticky="nsew") self.list_box_y_scrollbar.grid(row=0, column=1, sticky="ns") self.list_box_x_scrollbar.grid(row=1, column=0, columnspan=2, sticky="ew") self.cancel_button.grid(row=2, column=0, sticky="w", padx=10, pady=10) self.submit_button.grid(row=2, column=0, columnspan=2, sticky="e", padx=10, pady=10) #Bindings, Protocols, & Misc: self.dialog.bind("<Control-w>", self.cancel) self.treeview.bind("<<TreeviewSelect>>", self.treeview_select) self.treeview.bind("<Double-Button-1>", self.dialog_populate) self.treeview.bind("<Return>", self.dialog_populate) self.treeview.bind("<Right>", self.dialog_populate) self.list_box.bind("<<ListboxSelect>>", self.list_box_select) self.list_box.bind("<Return>", self.submit) self.dialog.protocol("WM_DELETE_WINDOW", self.cancel) self.dialog_selection = deque() self.selection_paths = deque() for disk in self.get_disks(): self.treeview.insert( "", index="end", text=disk, image=self.disk_icon, ) self.dialog.focus() def __call__(self): """ Display dialog & return selection """ (width_offset, height_offset) = self.get_offset(self.dialog) self.dialog.geometry(f"+{width_offset}+{height_offset}") self.dialog.update_idletasks() self.dialog.deiconify() self.dialog.wait_window() for i, path in enumerate(self.dialog_selection): if self.unix_delimiter: self.dialog_selection[i] = sub("\\\\", "/", path) else: self.dialog_selection[i] = sub("/", "\\\\", path) if self.stdout: [print(item) for item in self.dialog_selection] return list(self.dialog_selection) def __str__(self): """ Return own address """ return "Universal File Dialog"\ f" @ {hex(id(self))}" def __repr__(self): """ Return full string representation of constructor signature """ return f"Ufd("\ f"title=\"{self.title}\","\ f" icon=\"{self.icon}\","\ f" show_hidden={self.show_hidden},"\ f" include_files={self.include_files},"\ f" multiselect={self.multiselect},"\ f" select_dirs={self.select_dirs},"\ f" select_files={self.select_files},"\ f" unix_delimiter={self.unix_delimiter})"\ f" stdout={self.stdout})"\ f" @ {hex(id(self))}" @staticmethod def get_offset(tk_window): """ Returns an appropriate offset for a given tkinter toplevel, such that it always is created center screen on the primary display. """ width_offset = int((tk_window.winfo_screenwidth() / 2) - (tk_window.winfo_width() / 2)) height_offset = int((tk_window.winfo_screenheight() / 2) - (tk_window.winfo_height() / 2)) return (width_offset, height_offset) @staticmethod def get_disks(): """ Returns all mounted disks (for Windows) >> ["A:", "B:", "C:"] """ if system() != "Windows": raise OSError("For use with Windows platforms.") logicaldisks = run(["wmic", "logicaldisk", "get", "name"], capture_output=True) return findall("[A-Z]:", str(logicaldisks.stdout)) @staticmethod def list_dir(path, force=False): """ Reads a directory with a shell call to dir. Truthiness of bool force determines whether hidden items are returned or not. (For Windows) """ path = sub("/", "\\\\", path) if force: dir_listing = run(["dir", path, "/b", "/a"], shell=True, capture_output=True) else: dir_listing = run(["dir", path, "/b"], shell=True, capture_output=True) output = dir_listing.stdout err = dir_listing.stderr if not output: return [] if err: err = err.decode("utf-8") raise Exception(err) str_output = output.decode("utf-8") list_output = re_split("\r\n", str_output) return sorted([item for item in list_output if item]) def climb(self, item): """ Builds & returns a complete path to root directory, including the item name itself as the path tail. An extra delimiter is appeneded for the subsequent child node, which is normalized in dialog_populate() """ item_text = self.treeview.item(item)["text"] parent = self.treeview.parent(item) path = "" parents = deque() while parent: parents.append(self.treeview.item(parent)["text"] + "/") parent = self.treeview.parent(parent) for parent in reversed(parents): path += parent path += item_text + "/" return path def dialog_populate(self, event=None): """ Dynamically populates & updates the treeview, listbox, and keeps track of the full paths corresponding to each item in the listbox """ if not self.treeview.focus(): return self.treeview.column("#0", width=1000) existing_children = self.treeview.get_children(self.treeview.focus()) [self.treeview.delete(child) for child in existing_children] self.list_box.delete(0, "end") self.selection_paths.clear() focus_item = self.treeview.focus() path = self.climb(focus_item) if self.show_hidden: children = self.list_dir(path, force=True) else: children = self.list_dir(path) for child in children: if isdir(path + child): self.treeview.insert(focus_item, index="end", text=child, image=self.folder_icon) if self.select_dirs: self.list_box.insert("end", child) self.selection_paths.append(path + child) elif isfile(path + child): if self.include_files: self.treeview.insert(focus_item, index="end", text=child, image=self.file_icon) if self.select_files: self.list_box.insert("end", child) self.list_box.itemconfig("end", {"bg": "#EAEAEA"}) self.selection_paths.append(path + child) if isfile(normpath(path)): (head, tail) = path_split(normpath(path)) head = sub("\\\\", "/", head) self.list_box.insert("end", tail) self.selection_paths.append(head + "/" + tail) self.list_box.itemconfig("end", {"bg": "#EAEAEA"}) def list_box_select(self, event=None): """ Dynamically refresh the dialog selection with what's selected in the listbox (Callback for <<ListboxSelect>>). """ self.dialog_selection.clear() for i in self.list_box.curselection(): self.dialog_selection.append(self.selection_paths[i]) def treeview_select(self, event=None): """ Dynamically refresh the dialog selection with what's selected in the treeview (Callback for <<TreeviewSelect>>). """ for i in self.list_box.curselection(): self.list_box.selection_clear(i) self.dialog_selection.clear() item = normpath(self.climb(self.treeview.focus())) self.dialog_selection.append(item) def submit(self, event=None): """ Satisfies wait_window() in self.__call__() and validates selection (Callback for <Return>, <Button-1> on file_list, submit_button) """ if self.select_dirs == False: for item in self.dialog_selection: if isdir(item): messagebox.showwarning( "Error - Invalid Selection", "Unable to select directory. Please select a file(s).") return if self.select_files == False: for item in self.dialog_selection: if isfile(item): messagebox.showwarning( "Error - Invalid Selection", "Unable to select file. Please select a folder(s)") return self.dialog.destroy() def cancel(self, event=None): """ Satisfies wait_window() in self.__call__() (Callback for <Button-1> on cancel_button) (Callback for protocol "WM_DELETE_WINDOW" on self.dialog) """ self.dialog_selection.clear() self.dialog.destroy()
def historyTab(): # window that shows history of all chats. historyWindow = Toplevel(root) root.withdraw() historyWindow.title("{} - History".format(userEmailAddress)) historyWindow.geometry("1000x800") historyWindow.config(bg="#ccffcc") historyWindow.resizable(height=False, width=False) historyList = Listbox( historyWindow, height=37, width=96, bg="#ccffcc", foreground="#446665", font=("Verdana", 12), borderwidth=5, ) historyList.place(x=10, y=10) def returnList(text): responseList = [] i = 0 while i < len(text): if len(text) - i > 87: responseList.append(text[i:i + 87] + '-') i = i + 87 else: responseList.append(text[i:]) break return responseList scrollbary = Scrollbar(historyWindow, command=historyList.yview) historyList['yscrollcommand'] = scrollbary.set scrollbary.place(x=985, y=10, height=720) scrollbary.config(bg="#ccffcc") #scrollbarx = Scrollbar(historyWindow, command=historyList.xview, orient="horizontal") #historyList['xscrollcommand'] = scrollbarx.set #scrollbarx.place(x=10, y=725, width=980) #scrollbarx.config(bg="#ccffcc") mycursor = con.execute(""" select * from MsgStoreHistory """) histories = mycursor.fetchall() i = 1 try: dateTime = str(histories[0][0]) date = dateTime[:10] historyList.insert(i, date) historyList.itemconfig(i - 1, {'fg': 'red'}) i += 1 for chats in histories: chatsDateTime = str(chats[0]) chatsDate = chatsDateTime[:10] chatsTime = chatsDateTime[11:] if chatsDate != date: historyList.insert(i, " ") i += 1 date = chatsDate historyList.insert(i, date) historyList.itemconfig(i - 1, {'fg': 'red'}) i += 1 else: pass if chats[1] == userEmailAddress: textList = returnList(chats[2]) historyList.insert("end", chatsTime + " : You: " + textList[0]) historyList.itemconfig("end", {'fg': 'blue'}) for response in textList[1:]: historyList.insert( "end", " " + response) historyList.itemconfig("end", {'fg': 'blue'}) i += 1 elif chats[1] == "bot" + userEmailAddress: textList = returnList(chats[2]) historyList.insert("end", chatsTime + " : Bot: " + textList[0]) historyList.itemconfig("end", {'fg': 'green'}) for response in textList[1:]: historyList.insert( "end", " " + response) historyList.itemconfig("end", {'fg': 'green'}) i += 1 except IndexError: pass # calls when user invokes clear button def clearButtonListener(): answer = messagebox.askyesno("Clear", "Sure?") if answer == True: con.execute( """ delete from MsgStoreHistory where sender in ("{}", "{}") """ .format(userEmailAddress, 'bot' + userEmailAddress)) con.commit() historyList.delete(0, "end") messagebox.showinfo("Clear", "All the chat history has been deleted.") else: pass # loading and using clear button image clearButton = Button(historyWindow, image=clear_button_image, bg="#ccffcc", borderwidth=0, command=clearButtonListener) clearButton.place(x=8, y=740) # exports the chats to a file appended with current time. (Invokes when 'export chats history' invoke in menu bar of this particular window.) def exportChats(): timestr = str(datetime.now()) textFile = open( "Histories/{}_chatHistories_{}.txt".format( userEmailAddress, '_'.join([ timestr[:4], timestr[5:7], timestr[8:10], timestr[11:13], timestr[14:16], timestr[17:19] ])), 'w') mycursor = con.execute(""" select * from MsgStoreHistory """) messages = mycursor.fetchall() for message in messages: if message[1] == userEmailAddress: textFile.write( str(message[0]) + " => You:" + message[2] + '\n') elif message[1] == 'bot' + userEmailAddress: textFile.write( str(message[0]) + " => Bot:" + message[2] + '\n') textFile.close() messagebox.showinfo( "Export", """ Chats has been exported to "{}_chatsHistory_{}.txt" file """ .format( userEmailAddress, '_'.join([ timestr[:4], timestr[5:7], timestr[8:10], timestr[11:13], timestr[14:16], timestr[17:19] ]))) # calks when user exits from the history window. def exitWindow(): root.deiconify() historyWindow.withdraw() # menu bar for history window menubar = Menu(historyWindow, bg="#ccffcc") options = Menu(menubar, tearoff=0, bg="#ccffcc") menubar.add_cascade(label="Options", menu=options) options.add_command(label="Export Chat History", command=exportChats) options.add_separator() options.add_command(label="Exit", command=exitWindow) historyWindow.config(menu=menubar) historyWindow.protocol("WM_DELETE_WINDOW", exitWindow)
class CompilationScreen(TkPage): Name = 'Compilation' Font = lambda Size: ('Courier', Size) #font of the page def __init__(self, Parent, *args, **kwargs): super().__init__() #constructor of super class self.Songs = [Song for Song in DirList('Songs') if Song.endswith('.mid')] #mappable songs self.MappedSongs = [Song for Song in DirList('MappedSongs') if Song.endswith('.cmid')] #mapped and compiled song TopLabel = Label(self, text = 'Compile a Song', font= CompilationScreen.Font(24), bd = 10) #top label with a title for the page TopLabel.place(anchor= 'n', relx= 0.5, rely = 0.015, relwidth = 1, relheight=0.15) #placing the label self.ItemList = ListBox(self) #item list of the song for Index, Item in enumerate(self.Songs): #for loop for every compiled comiled song self.ItemList.insert(Index, Item) #indexing the song in the list self.ItemList.itemconfig(Index, {'bg' : '#C2C2C2'}) self.ItemList.place(anchor= 'n', relx= 0.5, rely = 0.19, relwidth = 1, relheight = 0.46) #placing the item list self.ApproxValue = IntVar() self.ApproxValue.set(1) self.SingleTracks = IntVar() self.SingleTracks.set(0) self.Closest = Radio(self, text = 'Closest Approximation (A# = A, A- = A)', variable = self.ApproxValue, value = 1) self.Closest.place(anchor = 'nw', relx = 0.008, rely = 0.65, relheight = 0.07, relwidth = 0.6) self.Upper = Radio(self, text = 'Upper Approximation (A# = B, A- = A)', variable = self.ApproxValue, value = 0) self.Upper.place(anchor = 'nw', relx = 0.008, rely = 0.71, relheight = 0.07, relwidth = 0.6) self.Split = Check(self, text = 'Split MIDI into single tracks', variable = self.SingleTracks, onvalue = 1, offvalue = 0) self.Split.place(anchor = 'nw', relx = 0.008, rely = 0.77, relheight = 0.07, relwidth = 0.6) self.Compilation = Button\ ( self, text = 'Compile selected song', command = lambda : self.CompileSong() ) self.Compilation.place(anchor = 'nw', relx = 0.615, rely = 0.66, relheight = 0.17, relwidth = 0.38) self.Back = Button\ ( self, text = 'Back to Home', command = lambda : self.TurnBack() ) self.Back.place(anchor = 'nw', relx = 0.008, rely = 0.84, relheight = 0.07, relwidth = 0.988) def CompileSong(self): Song = str(self.ItemList.get('active')) Approximation = bool(self.ApproxValue.get()) SplitMIDI = bool(self.SingleTracks.get()) if Approximation: print('closest approximation') Compile(Song, True, False, SplitMIDI) else: print('upper approximation') Compile(Song, False, True, SplitMIDI) def TurnBack(self): GenshinLyrePlayer.Raise(Home.Name) def Refresh(self): #this function update the song list self.Songs = [Song for Song in DirList('Songs') if Song.endswith('.mid')] #check the folder for the songs self.ItemList.delete('0','end') #delete every item of the list for Index, Item in enumerate(self.Songs): #loop for every song in the folder self.ItemList.insert(Index, Item) #index the song in the item list self.ItemList.itemconfig(Index, {'bg' : '#C2C2C2'}) #background of the itemlist
class MainAppController(Frame): """ Main Application for GUI """ def __init__(self, parent): """ Initialize Main Application """ Frame.__init__(self, parent) # create a style object style = Style() style.configure('D.TButton', foreground='red3') style.configure('R.TButton', foreground='DodgerBlue4', font=("TkTextFont", 9, 'bold')) style.configure('B.TButton', foreground='FireBrick4', font=("TkTextFont", 9, 'bold')) # Left frame, column 1 left_frame = Frame(master=self) left_frame.grid(row=1, column=1, padx=30, pady=35, rowspan=3) # Middle frame (info text, column 2) middle_frame = Frame(master=self) middle_frame.grid(row=1, column=2, padx=30, pady=35, rowspan=3) # Right frame (statistics, column 3) right_frame = Frame(master=self) right_frame.grid(row=1, column=3, padx=30, pady=35, rowspan=2) # LEFT FRAME WIDGET Label(left_frame, text="Book ID", font=("TkTextFont", 11)).grid(row=1, column=1, columnspan=3) self._book_list = Listbox(left_frame, height=10, width=10, font=("TkTextFont", 11), bg='LightSalmon2') self._book_list.grid(row=2, column=1) self._book_list.configure(justify="center") # Call this on select self._book_list.bind("<<ListboxSelect>>", self._update_textbox) # MIDDLE FRAME WIDGET Label(middle_frame, text="Book Summary", font=("TkTextFont", 11)).grid(row=1, column=2, columnspan=7) self._info_text = Text(master=middle_frame, height=10, width=45, font=("TkTextFont", 11), bg='plum2') self._info_text.grid(row=2, column=2, columnspan=7) self._info_text.tag_configure("bold", font=("TkTextFont", 10, "bold")) # RIGHT FRAME WIDGET Label(right_frame, text="Book Statistics", font=("TkTextFont", 11)).grid(row=1, column=1, columnspan=3) self._book_stat = Text(master=right_frame, height=10.5, width=30, font=("TkTextFont", 10), bg='LightSalmon2') self._book_stat.grid(row=2, column=1, rowspan=3) self._book_stat.tag_configure("bold", font=("TkTextFont", 10, "bold")) # Drop Down menu to add a book self._add_var = StringVar(left_frame) choices = ['eBook', 'Textbook'] OptionMenu(middle_frame, self._add_var, 'Select Type', *choices).grid(row=3, column=2, pady=5, columnspan=4) # Drop Down menu to update a book self._update_var = StringVar(left_frame) choices = ['eBook', 'Textbook'] OptionMenu(middle_frame, self._update_var, 'Select Type', *choices).grid(row=3, column=3, pady=5, columnspan=7) # A couple buttons - using TTK Button(left_frame, text="Delete Book", width=13, command=self._delete_book, style='D.TButton').grid(row=3, column=1, pady=5) Button(left_frame, text="Quit", width=13, command=self._quit_callback).grid(row=4, column=1) Button(middle_frame, text="Add Book", width=13, command=self._add_book).grid(row=4, column=2, columnspan=4) Button(middle_frame, text="Update Book", width=13, command=self._update_book).grid(row=4, column=3, columnspan=7) Button(right_frame, text="Borrow Book", width=13, command=self._borrow_cb, style='B.TButton').grid(row=5, column=1, pady=5) Button(right_frame, text="Return Book", width=13, command=self._return_cb, style='R.TButton').grid(row=6, column=1) # Now update the list and Statistics self._update_book_list() def _update_textbox(self, *args): """ Updates the info text box on the right, based on the current ID selected """ # This is a list, so we take just the first item (could be multi select...) try: selected_index = self._book_list.curselection()[0] except IndexError: return None book_id = self._book_list.get(selected_index) # Make a GET request r = requests.get( f"http://localhost:5000/library_manager/book/{book_id}") # Clear the text box self._info_text.delete(1.0, tk.END) # Check the request status code if r.status_code != 200: self._info_text.insert(tk.END, "Error running the request!") # For every item (key, value) in the JSON response, display them: for k, v in r.json().items(): self._info_text.insert(tk.END, f"{k.capitalize()}\t\t", "bold") self._info_text.insert(tk.END, f"{v}\n") self._update_book_stat() def _update_book_list(self): """ Update the List of Books """ r = requests.get("http://localhost:5000/library_manager/all") self._book_list.delete(0, tk.END) for s in r.json()["ebook"]: self._book_list.insert(tk.END, '{:^}'.format(s['book_id'])) self._book_list.itemconfig(tk.END, {'fg': 'Blue4'}) if s['is_borrowed']: self._book_list.itemconfig(tk.END, {'bg': 'khaki1'}) for s in r.json()["textbook"]: self._book_list.insert(tk.END, '{:^}'.format(s['book_id'])) self._book_list.itemconfig(tk.END, {'fg': 'Brown4'}) if s['is_borrowed']: self._book_list.itemconfig(tk.END, {'bg': 'khaki1'}) self._update_book_stat() def _update_book_stat(self): """ Update the List of Books """ r = requests.get("http://localhost:5000/library_manager/all/stats") self._book_stat.delete(1.0, tk.END) for k, v in r.json().items(): self._book_stat.insert(tk.END, f"{k}\t\t\t", "bold") self._book_stat.insert(tk.END, f"{v}\n") def _borrow_cb(self): """Borrow any book with the selected ID""" if not self._book_list.curselection(): mb.showerror('Error : Item not selected', 'Please select a book.') else: selected_index = self._book_list.curselection()[0] book_id = self._book_list.get(selected_index) r = requests.get( f"http://127.0.0.1:5000/library_manager/book/{book_id}") if r.json()['is_borrowed']: mb.showerror('Error : Bad selection', 'Book is already borrowed.') else: response = requests.put( f"http://127.0.0.1:5000/library_manager/{book_id}/borrow") if response.status_code == 200: self._update_book_list() def _return_cb(self): """Return any book with the selected ID to library""" if not self._book_list.curselection(): mb.showerror('Error : Item not selected', 'Please select a book.') else: selected_index = self._book_list.curselection()[0] book_id = self._book_list.get(selected_index) r = requests.get( f"http://127.0.0.1:5000/library_manager/book/{book_id}") if not r.json()['is_borrowed']: mb.showerror('Error : Bad selection', 'Book is already returned.') else: response = requests.put( f"http://127.0.0.1:5000/library_manager/{book_id}/return_book" ) if response.status_code == 200: self._update_book_list() def _add_ebook(self): """ Add eBook Popup """ self._popup_win = tk.Toplevel() self._popup = AddeBookPopup(self._popup_win, self._close_book_cb) def _add_textbook(self): """ Add Textbook Popup """ self._popup_win = tk.Toplevel() self._popup = AddTextbookPopup(self._popup_win, self._close_book_cb) def _add_book(self): """Redirect add book based on the type""" if self._add_var.get() == 'eBook': self._add_ebook() elif self._add_var.get() == 'Textbook': self._add_textbook() else: mb.showerror('Error : Type not selected', 'Please select a type.') def _update_book(self): """Update eBook attributes""" if self._update_var.get() == 'eBook': self._update_ebook() elif self._update_var.get() == 'Textbook': self._update_textbook() else: mb.showerror('Error : Type not selected', 'Please select a type.') def _update_ebook(self): """Update ebook attributes in the 'Book' database""" if not self._book_list.curselection(): mb.showerror('Error : Book not selected', 'Please select a book.') else: selected_index = self._book_list.curselection()[0] book_id = self._book_list.get(selected_index) r = requests.get( f"http://localhost:5000/library_manager/book/{book_id}") if r.json()['type'] != 'ebook': mb.showerror('Error : Invalid selection', 'Please select an ebook ID.') else: self._popup_win = tk.Toplevel() self._popup = UpdateeBookPopup(self._popup_win, book_id, self._close_book_cb) self._update_book_list() def _update_textbook(self): """Update textbook attributes in the 'Book' database""" if not self._book_list.curselection(): mb.showerror('Error : Book not selected', 'Please select a book.') else: self._popup_win = tk.Toplevel() selected_index = self._book_list.curselection()[0] book_id = self._book_list.get(selected_index) r = requests.get( f"http://localhost:5000/library_manager/book/{book_id}") if r.json()['type'] != 'textbook': mb.showerror('Error : Invalid selection', 'Please select a textbook ID.') else: self._popup = UpdateTextbookPopup(self._popup_win, book_id, self._close_book_cb) self._update_book_list() def _delete_book(self): """ Delete book Popup """ self._popup_win = tk.Toplevel() self._popup = DeleteBook(self._popup_win, self._close_book_cb) def _close_book_cb(self): """ Close Popup """ self._popup_win.destroy() self._update_book_list() def _quit_callback(self): """ Quit """ self.quit()
class Mainwindow(Frame): def __init__(self, height, width, server_host, users_list, master=None): Frame.__init__(self, master) self.master = master self.height = height self.width = width self.server_host = server_host self.pack() self.createWidgets() self.setupFunctions() self.insert_text("Has entrado a la conversación!") self.add_connect(users_list[0]) def createWidgets(self): self.chat_browser_scrollBar = Scrollbar(self.master) self.chat_browser_scrollBar.place(x=self.width-15, y=0, height=self.height*0.5) self.chat_browser = Text(self.master, yscrollcommand=self.chat_browser_scrollBar.set) self.chat_browser.place(x=0, y=0, width=self.width-15, height=self.height * 0.5) self.chat_browser.config(state=DISABLED) self.chat_browser_scrollBar.config(command=self.chat_browser.yview) self.text_writter = Text(self.master) self.text_writter.place(x=0, y=(self.height * 0.5) + 5, height=140) self.connected_list = Listbox(self.master) self.connected_list.place(x=self.width + 5, y=0, height=self.height * 0.5, width=self.width * 0.44) self.send_button = Button(self.master, text="Enviar", command=self.send_message) self.send_button.place(x=self.width * 1.22, y=self.height / 2 + 15, height=40, width=100) self.clear_button = Button(self.master, text="Borrar", command=self.clear_text) self.clear_button.place(x=self.width * 1.22, y=self.height / 2 + 80, height=40, width=100) def setupFunctions(self): self.text_writter.bind_all("<Return>", self.send_key_pressed) self.text_writter.bind_all("<BackSpace>", self.clear_key_pressed) def send_key_pressed(self, event): self.send_message() def clear_key_pressed(self, event): self.clear_text() def receive_message(self, host, message): text = host+":\n\t"+message self.insert_text(text) def insert_text(self, message): message += "\n" self.chat_browser.config(state=NORMAL) self.chat_browser.insert("end", message) self.chat_browser.config(state=DISABLED) self.chat_browser.see("end") def add_connect(self, item): color = "white" if self.connected_list.size() % 2 == 1: color = "#eaeae1" self.connected_list.insert("end", item) self.connected_list.itemconfig("end", bg=color) def delete_connect(self, item, list): list.remove(item) self.connected_list.delete(0, "end") for i in list: self.add_connect(i) def reset_connected_list(self, list): self.connected_list.delete(0, "end") for i in list: self.add_connect(i) def clear_text(self): self.text_writter.delete("1.0", "end") def send_message(self, text=None): message = text if not message: message = self.text_writter.get("1.0", "end") message = message.strip() self.text_writter.delete("1.0", "end") if not message: return print("Enviando mensaje:", message) start_new_thread(self.send_sock, (message,)) def send_sock(self, message): message = message.encode(encoding="UTF-8") sock = socket(AF_INET, SOCK_STREAM) sock.connect((self.server_host)) sock.send(message) sock.close()