def __init__(self, parent, tree: ttk.Treeview) -> None: Frame.__init__(self, parent) self.parent = parent self.values = tree.item(tree.selection())["values"] self.old = tree.item(tree.selection())["values"] self.initUI()
class hey: def __init__(self): self.star1 = Toplevel() self.obj = database.Database() self.result = self.obj.getmenu() self.star1.geometry('1366x768') self.can = Canvas(self.star1, height=768, width=1366) self.can.pack() self.img = PhotoImage(file='./image/654.png') self.can.create_image(0, 0, image=self.img, anchor=NW) self.table = Treeview(self.can, columns=("#0", "#1", "#2", "#3", "#4")) self.table.heading('#0', text="Sr no.") self.table.column('#0', width=40) self.table.heading('#1', text="Name") self.table.column('#1', width=100) self.table.heading('#2', text="Amount") self.table.column('#2', width=100) self.table.heading('#3', text="edit") self.table.column('#3', width=100) self.table.heading('#4', text="delete") self.table.column('#4', width=100) for i in self.result: self.table.insert('', 'end', text=i[0], values=(i[1], i[2], "edit", "Delete")) self.table.place(x=300, y=300) self.btn = Button(self.can, text="<- Back", fg='white', bg='black', font=('monaco', 15, 'bold'), command=self.back) self.btn.place(x=810, y=540) self.table.bind("<Double-Button-1>", self.trigger) self.star1.resizable(height=False, width=False) self.star1.state("zoomed") self.star1.mainloop() def back(self): self.star1.destroy() def trigger(self, e): f = self.table.focus() x = self.table.item(f) col = self.table.identify_column(e.x) if (col == "#3"): self.star1.destroy() obj = updatemenu.UpdateMenu(x["text"]) elif (col == "#4"): self.star1.destroy() d = database.Database() d.delete(x["text"])
class ContactsListView(Frame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.search_text = StringVar() self.console_text = StringVar() # Treeview setup col_ids = ("first_name", "surname", "phone", "email", "last_edited") self.contacts_list = Treeview(self, columns=col_ids, show='headings') for col_id, text in zip( col_ids, ["First name", "Surname", "Phone", "Email", "Last edited"]): self.contacts_list.column(col_id, stretch=True, width=160) self.contacts_list.heading(col_id, text=text) # Search panel search_panel = Frame(self) search_entry = Entry(search_panel, textvariable=self.search_text) self.search_btn = Button(search_panel, text="Search") search_entry.pack(side=LEFT) self.search_btn.pack(side=LEFT) # Controls self.add_btn = Button(self, text="Add") self.edit_btn = Button(self, text="Edit") self.delete_btn = Button(self, text="Delete") self.console = Label(self, textvariable=self.console_text) # Layout search_panel.pack() self.contacts_list.pack() self.console.pack() self.delete_btn.pack(side=RIGHT) self.edit_btn.pack(side=RIGHT) self.add_btn.pack(side=RIGHT) def set(self, contacts): self.contacts_list.delete(*self.contacts_list.get_children()) for contact_fields in contacts: rowid, values = str(contact_fields[0]), contact_fields[1:] self.contacts_list.insert('', 'end', text=rowid, values=values) self.log() def get_selected_contacts_ids(self): focused_rows = self.contacts_list.selection() return map(lambda focus: self.contacts_list.item(focus)['text'], focused_rows) def log(self, message=''): self.console_text.set(message)
class SelectionFrame(Frame): def __init__(self, fruit_list, **kw): # init drop down super().__init__(**kw) self.fruit_list = fruit_list self.type_select = StringVar(self) header = Label(self) header.grid(row=0, column=0, columnspan=2, pady=10) type_options = OptionMenu( header, self.type_select, *models.TYPES, command=self.set_group) type_options.config(width=14) type_options.grid(row=0, column=0) # init start simulator button simulator_btn = Button( header, text="模拟器", command=lambda: sm.Simulator().mainloop()) simulator_btn.grid(row=0, column=1) # init treeView self.tree = Treeview(self, columns=["名称", "效果"], show="headings") self.tree.column("名称", width=50, anchor='center') self.tree.column("效果", width=150, anchor='center') self.tree.heading("名称", text="名称") self.tree.heading("效果", text="效果") self.tree.grid(row=1, column=0) self.tree.bind("<Double-1>", self.select_item) self.select_item_callback = lambda x: x vbar = Scrollbar(self, orient=VERTICAL, command=self.tree.yview) self.tree.configure(yscrollcommand=vbar.set) vbar.grid(row=1, column=1, sticky=NS) # default value self.set_group(models.TYPES[0]) def set_group(self, group): self.type_select.set(group) x = self.tree.get_children() for item in x: self.tree.delete(item) for x in self.fruit_list: if x.get_type() == group: self.tree.insert("", END, value=(x.name, x.description)) def select_item(self, event): item = self.tree.selection()[0] name = self.tree.item(item, "value")[0] self.select_item_callback( next(filter(lambda x: x.name == name, self.fruit_list))) def set_select_callback(self, callback): self.select_item_callback = callback
def select_item(self, event: tk.Event, prop_class: Union[EXIFProperty, GPSProperty], tree: ttk.Treeview): query_item: Union[Tuple, str] = tree.item(tree.focus(), option='values') if query_item == '': return col: str = tree.identify_column(getattr(event, 'x')) prop, val = query_item if col == '#1': if isinstance(prop_class, IFDPanel.EXIFProperty) and prop == prop_class.file_name: os.startfile(self.app.widget_info.cur_img_path) return # '#2' if isinstance(prop_class, IFDPanel.EXIFProperty) and prop == prop_class.file_name: val = self.app.widget_info.cur_img_path.stem tree.clipboard_clear() tree.clipboard_append(val)
class ResultForm(tk.Frame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.header_label = tk.Label(self, text="All your saved passwords:", font=("roboto slab", 12, "bold")) self.header_label.grid(row=0, column=0, pady=(0, 5), sticky=tk.W) self.scrollbar_y = tk.Scrollbar(self, orient=tk.VERTICAL) self.tree = Treeview(self, columns=("Place", "Password"), yscrollcommand=self.scrollbar_y.set) self.scrollbar_y.config(command=self.tree.yview) self.scrollbar_y.grid(row=1, column=1, sticky="nsew") self.tree.heading("Place", text="Place") self.tree.heading("Password", text="Password") self.tree.column("#0", minwidth=0, width=0) self.tree.column("#1", width=175) self.tree.column("#2", width=175) self.style = Style() # noinspection SpellCheckingInspection self.style.configure("Treeview", rowheight=15) # noinspection SpellCheckingInspection self.style.configure("Treeview.Heading", font=("roboto slab", 10, "bold"), foreground="#a6a6a6") self.tree.grid(row=1, column=0) self.instruction_label = tk.Label(self, text="* First select an item, then choose from below", font=("roboto slab", 8, "italic")) self.instruction_label.grid(row=2, column=0, sticky=tk.W) def insert_to_tree(self, values): for value in values: self.tree.insert("", tk.END, value=value) def empty_tree(self): if self.tree.get_children(): self.tree.delete(*self.tree.get_children()) def return_selected_item_values(self): """Returns the values of the highlighted item inside TreeView""" highlighted_item = self.tree.selection() if highlighted_item: return tuple(self.tree.item(highlighted_item)["values"])
class Window: def __init__(self): self.tk = Tk() self.tk.geometry('500x500') fetch = (getdata.fetch()) self.tree = Treeview(self.tk, columns=("#1", "#2", "#3", "#4")) self.tree.heading("#0", text="user id") self.tree.column("#0", width=60) self.tree.heading("#1", text="User Name") self.tree.heading("#2", text="Password") self.tree.heading("#3", text="Update") self.tree.heading("#4", text="Delete") self.data = getdata.fetch() for i in self.data: self.tree.insert('', 'end', text=i[0], values=(i[1], i[2], "update", "delete")) self.tree.place(x=0, y=0) self.tree.bind("<Double-Button-1>", self.trigger) self.tk.mainloop() def trigger(self, e): #e will identify from where the function has been triggered print(e) #d will store the object of focused element in the treeview d = self.tree.focus() #self.tree.item is use to get the data from the focused row #so thats why we pass the focused item there d x = (self.tree.item(d)) print(x) #col will identify the focused column col = self.tree.identify_column(e.x) if col == "#3": print("Update") elif col == "#4": getdata.delete(x["text"]) print("delete")
class MultipleInstallPage(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller # will do a 4x4 grid here for count in range(0, 4): Grid.rowconfigure(self, count, weight=1) Grid.columnconfigure(self, count, weight=1) self.temp_tv = Treeview(self) temp_tv = self.temp_tv temp_tv.grid(row=0, column=0, rowspan=3, columnspan=4, sticky=(N, E, W, S)) temp_tv.heading('#0', text="Choose one:") temp_tv.column("#0", minwidth=300) # adding scrollbar ysb = Scrollbar(self, orient='vertical', command=temp_tv.yview) temp_tv.configure(yscroll=ysb.set) ysb.grid(row=0, column=3, rowspan=3, sticky='nse') # Buttons for the rest ok_button = Button(self, text="Ok", command=self.ok_button_click) ok_button.grid(row=3, column=0, sticky=N + S + E + W) cancel_button = Button(self, text="Cancel", command=lambda: controller.show_frame(MainPage)) cancel_button.grid(row=3, column=3, sticky=N + S + E + W) def ok_button_click(self): # Should only do stuff is something is selected if self.temp_tv.focus() != '': installer_path = self.temp_tv.item(self.temp_tv.focus())['text'] launch_installer(installer_path) self.controller.show_frame(MainPage) else: return -1
class IncomeEntry(Frame, MoneySubject): def __init__(self, parent): super().__init__(parent) MoneySubject.__init__(self) self.parent = parent self.initUI() def initUI(self): self.entries = {} self.records = [] titleFrame = Frame(self, borderwidth=1) titleFrame.pack(fill=BOTH, expand=True) lbl = Label(titleFrame, text="Incomes:", font=("Ubuntu", 20)) lbl.pack(side=LEFT) entryFrame = Frame(self, borderwidth=1) for data in [("Hours", 3), ("Rate", 5), ("Desc", 15)]: dataFrame = Frame(entryFrame, borderwidth=2) lbl = Label(dataFrame, text=data[0], font=("Ubuntu", 10)) lbl.pack() entry = Entry(dataFrame, width=data[1]) entry.pack() self.entries[data[0]] = entry dataFrame.pack(side=LEFT) okButton = Button(entryFrame, text="Submit", command=self.submitIncome) okButton.pack(side=LEFT) entryFrame.pack(fill=BOTH, expand=True) self.incomeList = Treeview(self, height=3) columns = ("Hours", "Rate", "Desc", "Total") self.incomeList["columns"] = columns self.incomeList.column("#0", width=0, minwidth=0, stretch=NO) for field in columns: self.incomeList.column(field, width=100, stretch=NO) self.incomeList.heading(field, text=field, anchor=W) self.incomeList.pack(side=LEFT) self.pack(fill=BOTH, expand=False) self.incomeList.bind("<Delete>", self.keydown) def keydown(self, e): item = self.incomeList.selection() if item != (): values = self.incomeList.item(item)['values'] hours = float(values[0]) rate = float(values[1]) desc = str(values[2]) amt = hours * rate self.moneyNotify({"income": -amt}) self.incomeList.delete(item) self.records.remove({"hours": hours, "rate": rate, "desc": desc}) def _emitIncome(self, hours, rate, desc): values = (hours, rate, desc, f"${hours*rate:.2f}") self.incomeList.insert("", "end", text="", values=values) self.records.append({"hours": hours, "rate": rate, "desc": desc}) self.moneyNotify({"income": hours * rate}) def submitIncome(self): # consume input in entry boxes and store in tree hours = float(self.entries["Hours"].get()) rate = float(self.entries["Rate"].get()) desc = self.entries["Desc"].get() self._emitIncome(hours, rate, desc) for entry in self.entries.values(): entry.delete(0, 'end') def clear(self): for child in self.incomeList.get_children(): self.incomeList.delete(child) self.records = [] def export(self): return self.records def restore(self, incomes, startDate): self.clear() for income in incomes: self._emitIncome(income["hours"], income["rate"], income["desc"])
class MediumTreeView(Frame): def __init__(self, parent, *args, **kwargs): Frame.__init__(self, parent) self.tree = Treeview(self) self.tree['selectmode'] = "browse" self.tree['columns'] = ('ID', 'Name', 'Gram', 'Include') self.tree['height'] = 30 self.tree['show'] = "headings" self.tree.heading('ID', text="ID") self.tree.heading('Name', text="Name") self.tree.heading('Gram', text="Quantity [mmol]") self.tree.heading('Include', text="Include") self.tree.column('ID', minwidth=0, width=20) self.tree.column('Name', minwidth=100, width=100) self.tree.column('Gram', minwidth=0, width=90) self.tree.column('Include', minwidth=50, width=50) self.tree.bind('<ButtonRelease-1>', self.select_item) self.tree.grid(row=0, column=0, columnspan=4) self.run_object = kwargs.pop('run_object', None) self.medium = None self.medium_volume = None self.uptake_quantities = {} self.species_names = [] self.pie_figure, self.piechart = plt.subplots() self.pie_figure.figsize = (4, 4) self.piechart.pie([0, 0]) self.canvas = FigureCanvasTkAgg(self.pie_figure, master=self) self.canvas.draw() self.canvas.get_tk_widget().grid(row=0, column=4, padx=10) Label(self, text="Quantity:").grid(row=1, column=0) self.edit_entry = FloatEntry(self, initial_value='') self.edit_entry.grid(row=1, column=1, sticky='w') Button(self, text="Save Changes", command=self.save_changes).grid(row=1, column=2, rowspan=2) self.rad_var = IntVar() self.rad_button_exclude = Radiobutton(self, text="No", variable=self.rad_var, value=0) self.rad_button_include = Radiobutton(self, text="Yes", variable=self.rad_var, value=1) self.rad_button_include.grid(row=2, column=1, sticky='w') self.rad_button_exclude.grid(row=2, column=1, sticky='e') Label(self, text="Include:").grid(row=2, column=0) Label(self, text="Medium Name:").grid(row=3, column=0) self.name_entry = StringEntry(self, initial_value="refined_medium") self.name_entry.grid(row=3, column=1, sticky='w') Button(self, text="Test Medium", command=parent.plot).grid(row=4, column=1) Button(self, text="Save Medium", command=lambda: self.save_medium(parent.save)).grid(row=3, column=2) def plot_medium(self, individual, sub_plot): #costruct medium from treeviev if self.medium is not None: components = {} children = self.tree.get_children('') for child in children: child = self.tree.item(child) ID = child['values'][0] quant = float(child['values'][2]) flag = bool(child['values'][3]) if flag: components[ID] = quant medium = Medium.from_dict(components, self.medium_volume) #simulate medium to get the nutrition uptake for each member of the bacterial community individual.plot(True, medium=medium, sub_plot=sub_plot) uptakes = individual.get_uptakes() #calculate the relative uptake quantities self.uptake_quantities = {} for child in children: child_elements = self.tree.item(child) ID = child_elements['values'][0] name = child_elements['values'][1] quant = float(child_elements['values'][2]) flag = child_elements['values'][3] uptake_per_species = [] self.species_names = [] for n, spec in enumerate(uptakes): self.species_names.append(spec) try: uptake = uptakes[spec][ID] except: uptake = 0 try: self.uptake_quantities[ID].append(uptake) except: self.uptake_quantities[ID] = [uptake] for ID in self.uptake_quantities: total = sum(self.uptake_quantities[ID]) if total == 0: self.uptake_quantities[ID] = [ 0 for i in self.species_names ] print(ID) continue relative_quantities = [] for i in self.uptake_quantities[ID]: relative_quantities.append(i / total) self.uptake_quantities[ID] = relative_quantities def add_medium(self, medium, medium_volume): if medium is not None: self.medium = medium self.medium_volume = medium_volume self.update_treeviev() def update_treeviev(self): if self.medium is not None: for i, comp in enumerate(self.medium.get_components()): try: name = SEEDIDs.SEED_to_Names[comp.split("_")[1]] except: name = comp self.tree.insert('', i, comp, values=[ comp, name, self.medium.get_components()[comp], 1, "" ]) def select_item(self, a): try: currItem = self.tree.focus() string_qu = self.tree.item(currItem)['values'][2] include = bool(self.tree.item(currItem)['values'][3]) self.edit_entry.set(string_qu) self.rad_var.set(0 if not include else 1) self.piechart.clear() self.piechart.pie( self.uptake_quantities[self.tree.item(currItem)['values'][0]], labels=self.species_names, labeldistance=None) self.piechart.axis('equal') self.piechart.legend() self.canvas.draw() except: pass def save_changes(self): currItem = self.tree.focus() ID = self.tree.item(currItem)['values'][0] name = self.tree.item(currItem)['values'][1] exclude = 1 if self.rad_var.get() == 1 else 0 uptake = self.tree.item(currItem)['values'][4] self.tree.item( currItem, values=[ID, name, self.edit_entry.get(), exclude, uptake]) def load_medium(self, file): medium = Medium.import_medium(file) self.add_medium(medium) #saves medium to file def save_medium(self, path): if self.medium is not None: file_path = "" for x in path.split("/")[:-1]: file_path = file_path + x + "/" components = {} children = self.tree.get_children('') for child in children: child = self.tree.item(child) ID = child['values'][0] name = child['values'][1] quant = float(child['values'][2]) flag = bool(child['values'][3]) if flag: if quant > 0: components[name] = quant medium = Medium.from_dict(components, self.medium_volume) Medium.export_medium( medium, file_path + "/" + self.name_entry.get() + ".csv")
class DebitList(Frame, MoneySubject, MoneyObserver): def __init__(self, parent): super().__init__(parent) MoneySubject.__init__(self) MoneyObserver.__init__(self) self.initUI() def initUI(self): self.records = [] self.debitList = Treeview(self, height=15) columns = ("Amount", "Desc") self.debitList["columns"] = columns self.debitList.column("#0", width=70, minwidth=70, stretch=NO) self.debitList.column("Amount", width=70, stretch=NO) self.debitList.column("Desc", width=250, stretch=NO) self.debitList.heading("#0", text="Date", anchor=W) for field in columns: self.debitList.heading(field, text=field, anchor=W) self.debitList.pack(side=LEFT) self.pack() self.debitList.bind("<Delete>", self.keydown) def keydown(self, e): item = self.debitList.selection() parent = self.debitList.parent(item) if item != () and parent != '': values = self.debitList.item(item)['values'] amount = float(values[0][1:]) self.moneyNotify({"debit": -amount}) self.debitList.delete(item) self.records.remove({ "debit": amount, "desc": str(values[1]), "date": parent }) def reset(self): self.records = [] for child in self.debitList.get_children(): self.debitList.delete(child) def export(self): return self.records def restore(self, debits, startDate): self.reset() self.setStartDate(startDate) dateTable = {} for d in range(7): day = startDate + timedelta(days=d) dateStr = day.strftime("%d/%m") dateTable[dateStr] = day for debit in debits: debit["date"] = dateTable[debit["date"]] self.moneyUpdate(debit) self.moneyNotify(debit) def moneyUpdate(self, monies): if "debit" in monies: dateStr = monies["date"].strftime("%d/%m") toSave = monies toSave["date"] = dateStr self.records.append(toSave) values = (f"${monies['debit']}", monies["desc"]) self.debitList.insert(dateStr, "end", text="", values=values) def setStartDate(self, startDate): for d in range(7): day = startDate + timedelta(days=d) dateStr = day.strftime("%d/%m") self.debitList.insert("", "end", id=dateStr, text=dateStr, values=("", ""))
class BioInfo(Tk): def __init__(self): Tk.__init__(self) self.wm_title("BioInfo : comparaison des listes") self.resizable(width=FALSE, height=FALSE) self.SortDir = False # Lists Types self.typeList1 = None self.typeList2 = None # Frame content self.frameContent = Frame(self) self.frameContent.pack(side=TOP, fill=X) # ScrollBar scrollbar = Scrollbar(self.frameContent, orient=VERTICAL) scrollbar.pack(side=RIGHT, fill=Y) # Result Content self.dataCols = ('microArn_A', 'microArn_B', 'FoldC', 'p-Value', 'Note') self.tree = Treeview(self.frameContent, columns=self.dataCols, show = 'headings', yscrollcommand=scrollbar.set) # configure column headings for c in self.dataCols: self.tree.heading(c, text=c, command=lambda c=c: self.columnSort(c, self.SortDir)) self.tree.column(c, width=10) self.tree.pack(side=LEFT, fill=X, expand="yes") scrollbar.config(command=self.tree.yview) # Frame Lists self.frameLists = Frame(self) self.frameLists.pack(side=LEFT) # Frame Forms self.frameForms = Frame(self) self.frameForms.pack(side=LEFT, padx=20) #Liste n°1 selection self.frameList1 = Frame(self.frameLists) self.frameList1.pack() self.typeListStr1 = StringVar(self.frameList1) self.typeListStr1.set(str(ListBioType.TypeA)) self.buttonTypeList1 = OptionMenu(self.frameList1, self.typeListStr1, str(ListBioType.TypeA), str(ListBioType.TypeB)).pack(side=LEFT) self.entrylist1 = Entry(self.frameList1, width=30) self.entrylist1.pack(side=LEFT) self.buttonBrowseList1 = Button(self.frameList1, text="Parcourir", command=self.load_fileList1, width=10) self.buttonBrowseList1.pack(side=LEFT, padx=5) # List n°2 selection self.frameList2 = Frame(self.frameLists) self.frameList2.pack(side=BOTTOM) self.typeListStr2 = StringVar(self.frameList2) self.typeListStr2.set(str(ListBioType.TypeB)) self.buttonTypeList2 = OptionMenu(self.frameList2, self.typeListStr2, str(ListBioType.TypeA), str(ListBioType.TypeB)).pack(side=LEFT) self.entrylist2 = Entry(self.frameList2, width=30) self.entrylist2.pack(side=LEFT) self.buttonBrowseList2 = Button(self.frameList2, text="Parcourir", command=self.load_fileList2, width=10) self.buttonBrowseList2.pack(side=LEFT, padx=5) # Form pValue self.framePVal = Frame(self.frameForms) self.framePVal.pack() Label(self.framePVal, text="pValue").pack(side=LEFT) self.entryPVal = Entry(self.framePVal, width=6) self.entryPVal.pack(side=LEFT) # Form foldC self.frameFoldC = Frame(self.frameForms) self.frameFoldC.pack() Label(self.frameFoldC, text="foldCh").pack(side=LEFT) self.entryFoldC = Entry(self.frameFoldC, width=6) self.entryFoldC.pack(side=LEFT) # Form note self.frameNote = Frame(self.frameForms) self.frameNote.pack() Label(self.frameNote, text="note ").pack(side=LEFT) self.entryNote = Entry(self.frameNote, width=6) self.entryNote.pack(side=LEFT) # Bouton comparer self.buttonComparer = Button(self, text="Comparer", command=self.compare, width=10, state=DISABLED) self.buttonComparer.pack(fill= X, expand="yes", padx=20, pady=(10,0)) #Bouton exporter self.buttonExport = Button(self, text="Exporter", command=self.export, width=10, state=DISABLED) self.buttonExport.pack(fill= X, expand="yes", padx=20) # Réinitialiser self.buttonReset = Button(self, text="Réinitialiser", command=self.reset, width=10) self.buttonReset.pack(fill= X, expand="yes", padx=20, pady=(0,10)) # file members self.list1 = None self.list2 = None def load_fileList1(self): fname = askopenfilename(filetypes=(("CSV files", "*.csv"), ("All files", "*.*") )) if fname: self.entrylist1.delete(0, END) self.list1 = fname self.entrylist1.insert(0,fname) self.buttonComparer.config(state=NORMAL) def load_fileList2(self): fname = askopenfilename(filetypes=(("CSV files", "*.csv"), ("All files", "*.*") )) if fname: self.entrylist2.delete(0, END) self.list2 = fname self.entrylist2.insert(0,fname) self.buttonComparer.config(state=NORMAL) else: showerror("Erreur : fichier B", "La liste B est introuvable") def resetTree (self): for i in self.tree.get_children(): self.tree.delete(i) def reset(self): self.list1 = None self.entrylist1.delete(0, END) self.list2 = None self.entrylist2.delete(0, END) self.entryPVal.delete(0,END) self.entryFoldC.delete(0, END) self.entryNote.delete(0, END) self.typeList1 = None self.typeList2 = None self.buttonExport.config(state=DISABLED) self.buttonComparer.config(state=DISABLED) self.resetTree() def isValidfoldC(self, s): try: float(s) return True except ValueError: return False def isValidPValue(self, s): try: f = float(s) if f >= 0 and f <= 1: return True else: return False except: return False def isValidNote (self, s): try: f = int(s) return True except: return False def compare(self): self.buttonExport.config(state=NORMAL) # Détermination type Listes # List 1 if self.typeListStr1.get() == str(ListBioType.TypeA): self.typeList1 = ListBioType.TypeA elif self.typeListStr1.get() == str(ListBioType.TypeB): self.typeList1 = ListBioType.TypeB else: self.typeList1 = None # List 2 if self.typeListStr2.get() == str(ListBioType.TypeA): self.typeList2 = ListBioType.TypeA elif self.typeListStr2.get() == str(ListBioType.TypeB): self.typeList2 = ListBioType.TypeB else: self.typeList2 = None if not self.isValidfoldC(self.entryFoldC.get()) and not self.entryFoldC.get() == "": showerror("Erreur : foldC","La valeur fold Change n'est pas un nombre") elif not self.isValidPValue(self.entryPVal.get()) and not self.entryPVal.get() == "": showerror("Erreur : pValue","La valeur pValue n'est pas un nombre compris entre 0 et 1") elif not self.isValidNote(self.entryNote.get()) and not self.entryNote.get() == "": showerror("Erreur : note", "La valeur note n'est pas un nombre entier") # (List A and No List) or (No List and List A) elif ((self.list1 is not None and self.typeList1 == ListBioType.TypeA) and (self.list2 is None)) or\ ((self.list2 is not None and self.typeList2 == ListBioType.TypeA) and (self.list1 is None)): self.resetTree() try: listComp = ListComparator(self.list1, self.list2, self.entryPVal.get(), self.entryFoldC.get(), self.entryNote.get()) for e in listComp.getFilterListA(): self.tree.insert('', 'end', values=e) except IndexError: showerror("Erreur : liste A invalide", "Le fichier liste A n'est pas un fichier valide") # (List B and No List) or (No List and List B) elif ((self.list1 is not None and self.typeList1 == ListBioType.TypeB) and (self.list2 is None)) or\ ((self.list2 is not None and self.typeList2 == ListBioType.TypeB) and (self.list1 is None)): self.resetTree() try: listComp = ListComparator(self.list1, self.list2, self.entryPVal.get(), self.entryFoldC.get()) for e in listComp.getFilterListB(): self.tree.insert('', 'end', values=e) except IndexError: showerror("Erreur : liste A invalide", "Le fichier liste A n'est pas un fichier valide") # (List A and List B) or (List B and List A) elif ((self.list1 is not None and self.typeList1 == ListBioType.TypeA) and \ (self.list2 is not None and self.typeList2 == ListBioType.TypeB)) or \ ((self.list1 is not None and self.typeList1 == ListBioType.TypeB) and \ (self.list2 is not None and self.typeList2 == ListBioType.TypeA)): self.resetTree() listA = "" listB = "" if self.typeList1 == ListBioType.TypeA: listA = self.list1 else: listA = self.list2 if self.typeList1 == ListBioType.TypeB: listB = self.list1 else: listB = self.list2 try: listComp = ListComparator(listA, listB, self.entryPVal.get(), self.entryFoldC.get(), self.entryNote.get()) for e in listComp.getDiffAandB(): self.tree.insert('', 'end', values=e) except IndexError: showerror("Erreur : liste A ou B invalide", "Le fichier liste A ou B n'est pas un fichier valide") # (List A and List A) elif ((self.list1 is not None and self.typeList1 == ListBioType.TypeA) and \ (self.list2 is not None and self.typeList2 == ListBioType.TypeA)): self.resetTree() try: listComp = ListComparator(self.list1, self.list2, self.entryPVal.get(), self.entryFoldC.get(), self.entryNote.get()) for e in listComp.getDiffAandA(): self.tree.insert('', 'end', values=e) except IndexError: showerror("Erreur : liste A ou B invalide", "Le fichier liste A ou B n'est pas un fichier valide") # (List B and List B) elif ((self.list1 is not None and self.typeList1 == ListBioType.TypeB) and \ (self.list2 is not None and self.typeList2 == ListBioType.TypeB)): self.resetTree() try: listComp = ListComparator(self.list1, self.list2, self.entryPVal.get(), self.entryFoldC.get()) for e in listComp.getDiffBandB(): self.tree.insert('', 'end', values=e) except IndexError: showerror("Erreur : liste A ou B invalide", "Le fichier liste A ou B n'est pas un fichier valide") else: showerror("Erreur : Combinaisons de listes invalides", "Votre choix de types de listes ne correspond à aucune combinaison possible, contacter le developpeur") def export(self): if len(self.tree.get_children()) == 0: showinfo("Export", "Il n'y a rien à exporter") return fname = asksaveasfilename(filetypes=(("CSV files", "*.csv"), ("All files", "*.*") )) if fname: resExp = [] for it in self.tree.get_children(): resExp.append(self.tree.item(it)["values"]) expTabToCSV = TreeExportator(resExp, fname) expTabToCSV.export() showinfo("Export", "Exportation au format CSV réussi") def columnSort (self, col, descending=False): data = [(self.tree.set(child, col), child) for child in self.tree.get_children('')] data.sort(reverse=descending) for indx, item in enumerate(data): self.tree.move(item[1], '', indx) # reverse sort direction for next sort operation self.SortDir = not descending
class GUI: def __init__(self): self.root = Tk() self.right_frame = Frame(self.root) self.left_frame = Frame(self.root) self.image = None self.scrollbarx = Scrollbar(self.left_frame, orient=HORIZONTAL) self.scrollbary = Scrollbar(self.left_frame, orient=VERTICAL) self.tree = None self.files = {} self.tree_index = None self.selected_item = None self.test_data_creator = TestDataCreator() self.char_images = [] self.index = 0 self.panel = None self.buttons = {} def create_root(self): self.root.title('Data Creator') w = 720 h = 450 sw = self.root.winfo_screenwidth() sh = self.root.winfo_screenheight() x = (sw - w) / 2 y = (sh - h) / 2 self.root.geometry('%dx%d+%d+%d' % (w, h, x, y)) self.root.resizable(False, False) self.add_left_frame() self.add_buttons() self.left_frame.pack(side=LEFT) self.right_frame.pack(side=RIGHT) def add_buttons(self): self.panel = Label(self.right_frame, image=self.image) self.panel.pack(side=TOP) digit_frame = Frame(self.right_frame) for i in [str(i) for i in range(10)]: button_digit = Button(digit_frame, text=i, width=3) button_digit.bind('<Button-1>', self.button_click) button_digit.pack(side=LEFT, padx=2.) digit_frame.pack(pady=5) alpha_frame = Frame(self.right_frame) for i in ['A', 'B', 'E', 'K', 'M', 'H', 'O', 'P', 'C', 'T', 'Y', 'X']: button_alpha = Button(alpha_frame, text=i, width=3) button_alpha.bind('<Button-1>', self.button_click) button_alpha.pack(side=LEFT, padx=2.) alpha_frame.pack(pady=5) button_nothing = Button(self.right_frame, text='-', width=10) button_nothing.bind('<Button-1>', self.button_click) button_nothing.pack() def create_tree(self): if self.tree: self.tree.destroy() style = Style(self.left_frame) style.configure('Calendar.Treeview', rowheight=50) self.tree = Treeview(self.left_frame, columns='#1', height=400, selectmode="extended", yscrollcommand=self.scrollbary.set, xscrollcommand=self.scrollbarx.set, style='Calendar.Treeview') self.scrollbary.config(command=self.tree.yview) self.scrollbary.pack(side=RIGHT, fill=Y) self.scrollbarx.config(command=self.tree.xview) self.scrollbarx.pack(side=BOTTOM, fill=X) self.tree.heading('#0', text='image', anchor=CENTER) self.tree.heading('#1', text='file_name') self.tree.column('#0', width=80, anchor=CENTER) if self.files: for key in self.files: self.tree.insert("", 'end', values=key, image=self.files[key]) self.tree.pack(side=BOTTOM) def add_left_frame(self): load_button = Button(self.left_frame, text="load files", command=self.load_files) load_button.pack(side=TOP, anchor=NW, pady=5) start_button = Button(self.left_frame, text='Start recognition', command=self.run) start_button.pack(side=TOP, anchor=NW) self.create_tree() def load_files(self): file_names = fd.askopenfilenames( filetypes=[('Image file', '*.png'), ('Image file', '*.jpg'), ('Image file', '*.jpeg')]) for file in file_names: self.files[file] = ImageTk.PhotoImage( Image.open(file).resize((60, 40))) self.create_tree() def button_click(self, event): image_name = event.widget.cget('text') if image_name != '-': self.test_data_creator.multiply_image(self.char_images[self.index], image_name) self.index += 1 if self.index >= len(self.char_images): del self.files[self.selected_item] mb.showinfo("Recognition", "Characters are over!") self.image = None self.create_tree() else: self.image = ImageTk.PhotoImage( Image.fromarray(self.char_images[self.index].image).resize( (120, 200))) self.panel.configure(image=self.image) def run(self): index = self.tree.selection() if not index: mb.showinfo("Choice image", "Not selected item") return index = index[0] self.selected_item = ' '.join(self.tree.item(index)['values']) self.char_images = self.test_data_creator.start(self.selected_item) self.index = 0 if not self.char_images: mb.showerror("Recognition", "Car numbers not recognized") del self.files[self.selected_item] self.create_tree() self.image = None else: self.image = ImageTk.PhotoImage( Image.fromarray(self.char_images[self.index].image).resize( (120, 200))) self.panel.configure(image=self.image)
class Tree(LibraryListener): def __init__(self, config, master): self.views = config['views'] self.library = None self.__make_widgets(master) def __make_widgets(self, root): self.tree = Treeview(root) def on_library_change(self, library): self.library = library self.__make_root_nodes() def __make_root_nodes(self): for i in self.tree.get_children(): self.tree.delete(i) root_nodes = self.query_library({}, self.views[0]) for node in root_nodes: child = self.tree.insert("", "end", self.__make_node_id(None, self.views[0], node), text=node, tags=self.views[0]) self.fetch_children(child) @staticmethod def __make_node_id(parent_node, node_type, node_value): node_id = {} if parent_node: node_id = copy(parent_node) node_id[node_type] = node_value return node_id def can_be_expanded(self, node_type): return node_type != self.views[len(self.views) - 1] def get_child_node_type(self, node_type): return self.views[self.views.index(node_type) + 1] def query_library(self, node_id, view): return self.library.aggregate(node_id, view) def __has_children(self, node): return len(self.children(node)) > 0 def fetch_children(self, node): if not self.__has_children(node): node_type = self.tree.item(node, "tags")[0] if self.can_be_expanded(node_type): children_node_type = self.get_child_node_type(node_type) node_id = literal_eval(node) nodes = self.query_library(node_id, children_node_type) for child_node in nodes: self.tree.insert(node, "end", self.__make_node_id(node_id, children_node_type, child_node), text=child_node, tags=children_node_type) def delete_children(self, parent_node): children = self.children(parent_node) for node in children: self.tree.delete(node) @property def selected_node(self): if len(self.tree.selection()): return self.tree.selection()[0] def children(self, node): return self.tree.get_children(node)
text=col.title(), command=lambda c=col: sort_by(tree, c, 0)) #tree.column(col,stretch=True) #tree.column(col,width=font.nametofont('TkHeadingFont').measure(col.title()), #stretch=False) tree.column( col, width=font.Font(family=font_family, size=font_size, weight='bold').measure(col.title()) + 10, stretch=False) #print(tree.column(col)) # insert data row by row, then measure each items' width for ix, item in enumerate(tree_data): item_ID = tree.insert('', 'end', values=item) tree.item(item_ID, tags=item_ID) tree.tag_configure(item_ID, background=backg[ix % 2]) for indx, val in enumerate(item): #ilen = font.Font(family="Segoe UI", size=10, weight="normal").measure(val) ilen = font.nametofont('TkDefaultFont').measure(val) if tree.column(tree_columns[indx], width=None) < ilen + 10: tree.column(tree_columns[indx], width=ilen + 10) # you should see the widths adjust #print('col',tree.column(tree_columns[indx]),ilen) # display selection lvar = StringVar() lbl = Label(fr0, textvariable=lvar, text="Ready") lbl.grid(column=0, row=1, sticky='nsew')
class FacultyDelWindow: def __init__(self, data=''): self.data = data print(self.data) self.win = Tk() self.canvas = Canvas(self.win, width=800, height=420, bg='white') self.canvas.pack(expand=YES, fill=BOTH) # show window in center of the screen width = self.win.winfo_screenwidth() height = self.win.winfo_screenheight() x = int(width / 2 - 800 / 2) y = int(height / 2 - 420 / 2) str1 = "800x420+" + str(x) + "+" + str(y) self.win.geometry(str1) # disable resize window self.win.resizable(False, False) # changing title of the window self.win.title( "| DELETING FACULTY DETAILS | LIBRARY MANAGEMENT SYSTEM |") def add_frame(self): self.frame = Frame(self.win, height=420, width=800) self.frame.place(x=0, y=0) x, y = 0, 0 self.label = Label(self.frame, text="DELETING FACULTY DETAILS", fg='black') self.label.config(font=("Poppins", 20, 'underline bold')) self.label.place(x=190, y=35) # use tree view to show details from the table self.tr = Treeview(self.frame, columns=('FACULTY_ID', 'FACULTY_NAME', 'GENDER', 'DEPARTMENT', 'CONTACT_NO'), selectmode="extended") # heading key + text self.tr.heading('#0', text='FACULTY_ID') self.tr.column('#0', minwidth=0, width=100, stretch=NO) self.tr.heading('#1', text='FACULTY_NAME') self.tr.column('#1', minwidth=0, width=100, stretch=NO) self.tr.heading('#2', text='GENDER') self.tr.column('#2', minwidth=0, width=100, stretch=NO) self.tr.heading('#3', text='DEPARTMENT') self.tr.column('#3', minwidth=0, width=100, stretch=NO) self.tr.heading('#4', text='CONTACT_NO') self.tr.column('#4', minwidth=0, width=100, stretch=NO) self.tr.heading('#5', text='DELETE') self.tr.column('#5', minwidth=0, width=100, stretch=NO) # self.tr.heading('#6', text='DELETE') # self.tr.column('#6', minwidth=0, width=100, stretch=NO) j = 0 for i in Database.database.Faculties(): self.tr.insert('', index=j, text=i[0], values=(i[1], i[2], i[3], i[4], 'DELETE')) j += 1 # create action on deletion self.tr.bind('<Double-Button-1>', self.actions) self.tr.place(x=100, y=y + 100) self.win.mainloop() def actions(self, e): # get the value of deleted row tt = self.tr.focus() # get the column id col = self.tr.identify_column(e.x) print(col) print(self.tr.item(tt)) data = (self.tr.item(tt).get('text'), ) if col == '#5': res = messagebox.askyesno("Message", "Do you want to delete..!") if res: d = Database.database.DeleteFaculty(data) if d: messagebox.showinfo( "Message", "Faculty Details deleted successfully..!") self.win.destroy() x = Thirdpage else: self.win.destroy() x = Student.DeleteFaculty.FacultyDelWindow() x.add_frame()
class StructEditor(tk.Frame, Subscriber, Observable): """Displays and allow editing of the coordinates and points of one superstructure Args: parent (tk.Frame): widget that is the parent of the editor structure (model.structure.Structure): the ship superstructure that will be edited """ def __init__(self, parent, structure, command_stack): Subscriber.__init__(self, structure) Observable.__init__(self) tk.Frame.__init__(self, parent, borderwidth=4, relief="raised") self._structure = structure self._command_stack = command_stack self.bind("<Button-1>", self._on_click) self.bind("<FocusIn>", self._on_get_focus) self.bind("<FocusOut>", self._on_lost_focus) self._tree = Treeview(self, columns=["#", "X", "Y"], selectmode="browse") #kill the icon column self._tree.column("#0", minwidth=0, width=0) style = Style() style.configure("Treeview.Heading", font=(None, 16)) self._tree.column("#", minwidth=20, width=40, anchor=tk.CENTER) self._tree.column("X", minwidth=20, width=40, anchor=tk.CENTER) self._tree.column("Y", minwidth=20, width=40, anchor=tk.CENTER) self._tree.heading("#", text="#") self._tree.heading("X", text="\u21d5") self._tree.heading("Y", text="\u21d4") self._tree.grid(row=0, column=POINTS_TABLE_COL, sticky=tk.N + tk.S) self._tree.bind("<<TreeviewSelect>>", self._on_point_selected) self._tree.bind("<FocusIn>", self._on_get_focus) self._tree.bind("<FocusOut>", self._on_lost_focus) scroll = Scrollbar(self, command=self._tree.yview) scroll.grid(row=0, column=SCROLL_COL, sticky=tk.N + tk.S) scroll.bind("<FocusIn>", self._on_get_focus) self._tree.configure(yscrollcommand=scroll.set) self._index_of_sel_point = -1 self._fill_tree() self._edit_zone = EditZone(self, self._structure, command_stack, self._on_get_focus) self._edit_zone.grid(column=EDIT_ZONE_COL, row=0, sticky=tk.N) def _set_selection(self, new_sel_index): """Set the selected point to the new_sel_index Gives correct focus, update, etc to the editor's widgets if the index is outside of the self.points, does nothing """ if new_sel_index >= 0 and new_sel_index <= len(self.points) - 1: iid = self._tree.get_children()[new_sel_index] self._tree.selection_set(iid) def _on_click(self, *_args): self._tree.focus_set() def _on_get_focus(self, *_args): if self._index_of_sel_point == -1: self._set_selection(0) self.configure(relief="sunken") self._notify("focus", {}) def _on_lost_focus(self, event): if event.widget not in self.winfo_children(): self.configure(relief="raised") def _on_point_selected(self, _event): """called back when a point is selected in the table/treeview Updates the editable fields """ selected_iid = self._tree.selection() self._index_of_sel_point = self._tree.index(selected_iid) self._edit_zone.set_editable_point( self._tree.item(selected_iid)["values"][0]) self._notify("focus", {}) def _fill_tree(self): """fills the treeview with data from the structure """ self._tree.delete(*self._tree.get_children()) for point_index, point in enumerate(self._structure.points): self._tree.insert( '', 'end', values=[point_index, round(point[0]), round(point[1])]) if point_index == self._index_of_sel_point: self._set_selection(point_index) def _on_notification(self, observable, event_type, event_info): """Rebuild the treeview on structure update Depending on the structure state and the operation, change the selcted point """ if event_type == "add_point": self._index_of_sel_point = event_info["index"] self._fill_tree() else: if self._index_of_sel_point >= len(self._structure.points): self._index_of_sel_point = len(self._structure.points) self._edit_zone.unset_point() self._fill_tree() self._notify("focus", {}) def update_to_coord(self, point): """Move the selected point to the position of the given point Intended to be called from click on the top view Args: point (x, y): new position in funnel coordinates """ if self._index_of_sel_point != -1 and self._index_of_sel_point <= len( self.points) - 1: self._command_stack.do( model.structure.UpdatePoint(self._structure, self._index_of_sel_point, round(point[0]), round(point[1]))) elif self._index_of_sel_point == len(self.points) or not self.points: self._command_stack.do( model.structure.AddPoint(self._structure, self._index_of_sel_point + 1, round(point[0]), round(point[1]))) if self._index_of_sel_point + 1 >= len(self.points): self.winfo_toplevel().update() self._index_of_sel_point = len(self.points) else: self._set_selection(self._index_of_sel_point + 1) self.winfo_toplevel().update() @property def points(self): """Pipe throught the struct's properties""" return self._structure.points @property def fill(self): """Pipe throught the struct's properties""" return self._structure.fill @property def selected_index(self): """the index in the struct's point list of the currently selected point Should be -1 if none selected """ return self._index_of_sel_point
class My_Tk(): def __init__(self, root, user_info=None, cookies=None, headers=None, tasklist_=None): self.tk = root self.user_info = user_info self.base_cookies = cookies self.base_headers = headers # self.tk.geometry('620x400') self.orm = {} self.val_map = {} self.create_button() self.create_heading() self.create_tv() self.tasklist_ = tasklist_ def create_button(self): frame = Frame(self.tk, width=200, height=50) frame.pack(fill=X, side=TOP) Button(frame, text='下载', width=6, command=self.download).place(x=28, y=21) # Button(frame, text='测试数据', command=self.insert_test_tree_data).pack(side=LEFT, anchor='w') Button(frame, text='清除列表', command=self.clear_tree_data).place(x=82, y=21) def get_tv(self): return self.tv def download(self): try: for k, v in self.orm.items(): button = self.orm[k][0] button_value = button.getvar(button['variable']) if button_value == '1': print(self.tv.item(k, 'values')) if self.user_info == None or len(self.user_info) == 0: messagebox.showinfo(title="提示", message="请先登录!") return else: media_type = self.tasklist_.media_type_var.get() if media_type and media_type == ".mp4": params = { 'fragmentId': self.val_map[k] + 1, 'token': self.user_info['token'], 'albumId': -8888888, 'programId': -8888888 } else: params = { 'fragmentId': self.val_map[k], 'token': self.user_info['token'], 'albumId': 0, 'programId': 0 } self.base_headers["Host"] = "api.dushu.io" response = requests.post( url="http://api.dushu.io/fragment/content", json=params, headers=self.base_headers, cookies=self.base_cookies) response_data = response.json() mediaUrls = response_data["mediaUrls"] mediaUrl = None if mediaUrls and type( mediaUrls) == list and len(mediaUrls) > 0: if len(mediaUrls) > 1: if media_type == r".mp4": for url_ in mediaUrls: if url_.find("video") != -1: mediaUrl = url_ elif media_type == r".mp3": media_type = r".mp3" for url_ in mediaUrls: if url_.find("audio") != -1: mediaUrl = url_ elif mediaUrls[0].find("audio") != -1: if media_type == '.mp4': messagebox.showinfo( title="提示", message="该资源只有音频,请在任务列表切换下载类型!") return else: mediaUrl = response_data['mediaUrls'][0] elif mediaUrls[0].find("video") != -1: mediaUrl = response_data['mediaUrls'][0] else: return else: return if media_type == '.mp3': file_name = response_data['title'] else: file_name = response_data['bookName'] print(mediaUrl) media_info_headers = {} if (mediaUrl.startswith("https")): mediaUrl = "http" + mediaUrl[5:] host_pattern = re.compile("\w+://(.*?)/.*") host_ = host_pattern.findall(mediaUrl)[0] if host_ != "cdn-ali.dushu.io": media_info_headers = { 'Host': "v-cc.dushu.io", 'Cookie': "grwng_uid=e7e51c80-ead6-43bb-9744-7531778d6c73; UM_distinctid=16be039d03e8aa-0f0e963eb0f589-621c740a-4a640-16be039d03f633; gr_user_id=ebc67f00-d109-4c29-80b0-7d631382debf", 'X-Playback-Session-Id': "A078D569-3595-4399-8240-EB42F542F073", 'Connection': "keep-alive, keep-alive", 'Accept': "*/*", 'User-Agent': "AppleCoreMedia/1.0.0.16D57 (iPhone; U; CPU OS 12_1_4 like Mac OS X; en_us)", 'Accept-Language': "en-us", 'Accept-Encoding': "gzip", 'cache-control': "no-cache" } else: media_info_headers = { 'Host': "cdn-ali.dushu.io", 'Cookie': "grwng_uid=e7e51c80-ead6-43bb-9744-7531778d6c73; UM_distinctid=16be039d03e8aa-0f0e963eb0f589-621c740a-4a640-16be039d03f633; gr_user_id=ebc67f00-d109-4c29-80b0-7d631382debf", 'X-Playback-Session-Id': "A9D630B7-54FF-4514-923C-A561AFA5C7BA", 'Range': "bytes=0-1", 'Accept': "*/*", 'User-Agent': "AppleCoreMedia/1.0.0.16D57 (iPhone; U; CPU OS 12_1_4 like Mac OS X; en_us)", 'Accept-Language': "en-us", 'Accept-Encoding': "identity", 'Connection': "keep-alive", 'cache-control': "no-cache", } media_info_headers["Range"] = "bytes=0-1" media_info_headers['Host'] = host_ media_info = requests.get(url=mediaUrl, headers=media_info_headers, cookies=self.base_cookies) file_des = self.tasklist_.download_dir.get( ) + r"\\" + file_name + media_type bytes_length = 0 if "Content-Range" in media_info.headers: range_ = media_info.headers['Content-Range'] bytes_length = range_[range_.rfind('/') + 1:] elif host_ == "cdn-ali.dushu.io": with open(file_des, "wb") as saved: saved.write(bytes(media_info.content)) return def down(): try: row = [ str(datetime.now().strftime( "%Y%m%d%H%M%S")), file_name + media_type, datetime.now().strftime( "%Y-%m-%d %H:%M:%S"), self.tasklist_.catch_progress_bar(), StringVar(value="0") ] with open(file_des, 'wb') as saved: self.tasklist_.insert_data(row) media_info_content = media_info.content play_list_pattern = re.compile( "(\w+\.mp4_[\d]+\.ts)", re.DOTALL) play_list = [] if type(media_info_content) != str: play_list = play_list_pattern.findall( str(media_info_content)) threading.Thread( target=lambda: { messagebox.showinfo( title="提示", message="请前往任务列表查看下载状态") }).start() if play_list != None and len( play_list) == 0: if int(bytes_length) <= 0: return print(type(bytes_length)) count = (int(bytes_length) + 1 - 131072) / 131072 print(count) print(type(count)) tmp = 0 for index in range(int(count)): if index == count - 1: media_info_headers[ 'Range'] = "bytes=" + str( index * 131072 ) + "-" + str(bytes_length) else: media_info_headers[ 'Range'] = "bytes=" + str( index * 131072) + "-" + str( (index + 1) * 131072 - 1) media_content = requests.get( url=mediaUrl, headers=media_info_headers, cookies=self.base_cookies) saved.write( bytes(media_content.content)) tmp = tmp + 1 print(count) if (tmp > count / 100): print(tmp) self.tasklist_.progress( row[3], index / count * 164 ) # 比其所在canvas宽度小1,百分之99即撑满整个进度条 tmp = 0 row[4].set( str(int(index / count * 100)) + "%") print("*************downloading" + str(index / count * 100) + "%************") else: for index, play_url in enumerate( play_list): tmp_media_url = mediaUrl[:mediaUrl. rfind("/" ) + 1] + play_url[ 1:] response = requests.get( url=tmp_media_url, headers=media_info_headers, cookies=self.base_cookies) if response.status_code == 200: saved.write( bytes(response.content)) self.tasklist_.progress( row[3], index / len(play_list) * 164 ) # 比其所在canvas宽度小1,百分之99即撑满整个进度条 print( "*************downloading" + str(index / len(play_list) * 100) + "%**************") row[4].set( str( int(index / len(play_list) * 100)) + "%") except BaseException as e: row[4].set("失败") row.pop(3) self.tasklist_.append_download_history(row) messagebox.showinfo("错误", message=str(e)) else: row[4].set("100%") row.pop(3) self.tasklist_.append_download_history(row) messagebox.showinfo("提示", message=file_name + "下载完成!") th = threading.Thread(target=down) th.setDaemon(True) th.start() print(self.val_map[k]) except BaseException as e: print(e) traceback.print_exc(file=open('error.txt', 'a+')) messagebox.showerror("提示", message="下载出错") print("下载出错") def create_heading(self, ): '''重新做一个treeview的头,不然滚动滚动条,看不到原先的头!!!''' heading_frame = Frame(self.tk) heading_frame.pack(fill=X) # 填充用 # button_frame = Label(heading_frame,bg='gray') # button_frame.pack(side=LEFT, expand=False) # 全选按钮 self.all_buttonvar = IntVar() self.all_button = Checkbutton(heading_frame, text='', variable=self.all_buttonvar, command=self.select_all) self.all_button.pack(side=LEFT) self.all_buttonvar.set(0) self.columns = ['no', 'name', 'author'] self.columns_header_name = ['序号', '名称', '作者'] self.header_label_widths = [40, 260, 100] self.colums_header_widths = [46, 292, 115] # 重建tree的头 for i in range(len(self.columns)): Label(heading_frame, text=self.columns_header_name[i], width=int(self.header_label_widths[i] * 0.16), anchor='center', relief=GROOVE).pack(side=LEFT) def insert_test_tree_data(self): rows = [] for i in range(30): rows.append((i + 1, 'B', 'C', 110)) self.insert_tv(rows) def clear_tree_data(self): self.init_tree() # 初始化表格 def init_tree(self): [self.tv.delete(item) for item in self.tv.get_children()] self.tv.update() for child in self.button_frame.winfo_children(): # 第一个构件是label,所以忽略 child.destroy() self.canvas.itemconfigure(self.tv_frame, height=300) # 设定窗口tv_frame的高度 self.tk.update() self.canvas.config(scrollregion=self.canvas.bbox("all")) # 滚动指定的范围 self.canvas.config(height=300) def create_tv(self): # 放置 canvas、滚动条的frame canvas_frame = Frame(self.tk, width=500, height=400) canvas_frame.pack(fill=X) # 只剩Canvas可以放置treeview和按钮,并且跟滚动条配合 self.canvas = Canvas(canvas_frame, width=400, height=500, scrollregion=(0, 0, 500, 400)) self.canvas.pack(side=LEFT, fill=BOTH, expand=1) # 滚动条 ysb = Scrollbar(canvas_frame, orient=VERTICAL, command=self.canvas.yview) self.canvas.configure(yscrollcommand=ysb.set) ysb.pack(side=RIGHT, fill=Y) # !!!!=======重点:鼠标滚轮滚动时,改变的页面是canvas 而不是treeview self.canvas.bind_all( "<MouseWheel>", lambda event: self.canvas.yview_scroll( int(-1 * (event.delta / 120)), "units")) # 想要滚动条起效,得在canvas创建一个windows(frame)!! tv_frame = Frame(self.canvas) self.tv_frame = self.canvas.create_window(0, 0, window=tv_frame, anchor='nw', width=600, height=400) # anchor该窗口在左上方 # 放置button的frame self.button_frame = Frame(tv_frame) self.button_frame.pack(side=LEFT, fill=Y) Label(self.button_frame, width=3).pack() # 填充用 # 创建treeview self.tv = Treeview(tv_frame, height=10, columns=self.columns, show='tree') # height好像设定不了行数,实际由插入的行数决定 self.tv.column("#0", width=0, stretch=0) self.tv.pack(expand=True, side=LEFT, fill=BOTH) # 设定每一列的属性 for i in range(len(self.columns)): self.tv.column(self.columns[i], width=self.colums_header_widths[i], anchor='w', stretch=False) # 设定treeview格式 # import tkinter.font as tkFont # ft = tkFont.Font(family='Fixdsys', size=20, weight=tkFont.BOLD) self.tv.tag_configure('oddrow', font='黑体 8') # 设定treeview里字体格式font=ft self.tv.tag_configure('select', background='SkyBlue', font='Arial 8') # 当对应的按钮被打勾,那么对于的行背景颜色改变! self.rowheight = 27 # 很蛋疼,好像tkinter里只能用整数! Style().configure('Treeview', rowheight=self.rowheight) # 设定每一行的高度 # 设定选中的每一行字体颜色、背景颜色 (被选中时,没有变化) Style().map("Treeview", foreground=[ ('focus', 'black'), ], background=[('active', 'white')]) self.tv.bind('<<TreeviewSelect>>', self.select_tree) # 绑定tree选中时的回调函数 def insert_tv(self, rows=None): if rows == None: rows = [] for i in range(20): item = (i + 1, 'A', "B") rows.append(item) # 清空tree、checkbutton items = self.tv.get_children() [self.tv.delete(item) for item in items] self.tv.update() for child in self.button_frame.winfo_children(): # 第一个构件是label,所以忽略 child.destroy() # 重设tree、button对应关系 self.orm = {} index = 0 for row in rows: tv_item = self.tv.insert('', index, value=row[0:3], tags=('oddrow')) # item默认状态tags import tkinter ck_button = tkinter.Checkbutton(self.button_frame, variable=IntVar()) ck_button['command'] = lambda item=tv_item: self.select_button(item ) ck_button.pack() # ck_button['fragementId']=row[3] self.orm[tv_item] = [ck_button] self.val_map[tv_item] = row[3] index = index + 1 # 每次点击插入tree,先设定全选按钮不打勾,接着打勾并且调用其函数 self.all_buttonvar.set(0) self.all_button.invoke() # 更新canvas的高度 height = (len(self.tv.get_children()) + 1) * self.rowheight # treeview实际高度 self.canvas.itemconfigure(self.tv_frame, height=height) # 设定窗口tv_frame的高度 self.tk.update() self.canvas.config(scrollregion=self.canvas.bbox("all")) # 滚动指定的范围 self.canvas.config(height=height) def select_all(self): '''全选按钮的回调函数 作用:所有多选按钮打勾、tree所有行都改变底色(被选中)''' for item, [button] in self.orm.items(): if self.all_buttonvar.get() == 1: button.select() self.tv.item(item, tags='select') else: button.deselect() self.tv.item(item, tags='oddrow') def select_button(self, item): '''多选按钮的回调函数 作用:1.根据按钮的状态,改变对应item的底色(被选中) 2.根据所有按钮被选的情况,修改all_button的状态''' button = self.orm[item][0] button_value = button.getvar(button['variable']) if button_value == '1': self.tv.item(item, tags='select') else: self.tv.item(item, tags='oddrow') self.all_button_select() # 根据所有按钮改变 全选按钮状态 def select_tree(self, event): '''tree绑定的回调函数 作用:根据所点击的item改变 对应的按钮''' select_item = self.tv.focus() button = self.orm[select_item][0] button.invoke() # 改变对应按钮的状态,而且调用其函数 def all_button_select(self): '''根据所有按钮改变 全选按钮状态 循环所有按钮,当有一个按钮没有被打勾时,全选按钮取消打勾''' for [button] in self.orm.values(): button_value = button.getvar(button['variable']) if button_value == '0': self.all_buttonvar.set(0) break else: self.all_buttonvar.set(1)
class TestcaseSelector: def start(self): # Create TK window self.root = Tk() # Create Style object for TK window self.root.style = Style() # Set default frame size to 800x640 self.root.geometry('800x640') # Set Treeview row height to 40 so there's no overlap self.root.style.configure('Treeview',rowheight=40) # Set title and window size self.root.wm_title("Select Testcases to Run") # Create a frame for the treeview self.testcase_frame = Frame(self.root) # Create scrollbar for treeview scrollbar = Scrollbar(self.root) scrollbar.pack(side=RIGHT,fill=Y) # Create Treeview self.treeView = Treeview(self.testcase_frame) self.treeView.pack(expand=1,fill=BOTH) # Attach scrollbar to Treeview self.treeView.config(yscrollcommand=scrollbar.set) scrollbar.config(command=self.treeView.yview) # Get testcase name dictionary to use for filling out treeview testcase_dictionary = get_testcase_name_dictonary() self.testcase_data = {} self.testcase_run_data = {} for key in testcase_dictionary.keys(): subsection = testcase_dictionary[key] self.testcase_data[key] = subsection s_p = self.treeView.insert('', END, text=key) for test in subsection: testcase_name = test._testMethodName testcase_name = testcase_name self.treeView.insert(s_p, END, text=testcase_name) self.testcase_run_data[testcase_name] = test self.webData = self.testcase_run_data # Create buttons for cancel and run tests run_button = Button(self.testcase_frame, text="Run", fg="green",command=self._save_selection,width=25,height=5) run_button.pack(side=LEFT,expand=1,fill=BOTH) quit_button = Button(self.testcase_frame, text="Cancel", fg="red", command=self.treeView.quit,width=25,height=5) quit_button.pack(side=RIGHT,expand=1,fill=BOTH) # Pack the rest of the frame and tell it to scale on both x and y axis self.testcase_frame.pack(expand=1,fill=BOTH) def get_tests_from_selected_names(self,names): ret_tests = {} for name in names: ret_tests[name] = self.webData[name] return ret_tests def _save_selection(self): selected_tests = self.treeView.selection() output=[] for selection in selected_tests: item_text = self.treeView.item(selection,'text') if 'test_' in item_text: if item_text not in output: output.append(item_text) else: pass elif 'Tests' in item_text: for test in self.testcase_data[item_text]: output.append(test._testMethodName) # output = output + self.testSectionData[item_text] self.testcases = self.get_tests_from_selected_names(output) self.root.quit() def get_testcases(self): self.start() self.root.mainloop() self.root.destroy() # Try/Except to fail gracefully try: return self.testcases except: exit(0)
class Cerberus: def __init__(self, master, root): self.exportToCSV = False self.versionApp, self.key, self.salt = self.initApp() self.key = cerberusCryptography.getMasterKey() self.cipher_suite = Fernet(self.key) self.master = master self.master.title('Cerberus') self.windowWidth = 1060 self.windowHeight = 450 self.screenWidth = self.master.winfo_screenwidth() self.screenHeight = self.master.winfo_screenheight() self.positionRight = int(self.screenWidth / 2 - self.windowWidth / 2) self.positionDown = int(self.screenHeight / 3 - self.windowHeight / 2) self.master.geometry("{}x{}+{}+{}".format(self.windowWidth, self.windowHeight, self.positionRight, self.positionDown)) self.img = PhotoImage(data=icons.getAppIcon()) self.master.wm_iconphoto(True, self.img) self.master.resizable(0, 0) self.menubar = Menu(master) filemenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Cerberus", menu=filemenu) self.addIcon = PhotoImage(data=icons.getAddIcon()) filemenu.add_command(label="Εισαγωγή Υπηρεσίας", image=self.addIcon, compound='left', command=self.getAddNewServiceForm) self.editIcon = PhotoImage(data=icons.getEditIcon()) filemenu.add_command(label="Επεξεργασία Υπηρεσίας", image=self.editIcon, compound='left', command=self.getEditServiceForm) self.deleteIcon = PhotoImage(data=icons.getDeleteIcon()) filemenu.add_command(label="Διαγραφή Υπηρεσίας", image=self.deleteIcon, compound='left', command=self.deleteService) filemenu.add_separator() self.excelIcon = PhotoImage(data=icons.getExcelIcon()) filemenu.add_command(label="Εξαγωγή σε Excel", image=self.excelIcon, compound='left', command=self.checkPasswordToExportToCSV) filemenu.add_separator() self.exitIcon = PhotoImage(data=icons.getExitIcon()) filemenu.add_command(label="Έξοδος", image=self.exitIcon, compound='left', command=self.exitApp) settingsMenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Ρυθμίσεις", menu=settingsMenu) self.settingsIcon = PhotoImage(data=icons.getSettingsIcon()) settingsMenu.add_command(label="Επεξεργασία Στοιχείων", image=self.settingsIcon, compound='left') #command=self.getSettingsForm) aboutMenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Βοήθεια", menu=aboutMenu) self.infoIcon = PhotoImage(data=icons.getInfoIcon()) aboutMenu.add_command(label="Περί", image=self.infoIcon, compound='left', command=self.getAboutAppForm) self.master.config(menu=self.menubar) self.copyIcon = PhotoImage(data=icons.getCopyIcon()) self.popup = Menu(root, tearoff=0) self.popup.add_command(label=" Αντιγραφή Email", image=self.copyIcon, compound='left', command=self.copyEmail) self.popup.add_command(label=" Αντιγραφή Username", image=self.copyIcon, compound='left', command=self.copyUsername) self.popup.add_command(label=" Αντιγραφή Κωδικού", image=self.copyIcon, compound='left', command=self.copyPasswd) self.popup.add_command(label=" Αντιγραφή ID", image=self.copyIcon, compound='left', command=self.copyID) self.popup.add_separator() self.popup.add_command(label=" Επεξεργασία Υπηρεσίας", image=self.editIcon, compound='left', command=self.getEditServiceForm) self.popup.add_command(label=" Διαγραφή Υπηρεσίας", image=self.deleteIcon, compound='left', command=self.deleteService) self.popup.add_separator() self.popup.add_command(label=" Έξοδος", image=self.exitIcon, compound='left', command=self.exitApp) self.frame = Frame(self.master, background="white", borderwidth=1, relief="sunken", highlightthickness=1) self.frame.pack(side="top", fill="x", padx=4, pady=4) self.search = StringVar() self.searchEntry = Entry(self.frame, textvariable=self.search, borderwidth=0, highlightthickness=0, background="white") self.searchEntry.insert(0, 'Αναζήτηση Υπηρεσίας') self.searchEntry['fg'] = 'grey' self.search.trace( "w", lambda name, index, mode, sv=self.search: self.searchService()) self.searchEntry.image = PhotoImage(data=icons.getSearchIcon()) imageLabel = Label(self.frame, image=self.searchEntry.image) imageLabel.pack(side="left") imageLabel['bg'] = 'white' self.searchEntry.pack(side="left", fill="both", expand=True) # Fix BUG with Treeview colors in Python3.7 def fixed_map(option): return [ elm for elm in style.map('Treeview', query_opt=option) if elm[:2] != ('!disabled', '!selected') ] style = ttk.Style(root) style.map('Treeview', foreground=fixed_map('foreground'), background=fixed_map('background')) # Fix BUG with Treeview colors in Python3.7 self.table = Treeview(self.master) self.table['show'] = 'headings' self.table['columns'] = ('Services', 'email', 'username', 'passwd', 'id', 'category', 'url', 'ID') self.table["displaycolumns"] = ('Services', 'email', 'username', 'passwd', 'id', 'category', 'url') for col in self.table['columns']: self.table.heading( col, command=lambda c=col: self.sortby(self.table, c, 0)) self.table.heading('Services', text='Services') self.table.column('Services', anchor='center', width=200) self.table.heading('email', text='Email') self.table.column('email', anchor='center', width=200) self.table.heading('username', text='Username') self.table.column('username', anchor='center', width=100) self.table.heading('passwd', text='Password') self.table.column('passwd', anchor='center', width=100) self.table.heading('url', text='URL') self.table.column('url', anchor='center', width=120) self.table.heading('id', text='ID') self.table.column('id', anchor='center', width=100) self.table.heading('category', text='Category') self.table.column('category', anchor='center', width=100) self.table.heading('ID', text='ID') self.table.column('ID', anchor='center', width=200) self.table.tag_configure('oddrow', background='#e6eef2') self.table.tag_configure('evenrow', background='#b3cfdd') self.table.tag_configure('focus', background='#c6b6b4') self.last_focus = None self.last_focus_tag = None self.table.focus() self.table.pack(fill=BOTH, expand=1) self.table.bind("<<TreeviewSelect>>", self.onTableSelect) self.table.bind("<ButtonRelease-1>", self.openURLService) self.table.bind("<Motion>", self.changePointerOnHover) self.table.bind("<Button-3>", self.popupMenu) self.searchEntry.bind("<FocusIn>", self.foc_in) self.searchEntry.bind("<FocusOut>", self.foc_out) self.popup.bind("<FocusOut>", self.popupFocusOut) self.master.protocol("WM_DELETE_WINDOW", self.exitApp) self.loadTable(self) self.master.bind("<Escape>", self.exitApp) def popupFocusOut(self, event=None): self.popup.unpost() def foc_in(self, *args): if self.search.get() == 'Αναζήτηση Υπηρεσίας': self.searchEntry.delete('0', 'end') self.searchEntry['fg'] = 'black' def foc_out(self, *args): if not self.search.get(): self.searchEntry.insert(0, 'Αναζήτηση Υπηρεσίας') self.searchEntry['fg'] = 'grey' self.loadTable(self) def changePointerOnHover(self, event): _iid = self.table.identify_row(event.y) if _iid != self.last_focus: if self.last_focus: self.table.item(self.last_focus, tags=[self.last_focus_tag]) self.last_focus_tag = self.table.item(_iid, "tag") self.table.item(_iid, tags=['focus']) self.last_focus = _iid curItem = self.table.item(self.table.identify('item', event.x, event.y)) if curItem['values'] != '': col = self.table.identify_column(event.x) url = curItem['values'][int(col[-1]) - 1] if col[-1] == "7" and url != '---': self.master.config(cursor="hand2") else: self.master.config(cursor="") def openURLService(self, event): curItem = self.table.item(self.table.focus()) col = self.table.identify_column(event.x) region = self.table.identify("region", event.x, event.y) if col[-1] == "7" and region != 'heading': url = curItem['values'][int(col[-1]) - 1] if url != '---': webbrowser.open_new_tab('http://' + str(url)) def onTableSelect(self, event): for item in self.table.selection(): item_text = self.table.item(item, "values") print(item_text[0]) def getSelectedService(self, event): for item in self.table.selection(): selectedRow = self.table.item(item, "value") return selectedRow def initApp(self): print("Initialize Cerberus App") try: conn = sqlite3.connect('cerberus.db') except sqlite3.Error as e: print(e) cur = conn.cursor() cur.execute( "SELECT version, masterToken, salt FROM cerberusParameters") row = cur.fetchone() cur.close() return row def copyEmail(self): for item in self.table.selection(): item_text = self.table.item(item, "values") self.master.clipboard_clear() root.clipboard_append(item_text[1]) def copyUsername(self): for item in self.table.selection(): item_text = self.table.item(item, "values") self.master.clipboard_clear() root.clipboard_append(item_text[2]) def copyPasswd(self): for item in self.table.selection(): item_text = self.table.item(item, "values") self.master.clipboard_clear() root.clipboard_append(item_text[3]) def copyID(self): for item in self.table.selection(): item_text = self.table.item(item, "values") self.master.clipboard_clear() root.clipboard_append(item_text[4]) def searchService(self): try: conn = sqlite3.connect('cerberus.db') except sqlite3.Error as e: print(e) cur = conn.cursor() if self.search.get() == 'Αναζήτηση Υπηρεσίας': pass elif self.search.get(): cur.execute( "SELECT id, name, email, username, password, value, category, url FROM service WHERE name LIKE '%" + self.search.get() + "%' or name LIKE '%" + self.search.get().upper() + "%'") # ('%'+self.search.get()+'%',),'Α') elif not self.search.get(): cur.execute( "SELECT id, name, email, username, password, value, category, url FROM service " ) rows = cur.fetchall() cur.close() for k in self.table.get_children(): self.table.delete(k) i = 1 for row in rows: if (i % 2) == 0: tag = "oddrow" else: tag = "evenrow" self.table.insert( '', 'end', values=( row[1], self.cipher_suite.decrypt(row[2]).decode("utf-8").split(), self.cipher_suite.decrypt(row[3]).decode("utf-8").split(), self.cipher_suite.decrypt(row[4]).decode("utf-8").split(), self.cipher_suite.decrypt(row[5]).decode("utf-8").split(), self.cipher_suite.decrypt(row[6]).decode("utf-8").split(), self.cipher_suite.decrypt(row[7]).decode("utf-8").split(), row[0]), tags=tag) i = i + 1 @staticmethod def exitApp(event=None): root.destroy() @staticmethod def getAboutAppForm(): import aboutApp aboutApp.aboutApp() def getAddNewServiceForm(self): self.master.withdraw() import addNewServiceForm addNewServiceForm.addNewServiceForm(self) def getEditServiceForm(self): service = self.getSelectedService(self) if service is None: messagebox.showerror( "Μήνυμα Σφάλματος", "Παρακαλώ επιλέξτε την Υπηρεσία που θέλετε να Επεξεργαστείτε.") else: self.master.withdraw() import editServiceForm editServiceForm.editServiceForm(self, service) def getSettingsForm(self): import settingsForm settingsForm.settingsForm() def sortby(self, tree, col, descending): data = [(tree.set(child, col), child) for child in tree.get_children('')] data.sort(reverse=descending) for ix, item in enumerate(data): if (ix % 2) == 0: tag = "evenrow" else: tag = "oddrow" tree.move(item[1], '', ix) tree.item(item[1], tags=tag) # switch the heading so that it will sort in the opposite direction tree.heading( col, command=lambda x=col: self.sortby(tree, col, int(not descending))) @staticmethod def loadTable(self): try: conn = sqlite3.connect('cerberus.db') except sqlite3.Error as e: print(e) cur = conn.cursor() cur.execute( "SELECT id, name, email, username, password, value, category, url value FROM service" ) rows = cur.fetchall() for row in self.table.get_children(): self.table.delete(row) i = 1 for row in rows: if (i % 2) == 0: tag = "oddrow" else: tag = "evenrow" self.table.insert( '', 'end', values=( row[1], self.cipher_suite.decrypt(row[2]).decode("utf-8").split(), self.cipher_suite.decrypt(row[3]).decode("utf-8").split(), self.cipher_suite.decrypt(row[4]).decode("utf-8").split(), self.cipher_suite.decrypt(row[5]).decode("utf-8").split(), self.cipher_suite.decrypt(row[6]).decode("utf-8").split(), self.cipher_suite.decrypt(row[7]).decode("utf-8").split(), row[0]), tags=tag) i = i + 1 conn.close() self.last_focus = None self.table.selection() def deleteService(self): service = self.getSelectedService(self) if service is None: messagebox.showerror( "Μήνυμα Σφάλματος", "Παρακαλώ επιλέξτε την Υπηρεσία που θέλετε να Διαγράξετε.") else: msgBox = messagebox.askquestion( 'Διαγραφή: {}'.format(service[0]), 'Είστε σίγουρος ότι θέλετε να διαγράψετε την Υπηρεσία: ' '{}' ' ?'.format(service[0]), icon='warning') if msgBox == 'yes': try: conn = sqlite3.connect('cerberus.db') except sqlite3.Error as e: print(e) sql = 'DELETE FROM service WHERE id=?' cur = conn.cursor() cur.execute(sql, (service[-1], )) conn.commit() conn.close() self.loadTable(self) def popupMenu(self, event): serviceId = self.table.identify_row(event.y) if serviceId: self.table.selection_set(serviceId) try: self.popup.tk_popup(event.x_root, event.y_root) finally: self.popup.grab_release() def checkPasswordToExportToCSV(self): print("Check Password..") import logInForm self.master.withdraw() logInForm.logIn(self) @staticmethod def exportToCSV(): print("Export Services to CSV...") try: conn = sqlite3.connect('cerberus.db') except sqlite3.Error as e: print(e) key = cerberusCryptography.getMasterKey() cipher_suite = Fernet(key) cur = conn.cursor() cur.execute( "SELECT category, name, email, username, password, value, url value FROM service" ) rows = cur.fetchall() csvData = [[ 'Κατηγορία', 'Υπηρεσία', 'Email', 'Όνομα Χρήστη', 'Κωδικός', 'ID', 'URL', ]] for row in rows: csvData = csvData + [[ cipher_suite.decrypt(row[0]).decode("utf-8").split(), cipher_suite.decrypt(row[1]).decode("utf-8").split(), cipher_suite.decrypt(row[2]).decode("utf-8").split(), cipher_suite.decrypt(row[3]).decode("utf-8").split(), cipher_suite.decrypt(row[4]).decode("utf-8").split(), cipher_suite.decrypt(row[5]).decode("utf-8").split(), cipher_suite.decrypt(row[6]).decode("utf-8").split(), ]] try: homeFolder = str(Path.home()) filePath = filedialog.asksaveasfile( initialdir=homeFolder, initialfile='cerberus.csv', title="Επιλογή Αρχείου", filetypes=(("csv files", "*.csv"), ("all files", "*.*"))) if filePath: try: with open(filePath.name, 'w') as csvFile: csvFile = csv.writer(csvFile, delimiter='\t') csvFile.writerows(csvData) messagebox.showinfo( "Μήνυμα Επιτυχίας", "Το αρχείο αποθηκέυτηκε με Επιτυχία στην τοποθεσία {}." .format(filePath.name)) except Exception as e: messagebox.showerror( "Μήνυμα Σφάλματος", "Δεν ήταν δυνατή η Εξαγωγή του αρχείου.") except Exception as e: print(e) messagebox.showerror("Μήνυμα Σφάλματος", "Δεν ήταν δυνατή η Εξαγωγή του αρχείου.")
class ManagerWindow: """ 主管理界面入口类,直接无参数创建对象即可。 """ # 窗口宽高 WIN_WIDTH = 800 WIN_HEIGHT = 600 def __init__(self): # 界面根节点 self.root = Tk() # 主窗口标题 self.root.title(MANAGER_TITLE) # 读取config self.config_dict = ConfigOperation.get_dir_from_file() # 主窗口分辨率 self.root.geometry("%sx%s+%s+%s" % ( self.WIN_WIDTH, self.WIN_HEIGHT, int((self.root.winfo_screenwidth() - self.WIN_WIDTH) / 2), int((self.root.winfo_screenheight() - self.WIN_HEIGHT) / 2) )) self.root.minsize(self.WIN_WIDTH, self.WIN_HEIGHT) # 选项卡 self.tab_main = Notebook(self.root) self.tab_main.pack(expand=True, fill=BOTH) # 登录选项卡 self.frame_login = Frame(self.tab_main, bg=BG_COLOR) self.frame_login.pack(side=TOP) self.tab_main.add(self.frame_login, text=TAB_NAME_LIST["login"]["text"]) # 管理选项卡 self.frame_manage = Frame(self.tab_main, bg=BG_COLOR) self.tab_main.add(self.frame_manage, text=TAB_NAME_LIST["manage"]["text"]) # 好友选项卡 self.frame_friend = Frame(self.tab_main, bg=BG_COLOR) self.frame_friend.pack(side=TOP) self.tab_main.add(self.frame_friend, text=TAB_NAME_LIST["friends"]["text"]) # 群选项卡 self.frame_group = Frame(self.tab_main, bg=BG_COLOR) self.frame_group.pack(side=TOP) self.tab_main.add(self.frame_group, text=TAB_NAME_LIST["groups"]["text"]) # 插件选项卡 self.frame_plugin = Frame(self.tab_main, bg=BG_COLOR) self.frame_plugin.pack(side=TOP) self.tab_main.add(self.frame_plugin, text=TAB_NAME_LIST["plugins"]["text"]) # 初始化登录选项卡 self.__init_login_tab() # 初始化好友选项卡 self.__init_friend_tab() # 初始化群选项卡 self.__init_group_tab() # 初始化管理选项卡 self.__init_manage_tab() # 初始化插件选项卡 self.__init_plugin_tab() # 关闭窗口自动释放Session self.root.protocol("WM_DELETE_WINDOW", lambda: self.__on_close_root()) # 刷新显示 self.__refresh() # 运行相关线程 fetch_message_thread = FetchMessageThread() fetch_message_thread.daemon = True fetch_message_thread.start() # 运行插件初始化方法 PluginHandler.call_init() # 执行自动连接一次 self.__auto_connect() # 显示 self.root.mainloop() def __init_login_tab(self): """ 初始化登录选项卡界面 :return: 无 """ # 左边列表的frame frame_login_list = Frame(self.frame_login, bg=BG_COLOR) frame_login_list.pack( side=LEFT, expand=True, fill=BOTH, padx=5, pady=5 ) # 列表,用于保存连接记录 self.treeview_login_list = Treeview( frame_login_list, columns=[ LOGIN_GUIDE["host"], LOGIN_GUIDE["port"], LOGIN_GUIDE["authkey"], LOGIN_GUIDE["qq"] ], show="headings", selectmode=BROWSE ) self.treeview_login_list.pack( expand=True, fill=BOTH, side=LEFT ) self.treeview_login_list.column( LOGIN_GUIDE["host"], width=0 ) self.treeview_login_list.heading( LOGIN_GUIDE["host"], text=LOGIN_GUIDE["host"] ) self.treeview_login_list.column( LOGIN_GUIDE["port"], width=0 ) self.treeview_login_list.heading( LOGIN_GUIDE["port"], text=LOGIN_GUIDE["port"] ) self.treeview_login_list.column( LOGIN_GUIDE["authkey"], width=40 ) self.treeview_login_list.heading( LOGIN_GUIDE["authkey"], text=LOGIN_GUIDE["authkey"] ) self.treeview_login_list.column( LOGIN_GUIDE["qq"], width=0 ) self.treeview_login_list.heading( LOGIN_GUIDE["qq"], text=LOGIN_GUIDE["qq"] ) # 设定双击事件 self.treeview_login_list.bind( "<Double-Button-1>", lambda event: self.__on_double_click_login_list_content() ) # 设定登录列表的滚动条 scrollbar_login_list = Scrollbar(frame_login_list) scrollbar_login_list.pack(fill="y", expand=True) self.treeview_login_list.config(yscrollcommand=scrollbar_login_list.set) scrollbar_login_list.config(command=self.treeview_login_list.yview) # 设置列表右键菜单 self.treeview_login_list.bind("<Button-3>", self.__show_login_list_pop_up_menu) # 登录界面显示的那一坨 frame_login_menu = Frame(self.frame_login, bg=BG_COLOR) frame_login_menu.pack(side=LEFT, padx=5, pady=5) # mirai端地址 Label(frame_login_menu, text=LOGIN_GUIDE["host"], bg=BG_COLOR).grid(row=0, sticky=E, padx=5, pady=5) self.entry_host = Entry(frame_login_menu) self.entry_host.grid(row=0, column=1, sticky=W, padx=5, pady=5) # mirai端端口号 Label(frame_login_menu, text=LOGIN_GUIDE["port"], bg=BG_COLOR).grid(row=1, sticky=E, padx=5, pady=5) self.entry_port = Entry(frame_login_menu) self.entry_port.grid(row=1, column=1, sticky=W, padx=5, pady=5) # mirai端http授权码 Label(frame_login_menu, text=LOGIN_GUIDE["authkey"], bg=BG_COLOR).grid( row=2, sticky=E, padx=5, pady=5 ) self.entry_authkey = Entry(frame_login_menu, show=PWD_CHAR_CIRCLE) self.entry_authkey.grid(row=2, column=1, sticky=W, padx=5, pady=5) # 用于激活sessioKey的qq号码 Label(frame_login_menu, text=LOGIN_GUIDE["qq"], bg=BG_COLOR).grid( row=3, sticky=E, padx=5, pady=5 ) self.entry_qq = Entry(frame_login_menu) self.entry_qq.grid(row=3, column=1, sticky=W, padx=5, pady=5) # 自动连接复选框 self.auto_connect_var = BooleanVar() self.checkbutton_auto_connect = Checkbutton( frame_login_menu, text=AUTO_CONNECT_GUIDE, onvalue=True, offvalue=False, variable=self.auto_connect_var, bg=BG_COLOR ) self.checkbutton_auto_connect.grid(row=4, column=0, padx=5, pady=5, columnspan=2) # 连接按钮 self.btn_connect = Button( frame_login_menu, text=BTN_TEXT_CONN["connect"], width=15, command=lambda: self.__on_click_connect_event(), ) self.btn_connect.grid(row=5, columnspan=2, padx=5, pady=5) # 添加到登录列表按钮 self.btn_save_login = Button( frame_login_menu, width=15, text=BTN_TEXT_ADD_LOGIN, command=lambda: self.__on_click_add_to_login_list() ) self.btn_save_login.grid(row=6, columnspan=2, padx=5, pady=5) # 状态栏 self.label_login_status_bar = Label( self.root, text=LOGIN_STATUS_BAR_TEXT["notConnect"], fg=STATUS_BAR_COLOR["normal"] ) self.label_login_status_bar.pack(side=LEFT) # 下面开始从config中将内容填充进文本框中 self.entry_host.delete(0, END) self.entry_host.insert(END, self.config_dict["lastConnection"]["host"]) self.entry_port.delete(0, END) self.entry_port.insert(END, self.config_dict["lastConnection"]["port"]) self.entry_authkey.delete(0, END) self.entry_authkey.insert(END, self.config_dict["lastConnection"]["authkey"]) self.entry_qq.delete(0, END) self.entry_qq.insert(END, self.config_dict["lastConnection"]["qq"]) # 自动连接复选框内容 self.auto_connect_var.set(self.config_dict["autoConnect"]) def __init_friend_tab(self): """ 初始化好友选项卡内容 :return: 无 """ # 创建好友列表框架 frame_friend_list = Frame(self.frame_friend, bg=BG_COLOR) frame_friend_list.pack( side=LEFT, expand=True, fill=BOTH, padx=5, pady=5 ) # 创建消息测试发送框架 frame_friend_send = Frame(self.frame_friend, bg=BG_COLOR) frame_friend_send.pack( side=LEFT, padx=5, pady=5 ) # 设置列表 self.treeview_friend_list = Treeview( frame_friend_list, columns=[ FRIEND_GUIDE["qq"], FRIEND_GUIDE["nickname"], FRIEND_GUIDE["remark"] ], show="headings", selectmode=BROWSE ) self.treeview_friend_list.pack( expand=True, fill=BOTH, side=LEFT ) self.treeview_friend_list.column( FRIEND_GUIDE["qq"], width=0 ) self.treeview_friend_list.heading( FRIEND_GUIDE["qq"], text=FRIEND_GUIDE["qq"] ) self.treeview_friend_list.column( FRIEND_GUIDE["nickname"], width=0 ) self.treeview_friend_list.heading( FRIEND_GUIDE["nickname"], text=FRIEND_GUIDE["nickname"] ) self.treeview_friend_list.column( FRIEND_GUIDE["remark"], width=0 ) self.treeview_friend_list.heading( FRIEND_GUIDE["remark"], text=FRIEND_GUIDE["remark"] ) # 设定好友列表的滚动条 scrollbar_friend_list = Scrollbar(frame_friend_list) scrollbar_friend_list.pack(fill="y", expand=True) self.treeview_friend_list.config(yscrollcommand=scrollbar_friend_list.set) scrollbar_friend_list.config(command=self.treeview_friend_list.yview) # 刷新列表按钮 Button( frame_friend_send, text=BTN_FRIEND_REFRESH, command=lambda: self.__on_click_refresh_friend_list_event() ).grid(row=0, padx=5, pady=5) # 发送纯文本窗口标题 Label(frame_friend_send, text=SEND_TITLE, bg=BG_COLOR).grid(row=1, padx=5, pady=5) # 发送纯文本窗口 self.text_friend_send = Text(frame_friend_send, width=30, height=5) self.text_friend_send.grid(row=2, padx=5, pady=5) # 发送按钮 Button( frame_friend_send, text=BTN_SEND, command=lambda: self.__on_click_send_friend_message() ).grid(row=3, padx=5, pady=5) def __init_group_tab(self): """ 初始化群选项卡内容 :return: 无 """ # 创建好友列表框架 frame_group_list = Frame(self.frame_group, bg=BG_COLOR) frame_group_list.pack( side=LEFT, expand=True, fill=BOTH, padx=5, pady=5 ) # 创建消息测试发送框架 frame_group_send = Frame(self.frame_group, bg=BG_COLOR) frame_group_send.pack( side=LEFT, padx=5, pady=5 ) # 设置列表 self.treeview_group_list = Treeview( frame_group_list, columns=[ GROUP_GUIDE["group"], GROUP_GUIDE["name"], GROUP_GUIDE["permission"] ], show="headings", selectmode=BROWSE ) self.treeview_group_list.pack( expand=True, fill=BOTH, side=LEFT ) self.treeview_group_list.column( GROUP_GUIDE["group"], width=0 ) self.treeview_group_list.heading( GROUP_GUIDE["group"], text=GROUP_GUIDE["group"] ) self.treeview_group_list.column( GROUP_GUIDE["name"], width=0 ) self.treeview_group_list.heading( GROUP_GUIDE["name"], text=GROUP_GUIDE["name"] ) self.treeview_group_list.column( GROUP_GUIDE["permission"], width=0 ) self.treeview_group_list.heading( GROUP_GUIDE["permission"], text=GROUP_GUIDE["permission"] ) # 设定群列表的滚动条 scrollbar_group_list = Scrollbar(frame_group_list) scrollbar_group_list.pack(fill="y", expand=True) self.treeview_group_list.config(yscrollcommand=scrollbar_group_list.set) scrollbar_group_list.config(command=self.treeview_group_list.yview) # 刷新列表按钮 Button( frame_group_send, text=BTN_GROUP_REFRESH, command=lambda: self.__on_click_refresh_group_list_event() ).grid(row=0, padx=5, pady=5) # 发送纯文本窗口标题 Label(frame_group_send, text=SEND_TITLE, bg=BG_COLOR).grid(row=1, padx=5, pady=5) # 发送纯文本窗口 self.text_group_send = Text(frame_group_send, width=30, height=5) self.text_group_send.grid(row=2, padx=5, pady=5) # 发送按钮 Button( frame_group_send, text=BTN_SEND, command=lambda: self.__on_click_send_group_message() ).grid(row=3, padx=5, pady=5) def __init_manage_tab(self): """ 初始化管理选项卡 :return: 无 """ f_manage = Frame(self.frame_manage, bg=BG_COLOR) f_manage.pack(padx=5, pady=5, expand=True) # 指定头指示 Label(f_manage, text=MANAGE_GUIDE["commandHead"], bg=BG_COLOR).grid( row=0, column=0, padx=5, pady=5, sticky=E ) # 指令头文本框 self.entry_command_head = Entry(f_manage) self.entry_command_head.grid(row=0, column=1, padx=5, pady=5, sticky=EW) # 调试复选框 self.debug_var = BooleanVar() checkbutton_debug = Checkbutton( f_manage, text=MANAGE_GUIDE["debug"], onvalue=True, offvalue=False, variable=self.debug_var, bg=BG_COLOR ) checkbutton_debug.grid(row=1, column=0, columnspan=3, padx=5, pady=5) # 启用机器人 self.enable_var = BooleanVar() checkbutton_enable = Checkbutton( f_manage, text=MANAGE_GUIDE["enable"], onvalue=True, offvalue=False, variable=self.enable_var, bg=BG_COLOR ) checkbutton_enable.grid(row=2, column=0, columnspan=3, padx=5, pady=5) # 配置保存 Button( f_manage, text=MANAGE_GUIDE["saveConfig"], command=self.__on_click_save_config ).grid( row=3, column=1, padx=5, pady=5, sticky=EW ) # bot管理qq列表 self.treeview_op_list = Treeview( f_manage, columns=[ MANAGE_GUIDE["botOpQQ"] ], show="headings", selectmode=BROWSE ) self.treeview_op_list.column(MANAGE_GUIDE["botOpQQ"], width=200) self.treeview_op_list.heading(MANAGE_GUIDE["botOpQQ"], text=MANAGE_GUIDE["botOpQQ"]) self.treeview_op_list.grid( row=4, column=0, columnspan=3, rowspan=10, sticky=EW ) # 列表右键 self.treeview_op_list.bind("<Button-3>", self.__show_op_list_pop_up_menu) # 添加管理标签 Label(f_manage, text=MANAGE_GUIDE["addOpQQ"], bg=BG_COLOR).grid(row=14, column=0, padx=5, pady=5) # 添加管理文本框 self.entry_add_op = Entry(f_manage) self.entry_add_op.grid(row=14, column=1, padx=5, pady=5) # 添加添加按钮 Button( f_manage, text=MANAGE_GUIDE["btnAddOpQQ"], command=lambda: self.__on_click_add_op() ).grid(row=14, column=2, padx=5, pady=5, sticky=EW) def __init_plugin_tab(self): """ 初始化插件选项卡 :return: 无 """ # 指示标签 Label(self.frame_plugin, text=PLUGIN_LABEL_TEXT, bg=BG_COLOR).pack(side=TOP) # 插件列表frame frame_plugin_list = Frame(self.frame_plugin, bg=BG_COLOR) frame_plugin_list.pack( side=TOP, expand=True, fill=BOTH, padx=5, pady=5 ) # 插件列表 self.treeview_plugin_list = Treeview( frame_plugin_list, columns=[ PLUGIN_GUIDE["pluginName"] ], show="headings", selectmode=BROWSE ) self.treeview_plugin_list.pack(fill=BOTH, expand=True, side=LEFT) self.treeview_plugin_list.column(PLUGIN_GUIDE["pluginName"]) self.treeview_plugin_list.heading(PLUGIN_GUIDE["pluginName"], text=PLUGIN_GUIDE["pluginName"]) # 设定插件列表滚动条 scrollbar_plugin_list = Scrollbar(frame_plugin_list) scrollbar_plugin_list.pack(fill="y", expand=True) self.treeview_plugin_list.config(yscrollcommand=scrollbar_plugin_list.set) scrollbar_plugin_list.config(command=self.treeview_plugin_list.yview) def __on_click_connect_event(self): """ 点击连接按钮事件 :return: 无 """ if not GlobalValues.is_connected: # 如果是要连接 # 存到全局使用变量 GlobalValues.conn_host = self.entry_host.get() GlobalValues.conn_port = self.entry_port.get() GlobalValues.conn_authkey = self.entry_authkey.get() try: # 转换为整型后保存 GlobalValues.conn_qq = int(self.entry_qq.get()) except ValueError: self.label_login_status_bar.config(text=LOGIN_STATUS_BAR_TEXT["wrongQQ"], fg=STATUS_BAR_COLOR["failed"]) return # 修改界面上的一些内容为不可修改 self.__set_login_tools_active(False) # 修改按钮内容 self.btn_connect.config(text=BTN_TEXT_CONN["disconnect"]) # 修改状态栏内容 self.label_login_status_bar.config(text=LOGIN_STATUS_BAR_TEXT["connecting"], fg=STATUS_BAR_COLOR["normal"]) # 调用连接 try: Conn.new_session_key() except ( requests.exceptions.InvalidURL, requests.exceptions.ConnectionError, ): # 连接错误 # 错误信息显示到状态栏 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["connectFailed"], fg=STATUS_BAR_COLOR["failed"] ) # 修改文本框为可修改 self.__set_login_tools_active(True) self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) return except WrongAuthkeyException: # 授权码错误 # 显示到状态栏 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["wrongAuthkey"], fg=STATUS_BAR_COLOR["failed"] ) # 修改文本框为可修改 self.__set_login_tools_active(True) self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) return except BotNotExistException: # bot不存在错误 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["qqNotExist"], fg=STATUS_BAR_COLOR["failed"] ) # 修改文本框为可修改 self.__set_login_tools_active(True) self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) return self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["connected"], fg=STATUS_BAR_COLOR["passed"] ) # 修改连接状态值 GlobalValues.is_connected = True # 修改上次连接键值对 ConfigOperation.modify_dict("lastConnection", { "host": GlobalValues.conn_host, "port": GlobalValues.conn_port, "authkey": GlobalValues.conn_authkey, "qq": GlobalValues.conn_qq }) # 修改文件中自动连接开关 ConfigOperation.modify_dict("autoConnect", self.auto_connect_var.get()) else: # 如果要断开连接 # 修改文本框为可修改 self.__set_login_tools_active(True) # 修改按钮名称 self.btn_connect.config(text=BTN_TEXT_CONN["connect"]) # 修改属性值 self.label_login_status_bar.config( text=LOGIN_STATUS_BAR_TEXT["disconnectSuccess"], fg=STATUS_BAR_COLOR["normal"] ) # 释放session Conn.release_session_key() # 修改连接状态值 GlobalValues.is_connected = False def __set_login_tools_active(self, active: bool): """ 修改界面上的一些内容为不可修改 :param active: bool,如果为False则禁用掉文本框,否则启用 :return: 无 """ if active: self.entry_host.config(state=ACTIVE) self.entry_port.config(state=ACTIVE) self.entry_authkey.config(state=ACTIVE) self.entry_qq.config(state=ACTIVE) self.checkbutton_auto_connect.config(state=ACTIVE) else: self.entry_host.config(state=DISABLED) self.entry_port.config(state=DISABLED) self.entry_authkey.config(state=DISABLED) self.entry_qq.config(state=DISABLED) self.checkbutton_auto_connect.config(state=DISABLED) def __on_close_root(self): """ 关闭窗口的事件 :return: 无 """ # 如果正在连接则释放连接 if GlobalValues.is_connected: Conn.release_session_key() # 杀掉root self.root.destroy() def __refresh(self): """ 用于刷新界面,在必要时调用 :return: 无 """ def refresh_login_list(): """ 刷新登录列表 :return: 无 """ # 删除目前表中的所有内容 self.treeview_login_list.delete(*self.treeview_login_list.get_children()) # 把登录列表内容添加到显示中 for one_record in LoginListOperation.get_list_from_file(): self.treeview_login_list.insert("", index=END, values=( one_record["host"], one_record["port"], one_record["authkey"], one_record["qq"] )) def refresh_op_list(): """ 刷新bot管理员qq列表 :return: 无 """ # 删除目前表中的所有内容 self.treeview_op_list.delete(*self.treeview_op_list.get_children()) # 把内容添加到显示中 for one_record in OpListOperation.get_list(): self.treeview_op_list.insert("", index=END, values=( one_record )) def refresh_config(): """ 刷新配置 :return: 无 """ # 重新获取config self.config_dict = ConfigOperation.get_dir_from_file() # 将文件中的内容显示到界面中 self.entry_command_head.delete(0, END) self.entry_command_head.insert(END, self.config_dict["commandHead"]) # 设置复选框默认勾选 self.debug_var.set(self.config_dict["debug"]) self.enable_var.set(self.config_dict["enable"]) # 将内容设置到全局变量 GlobalValues.command_head = self.config_dict["commandHead"] GlobalValues.debug_var = self.debug_var GlobalValues.enable_var = self.enable_var def refresh_plugin_list(): # 获取插件名称 plugin_names = PluginHandler.get_plugin_name_list() # 显示 self.treeview_plugin_list.delete(*self.treeview_plugin_list.get_children()) for name in plugin_names: self.treeview_plugin_list.insert("", index=END, values=( name )) # 调用刷新登录列表 refresh_login_list() # 调用刷新op列表 refresh_op_list() # 刷新config显示 refresh_config() # 刷新插件列表显示 refresh_plugin_list() def __on_click_add_to_login_list(self): """ 将填写内容添加到列表中 :return: 无 """ # 非空检测 if [ self.entry_host.get(), self.entry_port.get(), self.entry_authkey.get(), self.entry_qq.get() ] == [""] * 4: return # 调用添加登录项方法 LoginListOperation.add_to_list( self.entry_host.get(), self.entry_port.get(), self.entry_authkey.get(), self.entry_qq.get() ) # 刷新显示 self.__refresh() def __on_double_click_login_list_content(self): """ 双击登录列表项目时,自动填充到右侧 :return: 无 """ # 获取item的值 item_list = self.treeview_login_list.item(self.treeview_login_list.focus(), "values") # 获取需要的项目并设置 self.entry_host.delete(0, END) self.entry_host.insert(END, item_list[0]) self.entry_port.delete(0, END) self.entry_port.insert(END, item_list[1]) self.entry_authkey.delete(0, END) self.entry_authkey.insert(END, item_list[2]) self.entry_qq.delete(0, END) self.entry_qq.insert(END, item_list[3]) def __show_login_list_pop_up_menu(self, event): """ 显示右键菜单 :param event: 事件 :return: 无 """ def on_delete_event(item_id): """ 删除选项的事件 :return: 无 """ # 删除该项 LoginListOperation.remove_from_list(*self.treeview_login_list.item(item_id, "values")) self.treeview_login_list.delete(item_id) self.__refresh() # 获取选择对象 iid = self.treeview_login_list.identify_row(event.y) # 如果有选择,则弹出右键菜单 if iid: self.treeview_login_list.selection_set(iid) menu_pop_up = Menu(self.treeview_login_list, tearoff=False) menu_pop_up.add_command( label=POP_UP_MENU_DELETE_STR, command=lambda: on_delete_event(iid) ) menu_pop_up.post(event.x_root, event.y_root) def __on_click_refresh_friend_list_event(self): """ 点击刷新好友列表事件 :return: 无 """ try: # 如果未连接,则可能会抛出异常,此处直接弹出错误消息框 friend_list = Conn.get_friend_list() except: messagebox.showerror(message=REFRESH_ERROR_MSG) return # 删除列表内容 self.treeview_friend_list.delete(*self.treeview_friend_list.get_children()) # 解析friend_list for friend_block in friend_list: self.treeview_friend_list.insert("", index=END, values=( friend_block["id"], friend_block["nickname"], friend_block["remark"] )) def __on_click_refresh_group_list_event(self): """ 点击刷新群列表事件 :return: 无 """ try: # 如果未连接,则可能会抛出异常,此处直接弹出错误消息框 group_list = Conn.get_group_list() except: messagebox.showerror(message=REFRESH_ERROR_MSG) return # 删除列表内容 self.treeview_group_list.delete(*self.treeview_group_list.get_children()) # 解析group_list for group_block in group_list: self.treeview_group_list.insert("", index=END, values=( group_block["id"], group_block["name"], group_block["permission"] )) def __on_click_send_friend_message(self): """ 点击发送消息给好友按钮 :return: 无 """ # 获取到选中好友的值列表 value_list = self.treeview_friend_list.item(self.treeview_friend_list.focus(), "values") try: # 获取qq并发送消息 qq = value_list[0] message_chain = MessageChain() text = self.text_friend_send.get(1.0, END) if text == "\n": return message_chain.add_plain_text(text) Conn.send_friend_message(qq, message_chain) self.text_friend_send.delete(1.0, END) except: messagebox.showerror(message=SEND_ERROR_MSG) return def __on_click_send_group_message(self): """ 点击发送消息给群按钮 :return: 无 """ # 获取到选中群的值列表 value_list = self.treeview_group_list.item(self.treeview_group_list.focus(), "values") try: # 获取qq并发送消息 qq = value_list[0] message_chain = MessageChain() text = self.text_group_send.get(1.0, END) if text == "\n": return message_chain.add_plain_text(text) Conn.send_group_message(qq, message_chain) self.text_group_send.delete(1.0, END) except: messagebox.showerror(message=SEND_ERROR_MSG) return def __on_click_add_op(self): """ 点击添加op按钮事件 :return: 无 """ content = self.entry_add_op.get() # 如果添加op的文本框中没有东西,则不添加 if content == "": return # 如果转换数字出错则不添加 try: op_qq = int(content) except ValueError: return # 添加到op列表中 OpListOperation.add_to_list(op_qq) # 刷新显示 self.__refresh() def __show_op_list_pop_up_menu(self, event): """ op列表右键菜单 :return: 无 """ def on_delete_event(): """ 删除选项的事件 :return: 无 """ # 删除该项 # 注意此处的强转,由于能够保证显示出来的内容一定只含有数字,故可以直接转换 OpListOperation.remove_from_list(int(self.treeview_op_list.item(op_qq, "values")[0])) self.treeview_op_list.delete(op_qq) self.__refresh() # 获取选择对象 op_qq = self.treeview_op_list.identify_row(event.y) # 如果有选择,则弹出右键菜单 if op_qq: menu_pop_up = Menu(self.treeview_op_list, tearoff=False) self.treeview_op_list.selection_set(op_qq) menu_pop_up.add_command( label=POP_UP_MENU_DELETE_STR, command=lambda: on_delete_event() ) menu_pop_up.post(event.x_root, event.y_root) def __on_click_save_config(self): """ 点击保存配置事件 :return: 无 """ content = self.entry_command_head.get() # 如果为空,则不存入,但是刷新 # 这样是为了保证点击后会显示原来的设置 if content == "": self.__refresh() return ConfigOperation.modify_dict("commandHead", content) ConfigOperation.modify_dict("debug", self.debug_var.get()) ConfigOperation.modify_dict("enable", self.enable_var.get()) # 刷新 self.__refresh() # 弹出对话框 messagebox.showinfo(message=MANAGE_GUIDE["successSaveCommandHeadMsg"]) def __auto_connect(self): if self.config_dict["autoConnect"]: self.__on_click_connect_event()
class window: def __init__(self): self.win = Tk() height = self.win.winfo_screenheight() width = self.win.winfo_screenwidth() x = (width - 700) // 2 y = (height - 700) // 2 self.win.geometry('700x700+{}+{}'.format(str(x), str(y))) self.win.resizable(width=False, height=False) self.frame = Frame(self.win, height=700, width=700, bg="#a3c2c2") self.frame.place(x=0, y=0) self.frame1 = Frame(self.frame, bg="#e0ebeb", height=700, width=2) self.frame1.place(x=30, y=0) self.frame1 = Frame(self.frame, bg="#75a3a3", height=700, width=4) self.frame1.place(x=20, y=0) self.frame1 = Frame(self.frame, bg="#476b6b", height=700, width=6) self.frame1.place(x=10, y=0) self.frame1 = Frame(self.frame, bg="#e0ebeb", height=2, width=700) self.frame1.place(x=0, y=30) self.frame1 = Frame(self.frame, bg="#75a3a3", height=4, width=700) self.frame1.place(x=0, y=20) self.frame1 = Frame(self.frame, bg="#476b6b", height=6, width=700) self.frame1.place(x=0, y=10) self.table = Treeview(self.frame, column=("#0", "#1", "#2", "#3", "#4", "#5", "#6", "#7")) style = ttk.Style() style.theme_use("alt") ttk.Style().configure("Treeview.Heading", font=('', 14, "bold")) self.table.column("#0", width=80) self.table.column("#1", width=80) self.table.column("#2", width=80) self.table.column("#3", width=80) self.table.column("#4", width=80) self.table.column("#5", width=80) self.table.column("#6", width=80) self.table.column("#7", width=80) self.table.heading("#0", text="Sr.") self.table.heading("#1", text="Name") self.table.heading("#2", text="Gender") self.table.heading("#3", text="Email") self.table.heading("#4", text="Contact") self.table.heading("#5", text="Address") self.table.heading("#6", text="Edit") self.table.heading("#7", text="Delete") x = database_queries.database() res = x.view_receptionist() #print(res) for i in res: self.table.insert('', 'end', text=i[0], value=(i[1], i[2], i[3], i[5], i[6], "edit", "delete")) self.table.bind("<Double Button-1>", self.trigger) self.table.place(x=40, y=50, width=640) self.win.mainloop() def trigger(self, e): row = self.table.focus() t = (self.table.item(row)) col = self.table.identify_column(e.x) if col == "#6": y = edit_receptionist.window(t["text"]) print("edit") elif (col == "#7"): o = database_queries.database() o.delete(t["text"])
class BlackWhite: def __init__(self): self.win = Tk() self.win.title("White/Black List") self.win.geometry('{}x{}'.format(800, 450)) self.canvas = Canvas(self.win, bg='#36393F') self.frame = Frame(self.canvas, bg='#36393F', width=600, height=340) self.userSelected = StringVar() self.whitebox = Treeview(self.frame, columns=1, show="headings", height="5") self.blackbox = Treeview(self.frame, columns=1, show="headings", height="5") self.userList = Combobox(self.frame, width=20, textvariable=self.userSelected, state="readonly") self.user = db.getName() def main(self): self.canvas.pack(expand=TRUE, fill=BOTH) self.frame.pack(expand=TRUE) Button(self.frame, text="Add", font='Arial 10 bold', bg='#36393F', fg="#f7cc35", command=self.addWhite).grid(row=0, column=0) Button(self.frame, text="Remove", font='Arial 10 bold', bg='#36393F', fg="#f7cc35", command=self.removeWhite).grid(row=1, column=0, padx=10) self.whitebox.grid(row=0, column=1, rowspan=2) self.whitebox.heading(1, text="WhiteBox") self.whitebox.column(1, width=100) self.blackbox.grid(row=0, column=2, rowspan=2) self.blackbox.heading(1, text="BlackBox") self.blackbox.column(1, width=100) Button(self.frame, text="Add", font='Arial 10 bold', bg='#36393F', fg="#f7cc35", command=self.addBlack).grid(row=0, column=3) Button(self.frame, text="Remove", font='Arial 10 bold', bg='#36393F', fg="#f7cc35", command=self.removeBlack).grid(row=1, column=3, padx=10) db.cursor.execute( "SELECT whitelisted FROM white_list WHERE whitelister = '%s'" % self.user) for row in db.cursor.fetchall(): self.whitebox.insert('', END, values=row) db.cursor.execute( "SELECT blacklisted FROM black_list WHERE blacklister = '%s'" % self.user) for row in db.cursor.fetchall(): self.blackbox.insert('', END, values=row) self.userList.grid(row=2, column=0, columnspan=4, pady=10) self.userList['values'] = inputUsers() self.userList.current(0) self.win.mainloop() def addWhite(self): # add selected user from combobox to whitebox self.whitebox.insert('', END, values=self.userSelected.get()) # add to white_list table db.cursor.execute("INSERT INTO white_list VALUES(%s, %s)", (self.user, self.userSelected.get())) def removeWhite(self): for selected_item in self.whitebox.selection(): whitelisted = self.whitebox.item(selected_item, 'values')[0] self.whitebox.delete(selected_item) db.cursor.execute( "DELETE FROM white_list WHERE whitelister = %s AND whitelisted = %s", (self.user, whitelisted)) def addBlack(self): self.blackbox.insert('', END, values=self.userSelected.get()) db.cursor.execute("INSERT INTO black_list VALUES(%s, %s)", (self.user, self.userSelected.get())) def removeBlack(self): for selected_item in self.blackbox.selection(): blacklisted = self.blackbox.item(selected_item, 'values')[0] self.blackbox.delete(selected_item) db.cursor.execute( "DELETE FROM black_list WHERE blacklister = %s AND blacklisted = %s", (self.user, blacklisted))
class Window: def fillTree(self,path, parent, list): for file in os.listdir(path): abspath = os.path.join(path,file) color = "" treelist = None for mini in list: if abspath in mini: color = 'red' treelist = mini else: for lk in mini: if abspath in lk: color = 'purple' child = None if color == 'red': child = self.tree.insert(parent,'end',text=file,open=False,tags=(abspath,'red',str(treelist)),) elif color == 'purple': child = self.tree.insert(parent,'end',text=file,open=False,tags=(abspath,'purple')) else: child = self.tree.insert(parent,'end',text=file,open=False,tags=(abspath,'white')) if(os.path.isdir(abspath)): self.tree.insert(child,'end',text='',open=False) def __init__(self,list,dirlist): self.root = Tk() self.root.wm_title("Duplicate_Files") self.min = None self.list = list self.root.geometry('600x600+0+0') self.tree = Treeview(self.root ,height=15) self.tree.pack(expand='yes',fill='both') self.tree.heading('#0',text="files") self.tree.tag_configure('red',foreground='red') self.tree.tag_configure('purple',foreground='#cc00ff') self.tree.bind("<Double-1>",self.onDoubleClick) self.tree.bind("<<TreeviewOpen>>",self.onOpen) self.tree.bind("<<TreeviewClose>>",self.onClose) for path in dirlist: branch = self.tree.insert('','end',text=path,open=True,tags=(path,'white')) self.fillTree(path,branch,list) self.root.mainloop() def onDoubleClick(self,event): item = self.tree.selection()[0] print ("clicked" + str(self.tree.item(item,'tags')[0])) if str(self.tree.item(item,'tags')[1]) == "red": list_of_files = ast.literal_eval(str(self.tree.item(item,'tags')[2])) if self.min != None: if self.min.mini.winfo_exists(): self.min.mini.destroy() self.min = MiniWindow(self.root,list_of_files) def onOpen(self,event): item = self.tree.selection()[0] if self.tree.parent(item) != '': if len(self.tree.get_children(item))>0: self.tree.delete(self.tree.get_children(item)) abspath = str(self.tree.item(item,'tags')[0]) if(os.path.isdir(abspath)): self.fillTree(abspath, item,self.list) def onClose(self,event): item = self.tree.selection()[0] if self.tree.parent(item) != '': if len(self.tree.get_children(item))>0: self.tree.delete(self.tree.get_children(item))
class AutoCorrectConfig(Frame): """Configuration window for autocorrect.""" def __init__(self, master, app, **kwargs): Frame.__init__(self, master, padding=4, **kwargs) self.rowconfigure(2, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.tree = Treeview(self, columns=('replace', 'by'), show='', selectmode='browse') scroll_x = AutoScrollbar(self, orient='horizontal', command=self.tree.xview) scroll_y = AutoScrollbar(self, orient='vertical', command=self.tree.yview) self.tree.configure(xscrollcommand=scroll_x.set, yscrollcommand=scroll_y.set) self.reset() self.replace = StringVar(self) self.by = StringVar(self) add_trace(self.replace, 'write', self._trace_replace) add_trace(self.by, 'write', self._trace_by) b_frame = Frame(self) self.b_add = Button(b_frame, text=_('New'), command=self.add) self.b_rem = Button(b_frame, text=_('Delete'), command=self.remove) self.b_add.state(('disabled', )) self.b_rem.state(('disabled', )) self.b_add.pack(pady=4, fill='x') self.b_rem.pack(pady=4, fill='x') Button(b_frame, text=_('Reset'), command=self.reset).pack(pady=8, fill='x') Label(self, text=_('Replace')).grid(row=0, column=0, sticky='w', pady=4) Label(self, text=_('By')).grid(row=0, column=1, sticky='w', pady=4) Entry(self, textvariable=self.replace).grid(row=1, column=0, sticky='ew', pady=4, padx=(0, 4)) Entry(self, textvariable=self.by).grid(row=1, column=1, sticky='ew', pady=4) self.tree.grid(row=2, columnspan=2, sticky='ewsn', pady=(4, 0)) scroll_x.grid(row=3, columnspan=2, sticky='ew', pady=(0, 4)) scroll_y.grid(row=2, column=2, sticky='ns', pady=(4, 0)) b_frame.grid(row=1, rowspan=2, padx=(4, 0), sticky='nw', column=3) self.tree.bind('<<TreeviewSelect>>', self._on_treeview_select) def _trace_by(self, *args): key = self.replace.get().strip() val = self.by.get().strip() self.by.set(val) if key in self.tree.get_children(''): if val != self.tree.set(key, 'by'): self.b_add.state(('!disabled', )) else: self.b_add.state(('disabled', )) else: self.b_add.state(('!disabled', )) if not val: self.b_add.state(('disabled', )) def _trace_replace(self, *args): key = self.replace.get().strip() val = self.by.get().strip() self.replace.set(key) if not key: self.b_add.state(('disabled', )) self.b_rem.state(('disabled', )) else: self.b_add.state(('!disabled', )) sel = self.tree.selection() if key in self.tree.get_children(''): if key not in sel: self.tree.selection_set(key) self.b_add.configure(text=_('Replace')) self.b_rem.state(('!disabled', )) if val != self.tree.set(key, 'by'): self.b_add.state(('!disabled', )) else: self.b_add.state(('disabled', )) else: self.b_rem.state(('disabled', )) self.b_add.configure(text=_('New')) if sel: self.tree.selection_remove(*sel) if not val: self.b_add.state(('disabled', )) def _on_treeview_select(self, event): sel = self.tree.selection() if sel: key, val = self.tree.item(sel[0], 'values') self.replace.set(key) self.by.set(val) def reset(self): self.tree.delete(*self.tree.get_children('')) keys = list(AUTOCORRECT.keys()) keys.sort() for key in keys: self.tree.insert('', 'end', key, values=(key, AUTOCORRECT[key])) def add(self): key = self.replace.get().strip() val = self.by.get().strip() if key in self.tree.get_children(''): self.tree.item(key, values=(key, val)) elif key and val: self.tree.insert('', 'end', key, values=(key, val)) def remove(self): key = self.replace.get() if key in self.tree.get_children(''): self.tree.delete(key) def ok(self): keys = self.tree.get_children('') AUTOCORRECT.clear() for key in keys: AUTOCORRECT[key] = self.tree.set(key, 'by')
class MainGUI: def __init__(self, master): self.parent = master # Set frame for the whole thing self.parent.title("LMS") self.frame = Frame(self.parent, width=1500, height=750) self.frame.grid(row=0, column=0) self.frame.grid_rowconfigure(0, weight=1) self.frame.grid_columnconfigure(0, weight=1) self.frame.grid_propagate(False) # Parameter Initialization self.search_string = None self.data = None self.borrowerId = None self.bookForCheckOutIsbn = None # Frame for the welcome message and header self.HeaderFrame = Frame(self.frame) self.HeaderFrame.grid(row=0, column=0, sticky=N) self.HeaderFrame.grid_rowconfigure(0, weight=1) self.HeaderFrame.grid_columnconfigure(0, weight=1) # # Label for the welcome message self.HeaderLabel = Label(self.HeaderFrame, text='What Book Do You Want?') self.HeaderLabel.grid(row=0, column=0) self.HeaderLabel.grid_rowconfigure(0, weight=10) self.HeaderLabel.grid_columnconfigure(0, weight=10) #Label for the searchbox self.SearchLabel = Label(self.HeaderFrame, text='') self.SearchLabel.grid(row=1, column=0) self.SearchLabel.grid_rowconfigure(1, weight=10) self.SearchLabel.grid_columnconfigure(0, weight=10) # Search Frame self.SearchFrame = Frame(self.frame) self.SearchFrame.grid(row=1, column=0, sticky=N) self.SearchFrame.grid_rowconfigure(1, weight=1) # self.SearchFrame.grid_columnconfigure(0, weight=1) self.SearchLabel = Label(self.SearchFrame, text='Search') self.SearchLabel.grid(row=0, column=0) self.SearchLabel.grid_rowconfigure(0, weight=1) # self.SearchLabel.grid_columnconfigure(0, weight=1) self.SearchTextBox = Entry(self.SearchFrame, text='Enter search string here...', width=70) self.SearchTextBox.grid(row=1, column=0) self.SearchTextBox.grid_rowconfigure(1, weight=1) self.SearchButton = Button(self.SearchFrame, text='Search', command=self.search) self.SearchButton.grid(row=2, column=0) self.SearchButton.grid_rowconfigure(2, weight=1) # Search Result Frame self.ActiveArea = Frame(self.frame) self.ActiveArea.grid(row=2, column=0, sticky=N) self.ActiveArea.grid_rowconfigure(2, weight=1) self.ResultTreeview = Treeview( self.ActiveArea, columns=["ISBN", "Book Title", "Author(s)", "Availability"]) self.ResultTreeview.grid(row=1, column=1) self.ResultTreeview.grid_rowconfigure(0, weight=1) self.ResultTreeview.heading('#0', text="ISBN") self.ResultTreeview.heading('#1', text="Book Title") self.ResultTreeview.heading('#2', text="Author(s)") self.ResultTreeview.heading('#3', text="Availability") self.ResultTreeview.bind('<ButtonRelease-1>', self.selectBookForCheckout) # Interaction Frame self.MajorFunctions = Frame(self.frame) self.MajorFunctions.grid(row=3, column=0, sticky=N) self.MajorFunctions.grid_rowconfigure(3, weight=1) self.checkOutBtn = Button(self.MajorFunctions, text="Check Out Book", command=self.check_out) self.checkOutBtn.grid(row=0, column=0, padx=10, pady=10) self.checkOutBtn.grid_rowconfigure(0, weight=1) self.checkOutBtn.grid_columnconfigure(0, weight=1) self.checkInBtn = Button(self.MajorFunctions, text="Check In Book", command=self.check_in) self.checkInBtn.grid(row=0, column=1, padx=10, pady=10) self.checkOutBtn.grid_rowconfigure(0, weight=1) self.checkOutBtn.grid_columnconfigure(1, weight=1) self.updateFinesBtn = Button(self.MajorFunctions, text="Updates Fines", command=self.update_fines) self.updateFinesBtn.grid(row=1, column=0, padx=10, pady=10) self.payFinesBtn = Button(self.MajorFunctions, text="Pay Fines", command=self.pay_fines) self.payFinesBtn.grid(row=1, column=1, padx=10, pady=10) self.changeDayBtn = Button(self.MajorFunctions, text="Change Day", command=self.change_day) self.changeDayBtn.grid(row=1, column=2, padx=10, pady=10) self.addBorrowerBtn = Button(self.MajorFunctions, text="Add New Borrower", command=self.add_borrower) self.addBorrowerBtn.grid(row=0, column=2, padx=10, pady=10) def change_day(self): global todays_date todays_date = todays_date + timedelta(days=1) print(todays_date) def search(self): self.search_string = self.SearchTextBox.get() cursor = cnx.cursor() cursor.execute( "select BOOK.isbn, BOOK.title, AUTHORS.fullname from BOOK join BOOK_AUTHORS on " "BOOK.isbn = BOOK_AUTHORS.isbn join AUTHORS on BOOK_AUTHORS.author_id = AUTHORS.author_id " "where BOOK.title like concat('%', '" + self.search_string + "', '%') or " "AUTHORS.fullname like concat('%', '" + self.search_string + "', '%') or " "BOOK.isbn like concat('%', '" + self.search_string + "', '%')") self.data = cursor.fetchall() self.view_data() def view_data(self): """ View data on Treeview method. """ self.ResultTreeview.delete(*self.ResultTreeview.get_children()) for elem in self.data: cursor = cnx.cursor() cursor.execute( "SELECT EXISTS(SELECT BOOK_LOANS.isbn from BOOK_LOANS where BOOK_LOANS.isbn = '" + str(elem[0]) + "')") result = cursor.fetchall() if result == [(0, )]: availability = "Available" else: cursor = cnx.cursor() cursor.execute( "SELECT BOOK_LOANS.Date_in from BOOK_LOANS where BOOK_LOANS.isbn = '" + str(elem[0]) + "'") result = cursor.fetchall() if result[-1][0] is None: availability = "Not Available" else: availability = "Available" self.ResultTreeview.insert('', 'end', text=str(elem[0]), values=(elem[1], elem[2], availability)) def selectBookForCheckout(self, a): curItem = self.ResultTreeview.focus() self.bookForCheckOutIsbn = self.ResultTreeview.item(curItem)['text'] def check_out(self): if self.bookForCheckOutIsbn is None: messagebox.showinfo("Attention!", "Select Book First!") return None self.borrowerId = simpledialog.askstring("Check Out Book", "Enter Borrower ID") cursor = cnx.cursor() cursor.execute( "SELECT EXISTS(SELECT Card_no from BORROWERS WHERE BORROWERS.Card_no = '" + str(self.borrowerId) + "')") result = cursor.fetchall() if result == [(0, )]: messagebox.showinfo("Error", "Borrower not in Database!") return None else: count = 0 cursor = cnx.cursor() cursor.execute( "SELECT BOOK_LOANS.Date_in from BOOK_LOANS WHERE BOOK_LOANS.Card_no = '" + str(self.borrowerId) + "'") result = cursor.fetchall() for elem in result: if elem[0] is None: count += 1 if count >= 3: messagebox.showinfo("Not Allowed!", "Borrower has loaned 3 books already!") return None else: cursor = cnx.cursor() cursor.execute("SET FOREIGN_KEY_CHECKS=0") cursor.execute( "INSERT INTO BOOK_LOANS (ISBN, Card_no, Date_out, Due_date) VALUES ('" + self.bookForCheckOutIsbn + "', '" + self.borrowerId + "', '" + str(todays_date) + "', '" + str(todays_date + timedelta(days=14)) + "')") cursor.execute("SET FOREIGN_KEY_CHECKS=1") cnx.commit() cursor = cnx.cursor() cursor.execute("SELECT MAX(Loan_Id) FROM BOOK_LOANS") result = cursor.fetchall() loan_id = result[0][0] cursor.execute( "INSERT INTO FINES (Loan_Id, fine_amt, paid) VALUES ('" + str(loan_id) + "', '0.00', '0')") cnx.commit() messagebox.showinfo("Done", "Book Loaned Out!") def check_in(self): self.checkInWindow = Toplevel(self.parent) self.checkInWindow.title("Check In Here") self.app = CheckIn(self.checkInWindow) def update_fines(self): cursor = cnx.cursor() cursor.execute( "SELECT BOOK_LOANS.Loan_Id, BOOK_LOANS.Date_in, BOOK_LOANS.Due_date FROM BOOK_LOANS" ) result = cursor.fetchall() for record in result: date_in = record[1] date_due = record[2] if date_in is None: date_in = todays_date diff = date_in.date() - date_due.date() if diff.days > 0: fine = int(diff.days) * 0.25 else: fine = 0 cursor = cnx.cursor() cursor.execute("UPDATE FINES SET FINES.fine_amt = '" + str(fine) + "' WHERE FINES.Loan_Id = '" + str(record[0]) + "'") cnx.commit() messagebox.showinfo("Info", "Generated Fines") def pay_fines(self): self.newPayFinesWindow = Toplevel(self.parent) self.newPayFinesWindow.title("Fine!!") self.app1 = PayFines(self.newPayFinesWindow) def add_borrower(self): self.newBorrowerWindow = Toplevel(self.parent) self.newBorrowerWindow.title("Borrowing Person New") self.newapp = BorrowingPerson(self.newBorrowerWindow)
class Program(Frame): """Class to represent a main window""" def __init__(self, parent): # Some top-level settings. Frame.__init__(self, parent) self.content = Frame(self, padding=(5, 5, 5, 20)) self.parent = parent self.parent.title('Restaurant manager') self.parent.minsize(DEFAULT_MINSIZE_WIDTH, DEFAULT_MINSIZE_HEIGHT) self.parent.protocol('WM_DELETE_WINDOW', self.onQuit) # Some variables. self.track_weight = IntVar() self.custom_entries = [] self.jsonReader = JsonReader(json_path) self.frames = [] self.entries = {} self.dishes = self.jsonReader.getDishesDict() self.dishes_names = self.jsonReader.getDishesNames() self.parent.iconphoto( True, PhotoImage(file=os.path.join(sys.path[0], logo_path))) # Initialize all widgets. self.initWidgets() def initWidgets(self): """ Initialize all widgets in window here. Entries are saved in [self.entries] list. ---------------------------------------------------------- 5 frames are initialized and saved into [self.frames] list here: 1) [About frame] - Frame to contain all non-food entries. 2) [Separator frame] - Frame to contain a simple separator. 3) [New order frame] - Frame to contain entries for adding orders to the main table. 4) [Orders table frame] - Frame to contain table with list of added orders. 5) [Save report frame] - Frame to contain buttons, which save a report. ---------------------------------------------------------- """ # Create 5 frames here. for i in range(5): self.frames.append(Frame(self.content)) # Set the weights of cols and rows in the grid. self.configureGrid() # Center a window. self.centerWindow() # Place 4 frames to the window. self.frames[0].grid(column=0, row=0, sticky=N + E + W, padx=5, pady=3) self.frames[1].grid(column=0, row=1, sticky=N + S + E + W, padx=5, pady=3) self.frames[2].grid(column=0, row=2, sticky=N + S + E + W, padx=5, pady=3) self.frames[3].grid(column=0, row=3, sticky=N + S + E + W, padx=5, pady=10) self.frames[4].grid(column=0, row=4, sticky=S + E + W, padx=5, pady=3) # About frame widgets. Label(self.frames[0], text='Заказчик').grid(row=0, column=0, sticky=E, pady=5) Label(self.frames[0], text='Менеджер').grid(row=0, column=2, sticky=E, pady=5) Label(self.frames[0], text='Вид мероприятия', justify=RIGHT, wraplength=90).grid(row=0, column=4, sticky=E, pady=5) Label(self.frames[0], text='Дата').grid(row=1, column=0, sticky=E, pady=5) Label(self.frames[0], text='Время').grid(row=1, column=2, sticky=E, pady=5) Label(self.frames[0], text='Место проведения', justify=RIGHT, wraplength=90).grid(row=1, column=4, sticky=E, pady=5) Label(self.frames[0], text='Количество персон', justify=RIGHT, wraplength=90).grid(row=1, column=6, sticky=E, pady=5) self.entries['client'] = Entry(self.frames[0]) self.entries['manager'] = Entry(self.frames[0]) self.entries['type'] = Entry(self.frames[0], width=10) self.entries['date'] = Entry(self.frames[0]) self.entries['time'] = Entry(self.frames[0]) self.entries['location'] = Entry(self.frames[0], width=10) self.entries['persons'] = Entry(self.frames[0], width=10) self.entries['client'].focus_set() today = date.today().isoformat().split('-')[::-1] self.entries['date'].insert(0, '.'.join(today)) self.entries['client'].grid(row=0, column=1, sticky=E + W, padx=(3, 13), pady=5) self.entries['manager'].grid(row=0, column=3, sticky=E + W, padx=(3, 13), pady=5) self.entries['type'].grid(row=0, column=5, columnspan=3, sticky=E + W, padx=(3, 13), pady=5) self.entries['date'].grid(row=1, column=1, sticky=E + W, padx=(3, 13), pady=5) self.entries['time'].grid(row=1, column=3, sticky=E + W, padx=(3, 13), pady=5) self.entries['location'].grid(row=1, column=5, sticky=E + W, padx=(3, 13), pady=5) self.entries['persons'].grid(row=1, column=7, sticky=E + W, padx=(3, 13), pady=5) # Add a separator between [about] and [new order] frames sep1 = Frame(self.frames[1], height=2, borderwidth=1, relief='sunken') sep1.pack(fill=X, padx=1, pady=10) # New Order frame widgets. Label(self.frames[2], text='Название', anchor=E).grid(row=0, column=0, sticky=E) Label(self.frames[2], text='Комментарий', anchor=E).grid(row=1, column=0, sticky=E) Label(self.frames[2], text='Количество', anchor=E).grid(row=2, column=0, sticky=E) self.sum_lbl = Label(self.frames[2], text='Текущая сумма заказа:\n 0 грн', anchor=E, justify=RIGHT) self.entries['name'] = AutocompleteEntry(self.frames[2]) self.entries['comment'] = Entry(self.frames[2]) self.entries['amount'] = Entry(self.frames[2]) addOrder_btn = Button(self.frames[2], text='Добавить блюдо в отчет') self.entries['name'].set_completion_list(self.dishes_names) self.entries['amount'].insert(0, '1') addOrder_btn['command'] = lambda: self.addDish() self.entries['name'].grid(row=0, column=1, columnspan=5, sticky=W + E, pady=3, padx=(3, 15)) self.entries['comment'].grid(row=1, column=1, columnspan=5, sticky=W + E, pady=3, padx=(3, 15)) self.entries['amount'].grid(row=2, column=1, columnspan=2, sticky=W + E, pady=3, padx=(3, 15)) addOrder_btn.grid(row=3, column=1, sticky=W, pady=3, padx=3) self.sum_lbl.grid(row=4, column=5, pady=0, padx=(190, 0)) customEntry_btn = Button(self.frames[2], text='Добавить собственную строку в отчет') customEntry_btn['command'] = lambda: self.addCustomEntry() customEntry_btn.grid(row=4, column=1, sticky=W, pady=3, padx=3) # Orders Table frame widgets. self.orders_view = Treeview(self.frames[3]) self.orders_view['columns'] = ('Weight', 'Amount', 'Comment', 'Price', 'Sum') self.orders_view.bind('<Delete>', lambda e: self.deleteEntry(e, self.orders_view)) self.orders_view.heading('#0', text='Название') self.orders_view.column('#0', anchor='w', minwidth=307, width=307) self.orders_view.heading('Weight', text='Выход') self.orders_view.column('Weight', anchor=CENTER, minwidth=100, width=100, stretch=NO) self.orders_view.heading('Amount', text='Количество') self.orders_view.column('Amount', anchor=CENTER, minwidth=100, width=100, stretch=NO) self.orders_view.heading('Comment', text='Комментарий') self.orders_view.column('Comment', anchor='w', minwidth=130, width=130) self.orders_view.heading('Price', text='Цена, грн') self.orders_view.column('Price', anchor=CENTER, minwidth=110, width=110, stretch=NO) self.orders_view.heading('Sum', text='Сумма, грн') self.orders_view.column('Sum', anchor=CENTER, minwidth=108, width=108, stretch=NO) self.orders_view.grid(row=0, column=0, sticky=N + S + E + W, padx=3, pady=3) # NOTE: next [for] block is for testing purposes only. """ for dish in self.dishes: self.orders_view.insert('', 'end', text=dish, values=[ self.dishes[dish]['weight'], 5, # [amount] column 'wats up?', # [comment] column self.dishes[dish]['price'], 5 * float(self.dishes[dish]['price']) ] ) """ orders_scrlbar = Scrollbar(self.frames[3], orient=VERTICAL, command=self.orders_view.yview) self.orders_view['yscrollcommand'] = orders_scrlbar.set orders_scrlbar.grid(row=0, column=1, sticky=N + S) # Save Report frame widgets. saveWeb_btn = Button(self.frames[4], text='Сохранить отчет', width=20) trackweight_chkbox = Checkbutton(self.frames[4], text='Учитывать средний вес', variable=self.track_weight) saveWeb_btn['command'] = lambda: self.saveWeb() saveWeb_btn.pack(side='left', anchor=CENTER, padx=5, pady=3) trackweight_chkbox.pack(side='left', anchor=CENTER, pady=3, padx=3) def configureGrid(self): """Configure weights of grids columns and rows""" # Top-level configuration. self.grid(sticky=N + S + E + W) top = self.winfo_toplevel() top.rowconfigure(0, weight=1) top.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) # Configuration of main content frame. self.configureFrame(self.content, [1], [0, 0, 0, 3, 0]) # Configuration of about frame. self.configureFrame(self.frames[0], [0, 1, 0, 1, 0, 0, 0, 0], [0, 0, 0]) # Configuration of new order frame. self.configureFrame(self.frames[2], [0, 1, 1, 1, 1, 1], [0, 0, 0, 0]) # Configuration of orders table frame. self.configureFrame(self.frames[3], [1, 0], [1]) def centerWindow(self): """Place the main window in the center of screen""" window_w = DEFAULT_MINSIZE_WIDTH window_h = DEFAULT_MINSIZE_HEIGHT screen_w = self.winfo_screenwidth() screen_h = self.winfo_screenheight() x = (screen_w - window_w) / 2 y = (screen_h - window_h) / 2 self.parent.geometry('%dx%d+%d+%d' % (window_w, window_h, x, y)) def onQuit(self): """Before the program exits, ask user, if he really wants it""" if messagebox.askyesno('Выход из программы', 'Вы действительно хотите выйти из программы?'): self.quit() @staticmethod def deleteEntry(e, tree): """Event to handle deletion in TreeView woth [Delete] button""" selected_item = tree.selection()[0] # get selected item tree.delete(selected_item) @staticmethod def configureFrame(frame, columns_wght, rows_wght): """Function to organize frame configuration routine""" frame.grid(column=0, row=0, sticky=N + S + E + W) for i, weight in enumerate(columns_wght): frame.columnconfigure(i, weight=weight) for i, weight in enumerate(rows_wght): frame.rowconfigure(i, weight=weight) def saveWeb(self): """Save data from the TreeView to the html report""" # Validation: if there is no items in tree_view if not self.orders_view.get_children(): messagebox.showerror('Ошибка', 'Ошибка создания отчета: нет блюд.') return # Open file dialog to choose saving path. file = filedialog.asksaveasfile(mode='w', defaultextension='.html', filetypes=[('Веб страница', '.html'), ('Все файлы', '.*')]) # If user pressed [Cancel] or closed a file dialog. if file is None: return # Pack files to send to HTML saver module. # Dictionary looks like: { name:{weight,amount,comment,price,total}, name:... } packed_dishes = { 'global': { 'trackw': self.track_weight.get(), # flag - is weight tracked 'totalsum': self.sum_lbl['text'][21:-4], # str - total sum of dishes 'centries': self.custom_entries # [5*str] - custom entries }, 'about': { 'client': self.entries['client'].get(), 'manager': self.entries['manager'].get(), 'type': self.entries['type'].get(), 'date': self.entries['date'].get(), 'time': self.entries['time'].get(), 'location': self.entries['location'].get(), 'persons': self.entries['persons'].get() }, 'dishes': {} } for child in self.orders_view.get_children(): child_content = self.orders_view.item(child) child_values = child_content['values'] child_name = child_content['text'] child_type = self.dishes[child_name]['type'] # Pack data about a certain dish. packed_child = { child_name: { 'weight': child_values[0], 'amount': child_values[1], 'comment': child_values[2], 'price': child_values[3], 'total': child_values[4], 'type': child_type } } packed_dishes['dishes'].update(packed_child) # Save the HTML report html_writer = DishesHTMLReport(file, data=packed_dishes) html_writer.create_html() messagebox.showinfo('Успешное сохранение', 'Данные были успешно сохранены.') def addCustomEntry(self): """This functions opens a window, which gives access for creating custom entries to report""" newentry_dialog = NewEntryDialog( self, title='Добавить собственную строку в отчет') if newentry_dialog.result: self.custom_entries.append(newentry_dialog.result) def addDish(self): """This function adds an entry to the order_view TreeView widget.""" # Get packed_info as a dictionary. packed_info = self.packInfo() # If info packed successfully, add a new entry to orders TreeView. if not packed_info: return # Add a dish to the TreeView. self.orders_view.insert('', 'end', text=packed_info['dish'], values=packed_info['values']) # Clear all entries. entries_toclear = ['name', 'comment', 'amount'] for entry_key in entries_toclear: self.entries[entry_key].delete(0, END) self.entries[entry_key].insert(0, '') self.entries['amount'].insert(0, '1') # Change [sum] label. total_sum = float(self.sum_lbl['text'][21:-4]) + float( packed_info['values'][4]) self.sum_lbl['text'] = 'Текущая сумма заказа:\n %.2f грн' % total_sum # Set focus to ['name'] entry. self.entries['name'].focus_set() def packInfo(self): """Pack values, that were inserted into Entries and Text, into dictionary""" msg = self.validateForm() if msg == 'OK': name = self.entries['name'].get() amount = self.entries['amount'].get() total_price = float(amount) * float(self.dishes[name]['price']) pack = { 'dish': name, 'values': [ self.dishes[name]['weight'], str(amount), self.entries['comment'].get(), self.dishes[name]['price'], '%.2f' % total_price ] } return pack elif msg == 'NEWDISH_CANCELED': return False else: messagebox.showerror('Ошибка ввода', 'При вводе случились ошибки: \n%s' % msg) return False def validateForm(self): """Validate all Entry and Text Widgets""" msg = '' index = 1 translations = { 'client': 'Клиент', 'manager': 'Менеджер', 'type': 'Вид мероприятия', 'date': 'Дата', 'time': 'Время', 'location': 'Место проведения', 'persons': 'Количество персон', 'name': 'Название', 'comment': 'Комментарий', 'amount': 'Количество', } for k in self.entries: # Check if some entry is empty. if self.entries[k].get() == '': if k == 'comment': continue msg += '%i) Поле [%s] пустое.\n' % (index, translations[k]) index += 1 # Persons entry should contain only digits. if not all(letter.isdigit() for letter in self.entries['persons'].get()): msg += '%i) Поле [Количество персон] должно содержать только цифры.\n' % index index += 1 # Check date entry. match = re.search(r'(\d{2})[.](\d{2})[.](\d{4})$', self.entries['date'].get()) if not match: msg += '%i) Неправильный формат даты.\nПравильный формат: дд.мм.гггг\n' % index index += 1 # Check amount entry. check = all(letter.isdigit() or letter == '.' for letter in self.entries['amount'].get()) if not check: msg += '%i) Поле [Количество] должно содержать только цифры, или точки.\n' % index index += 1 # Ask about [name] entry only if there are no more errors left. if msg != '': return msg # Check name entry. if (self.entries['name'].get() not in self.dishes_names and self.entries['name'].get() != ''): if messagebox.askyesno( 'Добавление нового блюда', 'Блюда %s нет в списке. Добавить?' % self.entries['name'].get()): # Create a new window, which will contain a [result] dictionary {name,type,weight,price} newdish_dialog = NewDishDialog(self, self.entries['name'].get(), 'Добавить новое блюдо') if newdish_dialog.result: dishToJSON = { newdish_dialog.result['name']: { 'weight': newdish_dialog.result['weight'], 'price': newdish_dialog.result['price'], 'type': newdish_dialog.result['type'] } } self.jsonReader.writeDish(dishToJSON) self.jsonReader.prepInformation() self.dishes = self.jsonReader.getDishesDict() self.dishes_names = self.jsonReader.getDishesNames() self.entries['name'].set_completion_list(self.dishes_names) else: # if [exit] was pressed return 'NEWDISH_CANCELED' else: return 'NEWDISH_CANCELED' # Check if the same dish is in the orderslist. for child in self.orders_view.get_children(): child_content = self.orders_view.item(child) if self.entries['name'].get() == child_content['text']: msg += '%i) Ошибка в поле [Название] - такое блюдо уже есть в списке.' % index index += 1 # If all tests passed correctly, msg is 'OK' if msg == '': msg = 'OK' return msg
class RightTree(Frame): def get_size_in_pixels(self, text): """ Returns the length of the String 'text' in pixels. """ font = ft.Font() w = font.measure(text) return w def __init__(self, parent, dispatch_event): """ Builds the lower right tree, which informs the user about the metadata information. Initialisation creates a frame, a treeview and two scrollbars for the treeview element. On Inform, if there is a dataset selected it will build a Treeview with the metadata. """ super().__init__(parent) self.dispatch_event = dispatch_event self.tree = Treeview(self, columns=["value"], show="tree") #self.configure(height=1000) self.scrollbar_y = Scrollbar(self.tree, orient="vertical") self.scrollbar = Scrollbar(self.tree, orient="horizontal") self.scrollbar.config(command=self.tree.xview) self.scrollbar_y.config(command=self.tree.yview) self.tree.configure(yscrollcommand=self.scrollbar_y.set, xscrollcommand=self.scrollbar.set) self.tree.pack(fill="both", expand=True) self.scrollbar.pack(side="bottom", fill="x") self.scrollbar_y.pack(side="right", fill="y") self.pack(expand=1, fill='both') self.bind("<Configure>", self.on_resize) def on_resize(self, event): """ Sets the width of column 0 to an arbitrary, long enough value, to fix issue nr.005. """ self.scrollbar.config(command=self.tree.xview) self.scrollbar.pack(side="bottom", fill="x") self.tree.column(0, width=600) self.update() pass def inform(self, data): """ Inform function of the RightTree class. Loads available data. If there is a project, it clears the Treeview. If there is exactly 1 selection, it will build a tree with the metadata shown in it. If there is no selection or more than 1, it will show an appropriate message. """ project = data["project"] if project: # First delete everything - Selection might have changed self.tree.delete(*self.tree.get_children()) # 3 ifs : no selection, 1 selected, multiple selections sel = project.selection if len(sel) == 0: self.tree.column("#0", width=1100) self.tree.insert("", tkinter.END, "Project information", text="Please add and select a dataset") elif len(sel) == 1: index = sel[0] # For legacy reasons variable named name self.tree.insert("", tkinter.END, "Project information", text="Project information") self.tree.insert("Project information", tkinter.END, "Project Path", text="Path", values=[project.path]) self.tree.insert("", tkinter.END, "Dataset information", text="Dataset information") self.tree.insert("Dataset information", tkinter.END, "Dataset Path", text="Path", values=[project.datasets[index].path]) self.tree.insert( "Dataset information", tkinter.END, "Rows", text="Rows", values=[ len(project.datasets[index].data) ]) # example: 120000 rows with time from 0 to 59.9995 s. # HERE I AM textlines = textwrap.wrap( (project.datasets[index].metadata["Description"]), width=70) if textlines == []: textlines.append("No description given.") self.tree.insert("Dataset information", tkinter.END, "Dataset Description", text="Description", values=[textlines[0]]) if len(textlines) > 1: for i in range(1, len(textlines)): self.tree.insert("Dataset information", tkinter.END, "Dataset Description %d" % (i), text="", values=[textlines[i]]) self.tree.insert("", tkinter.END, "Method", text="Method") if project.datasets[index].metadata[ "Method"] == "HILDE-Homogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("HILDE (homogeneous noise)")) elif project.datasets[index].metadata[ "Method"] == "HILDE-Heterogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("HILDE (heterogeneous noise)")) elif project.datasets[index].metadata[ "Method"] == "JULES-Homogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("JULES (homogeneous noise)")) elif project.datasets[index].metadata[ "Method"] == "JSMURF-Homogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("JSMURF (homogeneous noise)")) else: self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("JSMURF (heterogeneous noise)")) # Here i will go self.tree.insert("", tkinter.END, "Dataset parameters", text="Dataset parameters") self.tree.insert("Dataset parameters", tkinter.END, "Sampling rate in Hz", text="Sampling rate in Hz", values=project.datasets[index]. metadata["Sampling rate in Hz"]) self.tree.insert("Dataset parameters", tkinter.END, "Cut-off frequency in Hz", text="Cut-off frequency in Hz", values=[ project.datasets[index]. metadata["Cut-off frequency in Hz"] ]) self.tree.insert( "Dataset parameters", tkinter.END, "Filter type", text="Filter type", values=[project.datasets[index].metadata["Filter type"]]) if project.datasets[index].metadata[ "Method"] == "HILDE-Homogeneous": self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 1", text="Quantile 1", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 1", tkinter.END, "Significance level 1", text="Alpha1", values=[ project.datasets[index]. metadata["Significance level 1"] ]) # self.tree.insert("Quantile 1", tkinter.END, "Repetitions 1", text="Repetitions", values=[ # project.datasets[index].metadata["Repetitions"]]) self.tree.insert("Quantile 1", tkinter.END, "Repetitions ", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 2", text="Quantile 2", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 2", tkinter.END, "Significance level 2", text="Alpha2", values=[ project.datasets[index]. metadata["Significance level 2"] ]) self.tree.insert("Quantile 2", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) elif project.datasets[index].metadata[ "Method"] == "HILDE-Heterogeneous": self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 1", text="Quantile 1", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 1", tkinter.END, "Significance level 1", text="Alpha1", values=[ project.datasets[index]. metadata["Significance level 1"] ]) self.tree.insert("Quantile 1", tkinter.END, "Repetitions ", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 2", text="Quantile 2", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 2", tkinter.END, "Significance level 2", text="Alpha2", values=[ project.datasets[index]. metadata["Significance level 2"] ]) self.tree.insert("Quantile 2", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) elif project.datasets[index].metadata[ "Method"] == "JULES-Homogeneous": if project.datasets[index].metadata[ "Quantile_JULES_HOMOGENEOUS provided"]: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=[ project.datasets[index]. metadata["Quantile_JULES_HOMOGENEOUS"] ]) else: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=["will be computed by MC simulation"]) self.tree.insert("Quantile", tkinter.END, "Significance level", text="Alpha", values=[ project.datasets[index]. metadata["Significance level"] ]) self.tree.insert( "Quantile", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index].metadata["Repetitions"] ]) elif project.datasets[index].metadata[ "Method"] == "JSMURF-Homogeneous": if project.datasets[index].metadata[ "Quantile_JSMURF_HOMOGENEOUS provided"]: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=[ project.datasets[index]. metadata["Quantile_JSMURF_HOMOGENEOUS"] ]) else: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=["will be computed by MC simulation"]) self.tree.insert("Quantile", tkinter.END, "Significance level", text="Alpha", values=[ project.datasets[index]. metadata["Significance level"] ]) self.tree.insert( "Quantile", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index].metadata["Repetitions"] ]) else: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=["will be computed by MC simulation"]) self.tree.insert("Quantile", tkinter.END, "Significance level", text="Alpha", values=[ project.datasets[index]. metadata["Significance level"] ]) self.tree.insert( "Quantile", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index].metadata["Repetitions"] ]) maxw = 600 #600 for child in self.tree.get_children(): self.tree.see(child) w = self.get_size_in_pixels( str(self.tree.item(child)['values'])) if (w > maxw): maxw = w for grandchild in self.tree.get_children(child): self.tree.see(grandchild) w = self.get_size_in_pixels( str(self.tree.item(grandchild)['values'])) if (w > maxw): maxw = w for ggrandchild in self.tree.get_children(grandchild): self.tree.see(ggrandchild) w = self.get_size_in_pixels( str(self.tree.item(ggrandchild)['values'])) if (w > maxw): maxw = w self.tree.column(0, width=maxw) self.tree.column("#0", width=200, stretch=False) #200 else: self.tree.column("#0", width=1000) #1000 self.tree.insert( "", tkinter.END, "Project information", text= "Multiple Datasets have been selected, select single dataset to show project information." )
class Library: """ Main class. Combines GUI, functionality and Database. Args: root (instance): tkinter's root instance. """ appName = "Knihovna" appVersion = "0.2" tabList = [["Knihy", ["ID", "Název knihy", "Autor", "Ilustrátor", "Rok"]]] def __init__(self, root): """Initialises Library class. Args: root (instance): tkinter's root instance. """ self.root = root self.root.geometry('1000x500') self.root.configure(background='#bdc3c7') self.root.minsize(1000, 500) self.root.title(Library.appName + " v" + Library.appVersion) self.toplevel = None self.notebook = Autoresized_Notebook(self.root) self.tables = [] self.tabs = [] i = 0 for tab in Library.tabList: tabframe = Frame(self.notebook) self.notebook.add(tabframe, text=f"{tab[0]}") # zjistí, který tab je právě otevřený a zavolá funkci windowCreate, které předá název tabu Button(tabframe, text='+', command=lambda: self.windowCreate(), height=1).pack(fill=X) if len(tab) >= 2: columnList = "" e = 0 for columnName in tab[1]: if e != 0: columnList += ", " columnList += f"{e}" e = e + 1 # + editovací tlačítko columnList += ", " + str((int(e) + 1)) self.treeview = Treeview(tabframe, columns=(columnList), show="headings", height=10) self.treeview.bind("<ButtonRelease-1>", self.bookEditBind) f = 0 for columnName in tab[1]: self.treeview.column(f, minwidth=0, width=150, anchor=N, stretch=TRUE) self.treeview.heading(f, text=f"{columnName}", anchor=W) f = f + 1 i = i + 1 self.treeview.column(f + 1, minwidth=0, width=150, anchor=N, stretch=TRUE) self.treeview.heading(f + 1, text="jiné", anchor=W) self.updateTable() self.tables.append( self.treeview.pack(fill=X, side=TOP, expand=1)) Button(tabframe, text='Exit', command=root.destroy).pack(padx=100, pady=100) self.notebook.pack(fill=BOTH, expand=1) def windowCreate(self, id=None, deleteCallback=None): """Creates another window. Args: id (int): id of selected book (default None). deleteCallback (function): callback of inserted function. """ if (self.toplevel is not None) and self.toplevel.exists == True: return self.toplevel = Window(self.root, id, saveNewBook=self.save, deleteBook=deleteCallback) def bookEditBind(self, event): """Binds event when clicking to 'edit' book info. Args: event (instance): event. """ button = self.treeview.identify_column(event.x) region = self.treeview.identify_region(event.x, event.y) if button != '#6' or region != 'cell': return item = self.treeview.focus() id = self.treeview.item(item)['values'][0] self.windowCreate(id, self.delete) def getBooks(self): """Clears self.books, reselects book info and its metadata and reinserts itself to self.books.""" self.books = [] booksInfo = Database.select("SELECT * FROM books") for book in booksInfo: info = { "ID": book[0], "authors": [], "illustrators": [], "title": book[1], "year": book[2] } meta = Database.select( f"SELECT meta.role, meta.name FROM bookWorkers LEFT JOIN (SELECT workers.ID, (people.forename || ' ' || people.surname) as name, roles.name as role FROM workers LEFT JOIN people ON people.ID = workers.peopleID LEFT JOIN roles ON workers.roleID = roles.ID) meta ON bookWorkers.workersID = meta.ID WHERE bookID = {book[0]}" ) for person in meta: info[person[0] + "s"].append(person[1]) self.books.append(info) def updateTable(self): """Deletes data from table and calls getBooks to reinsert data.""" self.getBooks() self.treeview.delete(*self.treeview.get_children()) for book in self.books: if (len(book["authors"]) >= 2): authors = ", ".join(book["authors"]) else: authors = book["authors"][0] if (len(book["illustrators"]) >= 2): illustrators = ", ".join(book["illustrators"]) elif not book["illustrators"]: illustrators = "" else: illustrators = book["illustrators"][0] self.treeview.insert("", END, values=(book["ID"], book["title"], authors, illustrators, book["year"], "upravit")) def delete(self, id): """Deletes selected book and updates table immediately after. Args: id (int): id of selected (edited) book. """ Database.execute(f"DELETE FROM books WHERE ID = {id}") Database.execute(f"DELETE FROM bookWorkers WHERE bookID = {id}") self.updateTable() def save(self, data, id): """Saves data to Database using class of the same name. Args: data (array): example: [{'forename': 'dd', 'surname': 'dd'}], 'illustrators': [{'forename': 'dd', 'surname': 'dd'}], 'title': None, 'year': None} id (integer): id of selected book. """ bookID = Database.execute( f"INSERT INTO books (title, year) VALUES ('{data['title']}', '{data['year']}')" ) for role in data["roles"]: for person in data["roles"][role]: personID = Database.select( f"SELECT ID FROM people WHERE forename = '{person['forename']}' AND surname = '{person['surname']}'" ) if not personID: personID = Database.execute( f"INSERT INTO people (forename, surname) VALUES ('{person['forename']}', '{person['surname']}')" ) else: personID = personID[0][0] workerID = Database.select( f"SELECT ID FROM workers WHERE peopleID = '{personID}' AND roleID = (SELECT ID FROM roles WHERE name = '{role}')" ) if not workerID: workerID = Database.execute( f"INSERT INTO workers (peopleID, roleID) VALUES ({personID}, (SELECT ID FROM roles WHERE name = '{role}'))" ) else: workerID = workerID[0][0] bookWorkerID = Database.select( f"SELECT ID FROM bookWorkers WHERE workersID = '{workerID}' AND roleID = (SELECT ID FROM roles WHERE name = '{role}')" ) if not bookWorkerID: bookWorkerID = Database.execute( f"INSERT INTO bookWorkers (bookID, workersID) VALUES ('{bookID}', '{workerID}')" ) else: bookWorkerID = bookWorkerID[0][0] self.updateTable()
class Expenses(Frame): # Creates the first option menus in the expense window def createOptionButtons(self): self.master.title("Expenses") # Creates the add item to inventory button addItem = Button(root, text="Add item to inventory", command=lambda: self.sequence(self.addItem))#addItem(master))) # This button will send to the user to the add item page addItem.place(x = 130, y = 100) # Creates the view items in inventory button inventoryButton = Button(root, text="View items in inventory", command=lambda: self.sequence(self.viewInveroty)) # This button will send the user to the view inventory page inventoryButton.place(x = 130, y = 150) # Create the total cost button totalCost = Button(root, text="Total Cost", command=lambda: self.sequence(self.viewTotalCost)) totalCost.place(x = 130, y = 200) # Creates the back button backButton = Button(root, text="Back", command=returnHome) # This button will return the user to the main page. Still working on it. backButton.place(x = 50, y = 350) # Creates the add item to inventory button and entries def addItem(self): self.master.title("Add new item") # Changes the title of the page to Add New Item # Creates a label called nameOfItems and an entry called itemName nameOfItem = Label(root, text="Item Name: ") nameOfItem.place(x = 110, y = 100) self.itemName = Entry(root) # This will allow the user to enter the name of the item that they will be adding self.itemName.place(x = 190, y = 100) # Creates the label called itemTypeLabel and a drop down menu called itemTypeChoice itemTypeLabel = Label(root, text = "Item's type: ") itemTypeLabel.place(x = 110, y = 160) self.itemTypeChoice = StringVar(root) # This makes itemTypeChoice a permanent String self.itemTypeChoice.set("Tree") # Tree is set to the default string of itemTypeChoice typeChoices = OptionMenu(root, self.itemTypeChoice, "Tree", "Animal", "Machine") # Drop down menu is created and options Tree, Animal, and Machine are added to the menu typeChoices.place(x = 190, y = 160) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.createOptionButtons)) backButton.place(x = 50, y = 350) # Next button nextButton = Button(root, text = "Next", command=self.saveNameAndType) #This button will send the user to the add inventory page nextButton.place(x = 350, y = 350) # Function that creates a new item object and assigns it a name and the type def saveNameAndType(self): name = self.itemName.get() self.item = Inventory(name) itemType = self.itemTypeChoice.get() self.item.itemType = itemType self.sequence(self.addToInventory) # Creates the add to inventory options def addToInventory(self): self.master.title("Add %s to %s inventory" % (self.item.name, self.item.itemType)) # This assigns the variables month, day, and year to be value holder for integer values # They are also set to be values of the class expenses (by using self) so that they can # be used in the function updateDay and SaveDate self.month = IntVar(self) self.day = IntVar(self) self.year = IntVar(self) # This trace function is used to keep track of when the selected months and years change. This is # done to adjust the days of the month according to the month or the year self.month.trace('w', self.updateDay) self.year.trace('w', self.updateDay) numMonths = self.nums(1, 12) # Runs the nums function that creates a list from 1 to 12 numYears = self.nums(2015, 2030) # Runs the nums function that creates a list from 2015 to 2030 # This creates the drop down menu and assigns the options is the menu. The day menu is left empty and # is assigned in the updateDay function self.optionmenu_month = OptionMenu(root, self.month, *numMonths) self.optionmenu_day = OptionMenu(root, self.day, '') self.optionmenu_year = OptionMenu(root, self.year, *numYears) # Sets the default value of the month and year options to 1 and 2015 respectively self.month.set(numMonths[0]) self.year.set(numYears[0]) self.optionmenu_month.place(x = 100, y = 120) self.optionmenu_day.place(x = 150, y = 120) self.optionmenu_year.place(x = 200, y = 120) datePurchased = Label(root, text = "Date Purchased") datePurchased.place(x = 150, y = 95) quantityPurchasedLabel = Label(root, text="Amount purchased:") quantityPurchasedLabel.place(x = 50, y = 180) self.quantityPurchasedEntry = Entry(root, bd=5) # Creates input box for user to insert the amount of items purchased self.quantityPurchasedEntry.place(x = 180, y = 180) pricePaidLabe = Label(root, text="Price paid for all: ") pricePaidLabe.place(x = 50, y = 210) self.pricePaidEntry = Entry(root, bd=5) # Creates input box for user to insert the price paid for the item self.pricePaidEntry.place(x = 180, y = 210) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.addItem)) backButton.place(x = 50, y = 350) nextButton = Button(root, text = "Next", command=self.saveQuanAndPrice) nextButton.place(x = 350, y = 350) # This function will update the days of the month according to the selected month and year def updateDay(self, *args): # The .get() will obtain the selected month and year values from the drop down menu above month = self.month.get() year = self.year.get() # Creates a loop which chooses the last day of the month according to the month or the year if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12: lastDay = 31 elif month == 4 or month == 6 or month == 9 or month == 11: lastDay = 30 # This elif loop uses the leap year formula at account for leap years elif month == 2: if (year % 4) == 0: if (year % 100) == 0: if (year % 400) == 0: lastDay = 29 else: lastDay = 28 else: lastDay = 29 else: lastDay = 28 numDays = self.nums(1,lastDay) # Assigns menu to the day drop down menu and deletes all of the options in the menu menu = self.optionmenu_day['menu'] menu.delete(0, 'end') # Loop for generating the new day menu for day in numDays: menu.add_command(label=day, command=lambda d = day: self.day.set(d)) self.day.set(1) # Function that creates the range of numbers for the drop down menu def nums(self, numStart, numEnd): num = range(numStart, numEnd + 1) return num # Function that assigns the price and quantity to an item def saveQuanAndPrice(self): self.item.price = self.pricePaidEntry.get() self.item.quantity = self.quantityPurchasedEntry.get() self.saveDate() self.sequence(self.confirmation) # Function that assigns the purchase date to an item def saveDate(self): self.item.purchaseMonth = self.month.get() self.item.purchaseDay = self.day.get() self.item.purchaseYear = self.year.get() self.item.purchaseDate = ("%s/%s/%s" % (self.item.purchaseMonth, self.item.purchaseDay, self.item.purchaseYear)) # Function that displays the user inputted information def confirmation(self): self.master.title("Confirm %s information" % self.item.name) name = Label(root, text="Name of item: ") name.place(x = 100, y = 50) itemName = Label(root, text=self.item.name) itemName.place(x = 100, y = 65) type = Label(root, text="%s type: " % self.item.name) type.place(x = 100, y = 90) itemType = Label(root, text=self.item.itemType) itemType.place(x = 100, y = 105) quantity = Label(root, text="How many %s were bought?" % self.item.name) quantity.place(x = 100, y = 130) itemQuantity = Label(root, text=self.item.quantity) itemQuantity.place(x = 100, y = 145) price = Label(root, text="How much did the %s %s cost?" % (self.item.quantity, self.item.name)) price.place(x = 100, y = 170) itemPrice = Label(root, text=self.item.price) itemPrice.place(x = 100, y = 185) date = Label(root, text="When were %s bought?" % self.item.name) date.place(x = 100, y = 210) itemDate = Label(root, text=self.item.purchaseDate) itemDate.place(x = 100, y = 225) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.addToInventory)) backButton.place(x = 50, y = 350) startOverButton = Button(root, text = "Start Over", command=lambda: self.sequence(self.createOptionButtons)) startOverButton.place(x = 200, y = 350) confirmButton = Button(root, text = "Confirm", command=lambda: self.sequence(self.addToDatabase)) confirmButton.place(x = 320, y = 350) # Adds the item to the database def addToDatabase(self): self.inventoryDB.insertInvetory(self.item) return self.successful() # Displays a success message when the item is added def successful(self): self.master.title("%s was added successfully!" % self.item.name) succMessage = Message(root, text = "%s was successfully added to the %s list!" % (self.item.name, self.item.itemType)) succMessage.place(x = 150, y = 150) startOverButton = Button(root, text = "Start Over", command=lambda: self.sequence(self.createOptionButtons))#self.saveNameAndType(itemName)))#(self.saveNameAndType(itemName))) # (itemName)))# lambda: self.sequence(self.test)) #This button will send the user to the add inventory page startOverButton.place(x = 150, y = 350) # Used to view the inventory def viewInveroty(self): # Creates the label called chooseTypeLabel and a drop down menu called chooseItemType chooseTypeLabel = Label(root, text = "Item's type: ") chooseTypeLabel.place(x = 110, y = 160) self.chooseItemType = StringVar(root) # The drop down menu is created and assigned to chooseItemType self.chooseItemType.set("Tree") # Tree is set to the default option in the drop down menu typeChoices = OptionMenu(root, self.chooseItemType, "Tree", "Animal", "Machine", "All") # Options Tree, Animal, Machine, and ALL are added to the drop down menu typeChoices.place(x = 190, y = 160) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.createOptionButtons)) # This button will return the user to the expenses option page backButton.place(x = 50, y = 350) nextButton = Button(root, text = "Next", command=lambda: self.sequence(self.displayGeneralInventory))#self.saveNameAndType(itemName)))#(self.saveNameAndType(itemName))) # (itemName)))# lambda: self.sequence(self.test)) #This button will send the user to the add inventory page nextButton.place(x = 350, y = 350) # Used to create the inventory table def displayGeneralInventory(self): # This creates a table using the function Treeview self.tree = Treeview(height="20", columns=("Name", "Current Quantity")) self.tree.pack() self.tree.heading('#1', text = "Name", anchor = CENTER) self.tree.heading('#2', text = "Current Quantity", anchor = CENTER) self.tree.column('#1', minwidth=0, width = 100) self.tree.column('#2', minwidth=0, width = 100) self.tree.column('#0', minwidth=0, width = 0) itemType = self.chooseItemType.get() if(itemType == "All"): self.obtainData("Tree") self.obtainData("Animal") self.obtainData("Machine") else: self.obtainData(itemType) # Adds database data to the inventory table def obtainData(self, type): for row in (self.inventoryDB.getOverviewInventory(type)): name = row[0] totalQuantity = row[1] # Inserts data into the table. Each entry is tagged with the name and the type # This is done in order to make identifying the entries easier for when detailed # tables are requested self.tree.insert("", "end", values = (name,totalQuantity), tag= [name, type]) # Creates a bak function that is used in the displayGeneralInventory functions self.backFunction = self.displayGeneralInventory # Binds a double click function to the Treeview table. If an entry is double clicked, # the function displayGeneralInventory is ran self.tree.bind("<Double-1>", self.displayDetailedInventory) backButton = Button(root, text="Back", command=lambda: self.sequence(self.viewInveroty)) # This button will return the user to the main page. Still working on it. backButton.place(x = 50, y = 350) # Creates table when an entry is double clicked def displayDetailedInventory(self, event): # The selected item's tag are extracted and assigned to name and type itemSelected = self.tree.selection() name = self.tree.item(itemSelected,"tag")[0] type = self.tree.item(itemSelected, "tag")[1] for child in root.winfo_children(): child.destroy() self.createDisplayTable() self.obtainDetailedData(name, type) # Adds detailed database data to the inventory table def obtainDetailedData(self,name, type): for row in (self.inventoryDB.getDetailedInventory(type, name)): name = row[0] purchaseDate = row[1] Quantity = row[3] Price = row[4] self.tree.insert("", "end", values = (name,purchaseDate,Quantity, Price)) backButton = Button(root, text="Back", command=lambda: self.sequence(self.backFunction)) backButton.place(x = 50, y = 350) # Creates the view total cost by month and year buttons def viewTotalCost(self): viewMonth = Button(root, text="View by month", command=lambda: self.sequence(self.viewByMonth)) viewMonth.place(x = 120, y = 100) viewYear = Button(root, text="View by year", command=lambda: self.sequence(self.viewByYear)) viewYear.place(x = 120, y = 150) backButton = Button(root, text="Back", command=lambda: self.sequence(self.createOptionButtons))#displayGeneralInventory)) # This button will return the user to the main page. Still working on it. backButton.place(x = 50, y = 350) # Creates the options for the user to select a month and year def viewByMonth(self): monthLabel = Label(root, text="Month") yearLabel = Label(root, text="Year") self.month = IntVar(self) self.year = IntVar(self) numMonths = self.nums(1, 12) numYears = self.nums(2015, 2030) self.optionmenu_month = OptionMenu(root, self.month, *numMonths) self.optionmenu_year = OptionMenu(root, self.year, *numYears) self.month.set(numMonths[0]) self.year.set(numYears[0]) self.optionmenu_month.place(x = 100, y = 100) self.optionmenu_year.place(x = 150, y = 100) monthLabel.place(x = 100, y = 140) yearLabel.place(x = 150, y = 140) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.viewTotalCost)) # This button will return the user to the expenses option page backButton.place(x = 50, y = 350) nextButton = Button(root, text = "Next", command= self.viewTotalCostMonth)#self.viewTotalCostMonth)#self.saveNameAndType(itemName)))#(self.saveNameAndType(itemName))) # (itemName)))# lambda: self.sequence(self.test)) #This button will send the user to the add inventory page nextButton.place(x = 350, y = 350) # Creates database table and inserts the respective values by month and year def viewTotalCostMonth(self): self.createDisplayTable() self.totalPrice = 0 month = self.month.get() year = self.year.get() self.lengthMonth = len(str(month)) self.searchDate = str(month) + "/" + str(year) InventoryDB = getDatabaseConnection() database = InventoryDB.cursor() self.insertData("DetailedTreeInventory", "Tree", database, "Month") self.insertData("DetailedAnimalInventory", "Animal", database, "Month") self.insertData("DetailedMachineInventory", "Machine", database, "Month") InventoryDB.close() totalPriceLabel = Label(root, text=("Total price for " + calendar.month_name[month] + " in " + str(year) + " is: " + str(self.totalPrice))) totalPriceLabel.place(x = 100, y = 350) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.viewByMonth)) # This button will return the user to the expenses option page backButton.place(x = 50, y = 350) # Creates the option for the user to select the year def viewByYear(self): yearLabel = Label(root, text="Year") self.year = IntVar(self) numYears = self.nums(2015, 2030) self.optionmenu_year = OptionMenu(root, self.year, *numYears) self.year.set(numYears[0]) self.optionmenu_year.place(x = 100, y = 100) yearLabel.place(x = 100, y = 140) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.viewTotalCost)) # This button will return the user to the expenses option page backButton.place(x = 50, y = 350) nextButton = Button(root, text = "Next", command= self.viewTotalCostYear)#self.viewTotalCostMonth)#self.saveNameAndType(itemName)))#(self.saveNameAndType(itemName))) # (itemName)))# lambda: self.sequence(self.test)) #This button will send the user to the add inventory page nextButton.place(x = 350, y = 350) # Creates database table and inserts the respective values by year def viewTotalCostYear(self): self.createDisplayTable() self.totalPrice = 0 year = self.year.get() InventoryDB = getDatabaseConnection() database = InventoryDB.cursor() self.insertData("DetailedTreeInventory", "Tree", database, "Year") self.insertData("DetailedAnimalInventory", "Animal", database, "Year") self.insertData("DetailedMachineInventory", "Machine", database, "Year") totalPriceLabel = Label(root, text="Total price for " + str(year) + " is: " + str(self.totalPrice)) totalPriceLabel.place(x = 100, y = 350) backButton = Button(root, text = "Back", command=lambda: self.sequence(self.viewByYear)) # This button will return the user to the expenses option page backButton.place(x = 50, y = 350) # Inserts the detailed values into the detailed table def insertData(self, table, type, database, yearOrMonth): if yearOrMonth == "Year": for row in database.execute("SELECT * FROM %s" % table ): itemdate = row[1] if ( str(self.year.get()) == itemdate[-4:]): name = row[0] purchaseDate = row[1] Quantity = row[3] Price = row[4] self.tree.insert("", "end", values = (name,purchaseDate,Quantity, Price),tag = [name, type] ) self.totalPrice = self.totalPrice + Price self.backFunction = self.viewTotalCostYear else: for row in database.execute("SELECT * FROM %s" % table ): itemdate = row[1] if (self.searchDate == (itemdate[0:(self.lengthMonth + 1)] + itemdate[-4:])): name = row[0] purchaseDate = row[1] Quantity = row[3] Price = row[4] self.tree.insert("", "end", values = (name,purchaseDate,Quantity, Price), tag = [name, type]) self.totalPrice = self.totalPrice + Price self.backFunction = self.viewTotalCostMonth # If entry is double clicked, the table will acknoledge the click and display the detailed table self.tree.bind("<Double-1>", self.displayDetailedInventory) def createDisplayTable(self): for child in root.winfo_children(): child.destroy() self.tree = Treeview(height="15", columns=("Name", "Purchase Date", "Quantity", "Price"))#, "Description")) self.tree.pack() self.tree.heading('#1', text = "Name", anchor = CENTER) self.tree.heading('#2', text = "Purchase Date", anchor = CENTER) self.tree.heading('#3', text = "Quantity", anchor = CENTER) self.tree.heading('#4', text = "Price", anchor = CENTER) self.tree.column('#1', minwidth=0, width = 95) self.tree.column('#2', minwidth=0, width = 95) self.tree.column('#3', minwidth=0, width = 95) self.tree.column('#4', minwidth=0, width = 95) self.tree.column('#0', minwidth=0, width = 0) # This is a helper function that will delete the current widgets of the frame def sequence(self, run): for child in root.winfo_children(): child.destroy() run() def __init__(self, master=None): Frame.__init__(self, master) self.place(); self.inventoryDB = InventoryDatabase() # self.inventoryDB.createTable() self.createOptionButtons()
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()
class FormChildAED: def __init__(self, frm_parent, title, connection): self.connection = connection self.directive = Message() self.title = title self.decide = True self.id_selected = 0 self.frm_child_list = LabelFrame(frm_parent) self.frm_child_crud = LabelFrame(frm_parent) self.frm_child_crud.config(fg=TEXT_COLOR, font=SUBTITLE_FONT) self.initialize_components() def initialize_components(self): """ Method that initialize the visual components for each form associated with the local administration """ # Resources for the Forms self.new_icon = PhotoImage(file=r"./Resources/create.png") self.modify_icon = PhotoImage(file=r"./Resources/modify.png") self.remove_icon = PhotoImage(file=r"./Resources/delete.png") self.save_icon = PhotoImage(file=r"./Resources/save.png") self.cancel_icon = PhotoImage(file=r"./Resources/cancel.png") # Components for List Form lbl_sep1 = Label(self.frm_child_list) lbl_sep1.grid(row=0, column=0, padx=10, pady=25) self.trv_available = Treeview(self.frm_child_list, height=15, columns=('N', 'Name', 'Surname', 'E-mail')) self.trv_available.heading('#0', text='ID', anchor=CENTER) self.trv_available.heading('#1', text='N', anchor=CENTER) self.trv_available.heading('#2', text='Name', anchor=CENTER) self.trv_available.heading('#3', text='Surname', anchor=CENTER) self.trv_available.heading('#4', text='E-mail', anchor=CENTER) self.trv_available.column('#0', width=0, minwidth=50, stretch=NO) self.trv_available.column('#1', width=20, minwidth=20, stretch=NO) self.trv_available.column('#2', width=200, minwidth=200, stretch=NO) self.trv_available.column('#3', width=200, minwidth=200, stretch=NO) self.trv_available.column('#4', width=400, minwidth=400, stretch=NO) self.trv_available.grid(row=0, column=1, sticky=W, pady=25) vsb_trv_av = Scrollbar(self.frm_child_list, orient="vertical", command=self.trv_available.yview) vsb_trv_av.grid(row=0, column=2, pady=25, sticky=NS) self.trv_available.configure(yscrollcommand=vsb_trv_av.set) frm_aux4 = Frame(self.frm_child_list) btn_new = Button(frm_aux4, image=self.new_icon, command=self.click_new) btn_new.grid(row=0, column=0, pady=5, padx=5, sticky=E) btn_new_ttp = CreateToolTip(btn_new, 'New ' + self.title.lower()) btn_edit = Button(frm_aux4, image=self.modify_icon, command=self.click_update) btn_edit.grid(row=1, column=0, pady=5, padx=5, sticky=E) btn_edit_ttp = CreateToolTip(btn_edit, 'Edit ' + self.title.lower()) btn_delete = Button(frm_aux4, image=self.remove_icon, command=self.click_delete) btn_delete.grid(row=2, column=0, pady=5, padx=5, sticky=E) btn_delete_ttp = CreateToolTip(btn_delete, 'Delete ' + self.title.lower()) frm_aux4.grid(row=0, column=3, pady=25, padx=25, sticky=NW) # Components for CRUD FRM lbl_name = Label(self.frm_child_crud, text='Name*') lbl_name.config(fg=TEXT_COLOR, font=LABEL_FONT) lbl_name.grid(row=0, column=0, pady=10, padx=20, sticky=W) lbl_surname = Label(self.frm_child_crud, text='Surname*') lbl_surname.config(fg=TEXT_COLOR, font=LABEL_FONT) lbl_surname.grid(row=1, column=0, pady=10, padx=20, sticky=W) lbl_email = Label(self.frm_child_crud, text='E-mail*') lbl_email.config(fg=TEXT_COLOR, font=LABEL_FONT) lbl_email.grid(row=2, column=0, pady=10, padx=20, sticky=W) self.lbl_old_passwd = Label(self.frm_child_crud, text='Old password*') self.lbl_old_passwd.config(fg=TEXT_COLOR, font=LABEL_FONT) self.lbl_passwd = Label(self.frm_child_crud, text='New password*') self.lbl_passwd.config(fg=TEXT_COLOR, font=LABEL_FONT) self.lbl_passwd_conf = Label(self.frm_child_crud, text='Confirm new password*') self.lbl_passwd_conf.config(fg=TEXT_COLOR, font=LABEL_FONT) self.txt_name = Entry(self.frm_child_crud) self.txt_name.grid(row=0, column=1, pady=10, padx=20, sticky=W) self.txt_surname = Entry(self.frm_child_crud) self.txt_surname.grid(row=1, column=1, pady=10, padx=20, sticky=W) self.txt_email = Entry(self.frm_child_crud) self.txt_email.grid(row=2, column=1, pady=10, padx=20, sticky=W) self.txt_old_passwd = Entry(self.frm_child_crud, show="*") self.txt_passwd = Entry(self.frm_child_crud, show="*") self.txt_passwd_conf = Entry(self.frm_child_crud, show="*") sep_aux2 = Separator(self.frm_child_crud, orient=VERTICAL) sep_aux2.grid(row=0, column=2, sticky=NS, rowspan=6) frm_aux = Frame(self.frm_child_crud) btn_save = Button(frm_aux, image=self.save_icon, command=self.click_save) btn_save.grid(row=0, column=0, padx=5, pady=5, sticky=E) btn_save_ttp = CreateToolTip(btn_save, 'Save ' + self.title.lower()) btn_cancel = Button(frm_aux, image=self.cancel_icon, command=self.click_cancel) btn_cancel.grid(row=1, column=0, padx=5, pady=5, sticky=E) btn_cancel_ttp = CreateToolTip(btn_cancel, 'Cancel') frm_aux.grid(row=0, column=3, pady=10, padx=25, sticky=N, rowspan=6) def retrieve_list(self): """ Method that retrieve users information from the server and displays them in the TreeView from the List Form """ # Remove existing elements in the list for item in self.trv_available.get_children(): self.trv_available.delete(item) # Retrieve information from the server if self.title == 'Experimenter': self.directive = Message(action=17) elif self.title == 'Designer': self.directive = Message(action=22) elif self.title == 'Administrator': self.directive = Message(action=12) else: raise Exception('Error en recuperacion: tipo de usuario') self.connection = self.directive.send_directive(self.connection) # Adding elements in the list for index, item in enumerate(self.connection.message.information): elements = item.split('¥') self.trv_available.insert('', 'end', text=elements[0], values=(index + 1, elements[1], elements[2], elements[3])) # Mark first element of the treeview if exist if len(self.trv_available.get_children()) != 0: self.trv_available.selection_set( self.trv_available.get_children()[0]) def show_frm(self): """ Show the List form when the User administration is called """ self.retrieve_list() self.frm_child_list.grid(row=1, column=0, columnspan=9, rowspan=8, pady=10, padx=10) def hide_frm(self): """ Hide the User administration Forms """ self.clear_fields() self.frm_child_list.grid_forget() self.frm_child_crud.grid_forget() def click_new(self): """ Initialize CRUD Form for creating a new user. """ self.user = Designer() self.frm_child_list.grid_forget() self.txt_name.focus_set() self.frm_child_crud['text'] = 'New ' + self.title.lower() self.lbl_passwd.grid(row=3, column=0, pady=10, padx=20, sticky=W) self.lbl_passwd_conf.grid(row=4, column=0, pady=10, padx=20, sticky=W) self.txt_passwd.grid(row=3, column=1, pady=10, padx=20, sticky=W) self.txt_passwd_conf.grid(row=4, column=1, pady=10, padx=20, sticky=W) self.frm_child_crud.grid(row=1, column=0, columnspan=9, rowspan=8, pady=10, padx=10) def click_update(self): """ Initialize CRUD Form for updating a user. It loads information of selected User into visual components """ if len(self.trv_available.selection()) == 1: id_selected = int( self.trv_available.item( self.trv_available.selection())['text']) if self.title == 'Experimenter': self.directive = Message(action=20, information=[id_selected]) elif self.title == 'Designer': self.directive = Message(action=25, information=[id_selected]) else: self.directive = Message(action=15, information=[id_selected]) self.connection = self.directive.send_directive(self.connection) if self.connection.message.action == 5: # An error ocurred while trying to update the item messagebox.showerror( parent=self.frm_child_list, title='Can not update the item', message=self.connection.message.information[0]) else: self.user = Designer( id=id_selected, name=self.connection.message.information[0], surname=self.connection.message.information[1], user=self.connection.message.information[2], password=self.connection.message.information[3]) self.txt_name.insert(0, self.user.name) self.txt_surname.insert(0, self.user.surname) self.txt_email.insert(0, self.user.user) self.frm_child_list.grid_forget() self.txt_name.focus_set() self.frm_child_crud['text'] = 'Update ' + self.title.lower() self.lbl_old_passwd.grid(row=3, column=0, pady=10, padx=20, sticky=W) self.lbl_passwd.grid(row=4, column=0, pady=10, padx=20, sticky=W) self.lbl_passwd_conf.grid(row=5, column=0, pady=10, padx=20, sticky=W) self.txt_old_passwd.grid(row=3, column=1, pady=10, padx=20, sticky=W) self.txt_passwd.grid(row=4, column=1, pady=10, padx=20, sticky=W) self.txt_passwd_conf.grid(row=5, column=1, pady=10, padx=20, sticky=W) self.frm_child_crud.grid(row=1, column=0, columnspan=9, rowspan=8, pady=10, padx=10) else: messagebox.showwarning(parent=self.frm_child_list, title='No selection', message='You must select one item') def click_delete(self): """ Method that removes a selected user from the initial list (changes are updated in DB) """ if len(self.trv_available.selection()) == 1: decision = messagebox.askyesno( parent=self.frm_child_list, title='Confirmation', message='Are you sure you want to delete the item?') if decision: id_selected = int( self.trv_available.item( self.trv_available.selection())['text']) if self.title == 'Experimenter': self.directive = Message(action=19, information=[id_selected]) elif self.title == 'Designer': self.directive = Message(action=24, information=[id_selected]) else: self.directive = Message(action=14, information=[id_selected]) self.connection = self.directive.send_directive( self.connection) if self.connection.message.action == 5: # An error ocurred while deleting the item messagebox.showerror( parent=self.frm_child_list, title='Can not delete the item', message=self.connection.message.information[0]) else: self.retrieve_list() else: messagebox.showwarning(parent=self.frm_child_list, title='No selection', message='You must select one item') def click_save(self): """ Saves information of the user inserted into the visual components and sends to the server """ if self.validate_fields(): self.user.name = self.txt_name.get() self.user.surname = self.txt_surname.get() self.user.user = self.txt_email.get() self.user.password = self.txt_passwd.get() if self.user.id == 0: # Creating an user if self.title == 'Experimenter': self.directive = Message( action=16, information=[ self.user.name, self.user.surname, self.user.user, hashlib.sha1( self.user.password.encode()).hexdigest() ]) elif self.title == 'Designer': self.directive = Message( action=21, information=[ self.user.name, self.user.surname, self.user.user, hashlib.sha1( self.user.password.encode()).hexdigest() ]) else: self.directive = Message( action=11, information=[ self.user.name, self.user.surname, self.user.user, hashlib.sha1( self.user.password.encode()).hexdigest() ]) else: # Updating an user if self.title == 'Experimenter': self.directive = Message( action=18, information=[ self.user.id, self.user.name, self.user.surname, self.user.user, hashlib.sha1( self.user.password.encode()).hexdigest() ]) elif self.title == 'Designer': self.directive = Message( action=23, information=[ self.user.id, self.user.name, self.user.surname, self.user.user, hashlib.sha1( self.user.password.encode()).hexdigest() ]) else: self.directive = Message(action=13, information=[ self.user.id, self.user.name, self.user.surname, self.user.user, self.user.password ]) self.connection = self.directive.send_directive(self.connection) if self.connection.message.action == 5: messagebox.showwarning(parent=self.frm_child_crud, title='Repeated e-mail', message=self.connection.message.comment) else: self.clear_fields() self.frm_child_crud.grid_forget() self.show_frm() def click_cancel(self): """ Function activated when 'Cancel' button is pressed in frm_child_crud """ decision = True if self.txt_name.get() != self.user.name or \ self.txt_surname.get() != self.user.surname or \ self.txt_email.get() != self.user.user or len(self.txt_passwd.get()) != 0 or \ len(self.txt_passwd_conf.get()) != 0: if self.user.id != 0 and len( self.txt_passwd_conf.get()) != 0 or self.user.id == 0: decision = messagebox.askyesno( parent=self.frm_child_crud, title='Cancel', message='Are you sure you want to cancel?') if decision: self.clear_fields() self.frm_child_crud.grid_forget() self.show_frm() def validate_fields(self): if len(self.txt_name.get()) == 0: messagebox.showwarning( parent=self.frm_child_crud, title='Missing information', message='You must insert a name for the {}'.format( self.title.lower())) return False if len(self.txt_surname.get()) == 0: messagebox.showwarning( parent=self.frm_child_crud, title='Missing information', message='You must insert a surname for the {}'.format( self.title.lower())) return False if len(self.txt_email.get()) == 0: messagebox.showwarning( parent=self.frm_child_crud, title='Missing information', message='You must insert an e-mail for the {}'.format( self.title.lower())) return False # If updating an user if self.user.id != 0 and len(self.txt_old_passwd.get()) == 0: messagebox.showwarning( parent=self.frm_child_crud, title='Missing information', message='You must insert the old password for the {}'.format( self.title.lower())) return False if len(self.txt_passwd.get()) == 0: messagebox.showwarning( parent=self.frm_child_crud, title='Missing information', message='You must insert a new password for the {}'.format( self.title.lower())) return False if len(self.txt_passwd_conf.get()) == 0: messagebox.showwarning( parent=self.frm_child_crud, title='Missing information', message='You must confirm the new password for the {}'.format( self.title.lower())) return False if self.txt_passwd.get() != self.txt_passwd_conf.get(): messagebox.showwarning( parent=self.frm_child_crud, title='Password field', message= 'The new password you provided does not match the confirmation' ) return False # If updating an user if self.user.id != 0 and self.user.password != hashlib.sha1( self.txt_old_passwd.get().encode()).hexdigest(): messagebox.showwarning(parent=self.frm_child_crud, title='Old password field', message='The old password is incorrect') return False return True def clear_fields(self): self.txt_name.delete(0, END) self.txt_surname.delete(0, END) self.txt_email.delete(0, END) self.txt_old_passwd.delete(0, END) self.txt_passwd.delete(0, END) self.txt_passwd_conf.delete(0, END) self.lbl_old_passwd.grid_forget() self.lbl_passwd.grid_forget() self.lbl_passwd_conf.grid_forget() self.txt_old_passwd.grid_forget() self.txt_passwd.grid_forget() self.txt_passwd_conf.grid_forget()
class GUIExample(master.Subscriber): def __init__(self): #jumbonet stuff self.net = master.Master() self.net.mainloop() self.output = {} # uuid -> list of lines of output self.processes = {} # uuid/iid -> remote object #the fugly tkinter stuff self.tk = Tk() self.input = StringVar() self.selection = (None, False, False ) #process/remote, is_process, is_remote self.tv = None # treeview self.dsp_global = None self.dsp_process = None def _setup(self): tk = self.tk tk.wm_title("Jumbonet GUI Example") tk.protocol("WM_DELETE_WINDOW", self.shutdown) height = 250 # center: treeview self.tv = Treeview(tk) tv = self.tv tv.config(height=height) # treeview configuration tv["columns"] = ("process", "status") tv.column("process", width=130) tv.column("status", width=70) tv.heading("process", text="Process UUID") tv.heading("status", text="Status") tv.bind("<ButtonRelease-1>", self.row_selected) # right: log windows r_frame = Frame(tk, height=height) scroll = Scrollbar(r_frame) #the global log (top) self.dsp_global = TextDisplay(r_frame, width=70, height=20) self.dsp_global.append("Global information") #the process log (bottom) self.dsp_process = TextDisplay(r_frame, width=70, height=25) self.dsp_process.append("This shows output of the selected process") #left: entry and buttons self.input.set("") l_frame = Frame(tk, width=200, height=height) l = Label(l_frame, text="Start process here") e = Entry(l_frame, textvariable=self.input) buttons = Frame(l_frame) # buttons button_add = Button(buttons, text="Start", command=self.start_process) button_kill = Button(buttons, text="Kill", command=self.kill_process) # packing all of it # frame on left l.pack(side=TOP, fill=X) e.pack(side=TOP, fill=X) button_add.pack(side=LEFT) button_kill.pack(side=LEFT) buttons.pack(side=TOP, fill=X) # applog frame on right scroll.pack(side=RIGHT, fill=Y) self.dsp_global.pack(side=TOP, fill=X) self.dsp_process.pack(side=TOP, fill=X) # top-level pack l_frame.pack(side=LEFT, fill=Y, expand=False) tv.pack(side=LEFT, fill=Y, expand=False) r_frame.pack(side=LEFT, fill=Y, expand=False) def shutdown(self): self.net.shutdown() sys.exit(0) def row_selected(self, a): iid = self.tv.focus() log.debug("Selected: {}".format(iid)) assert (iid is not None) # is it a remote? r = self.net.remotes.get(iid) if r is not None: self.selection = (r, False, True) return # is it a process? #the process we're already showing output from? if self.selection[1] and iid == self.selection[0].uuid: #nothing to do then return # is it another process? p = self.processes[iid] if p is not None: # clear the log and display whats happening on the selected process self.dsp_process.clear() lines = self.output.get(iid) self.dsp_process.append(lines) self.selection = (p, True, False) else: self.selection = (None, False, False) def start_process(self): log.debug("Selected: {}".format(self.selection)) if not self.selection[2]: return cmd = self.input.get() if cmd == "type shell command here ": self.dsp_global.append("\nPlease type a valid shell command") return cmdargs = cmd.split(" ") r = self.selection[0] p = r.popen(cmdargs, self, listen_output=True, listen_error=True, listen_status=True) self.output[p.uuid] = list() self.processes[p.uuid] = p self.tv.insert(parent=self.selection[0].name, index="end", iid=p.uuid, text=cmd, values=(p.uuid, "Running")) self.dsp_global.append("\nStart {} as {} to {}".format( cmd, p.uuid, self.selection)) def kill_process(self): if not self.selection[1]: return p = self.selection[0] if not p.alive: self.dsp_global.append("\nCannot kill {} has alread exited".format( p.uuid)) else: self.dsp_global.append("\nKilling {}".format(self.selection)) p.kill() def _update_process_display(self, remotename, uuid, args, lines): old_output = self.output.get(uuid) old_output.extend(lines) if not self.selection[1]: return # are we showing the same process already? then add them to the log if uuid == self.selection[0].uuid: self.dsp_process.append(lines) self.dsp_process.see(END) def receive_out(self, remotename, uuid, args, lines): self._update_process_display(remotename, uuid, args, lines) def receive_err(self, remotename, uuid, args, lines): self._update_process_display(remotename, uuid, args, lines) def receive_status(self, remotename, uuid, args, exitcode): self.dsp_global.append("\nExit {} aka {} with code".format( args, uuid, exitcode)) self.tv.item(uuid, values=(uuid, "Exited ".format(exitcode))) #### these could also be used to get a nicer output for debugging complex testcases def add_host(self, remote): self.tv.insert("", END, text=remote.name, iid=remote.name, values=[], open=True) def add_process(self, remote, process): self.processes[process.uuid] = remote self.tv.insert(remote.name, END, iid=process.uuid, text=" ".join(process.args), values=(process.uuid, "Running"))
class App(ttk.Frame): def __init__(self, parent=None, *args, **kwargs): self._running = threading.Event() self._stop = threading.Event() self._stop.clear() self.init_UI(parent) self.init() def init_UI(self, parent=None): ttk.Frame.__init__(self, parent) self.parent = parent ''' ### Frame setting ''' self.frame_l = Frame(self.parent) self.frame_l.grid(row=0, column=0, padx=1, pady=1, sticky='NSWE') self.frame_r = Frame(self.parent) self.frame_r.grid(row=0, column=1, padx=1, pady=1, sticky='NSWE') Grid.rowconfigure(self.frame_r, 0, weight=1) Grid.columnconfigure(self.frame_r, 0, weight=1) ''' ### setting_panel ''' self.setting_panel = ttk.LabelFrame(self.frame_l, text=u"设置") self.setting_panel.grid(column=0, row=0, padx=5, pady=0) self.add_btn = Button( self.setting_panel, text=u"添加", command=self.add_btn_click, bg='#2E8B57') self.add_btn.grid(row=0, column=2, padx=1, pady=5, sticky='NWSE') self.new_url = StringVar() self.entry_new_url = Entry( self.setting_panel, textvariable=self.new_url) self.entry_new_url.grid(row=0, column=0, pady=5, columnspan=2, sticky='NWSE') Label(self.setting_panel, text=u'刷新频率(秒):').grid( row=1, column=0, padx=0, pady=5, sticky='NWSE') self.set_btn = Button( self.setting_panel, text=u"设置", command=self.set_btn_click, bg='#2E8B57') self.set_btn.grid(row=1, column=2, pady=5, sticky='NWSE') self.refresh_delay = StringVar() self.entry_refresh_delay = Entry( self.setting_panel, textvariable=self.refresh_delay) self.entry_refresh_delay.grid(row=1, column=1, pady=5, sticky='NWSE') self.refresh_delay.set('60') ''' ### control_panel ''' self.control_panel = ttk.LabelFrame(self.frame_l, text=u"操作") self.control_panel.grid(column=0, row=1, padx=5, pady=0, sticky='NWSE') Grid.columnconfigure(self.control_panel, 0, weight=1) self.displayed_msg = StringVar() self.displayed_msg.set(u'正在初始化...') self.label = Label(self.control_panel, textvariable=self.displayed_msg, bg='#AAAAAA') self.label.grid(row=0, column=0, padx=1, pady=5, rowspan=2, sticky='NWSE') self.start_btn = Button( self.control_panel, text=u"开始", command=self.start_btn_click, bg='#2E8B57') self.start_btn.grid(row=0, column=1, padx=1, pady=5, sticky='NWSE') self.stop_btn = Button( self.control_panel, text=u"停止", command=self.stop_btn_click, bg='#2E8B57') self.stop_btn.grid(row=1, column=1, padx=1, pady=5, sticky='NWSE') ''' ### Treeview ''' self.tree = Treeview( self.frame_r, columns=['c1', 'c2', 'c3'], displaycolumns=['c1', 'c2'], selectmode='browse', ) # 设置每列宽度和对齐方式 self.tree.column('#0', anchor='center', width=60) self.tree.column('c1', anchor='w') self.tree.column('c2', anchor='center', width=80) self.tree.column('c3', anchor='center') # 设置每列表头标题文本 self.tree.heading('c1', text=u'视频名称') self.tree.heading('c2', text=u'发布时间') self.tree.heading('c3', text=u'url') self.tree.grid(row=0, column=0, sticky='NSWE') # ----vertical scrollbar------------ self.vbar = ttk.Scrollbar( self.frame_r, orient=VERTICAL, command=self.tree.yview) self.tree.configure(yscrollcommand=self.vbar.set) self.vbar.grid(row=0, column=1, sticky='NS') ''' # 定义并绑定Treeview组件的鼠标单击事件 ''' menu = Menu(self.frame_r, tearoff=0) menu.add_command(label=u"删除选中行", command=self.delete) def treeviewDoubleClick(event): ''' 如果是根结点,打开个人主页 如果是子节点,打开视频页面 ''' webbrowser.open( self.tree.item(self.tree.selection()[0], "values")[2]) if self.tree.tag_has('unread', self.tree.selection()[0]): self.tree.item( self.tree.selection()[0], image=image_old, tag=['root', 'read']) def treeviewOpen(event): ''' 如果是根结点,打开个人主页 如果是子节点,打开视频页面 ''' if self.tree.tag_has('unread', self.tree.selection()[0]): self.tree.item( self.tree.selection()[0], image=image_old, tag=['root', 'read'] ) def treeviewPopupmenu(event): menu.post(event.x_root, event.y_root) self.tree.bind('<Double-1>', treeviewDoubleClick) self.tree.bind('<<TreeviewOpen>>', treeviewOpen) self.tree.bind('<Button-3>', treeviewPopupmenu) def init(self): if not os.path.exists(DATA_PATH): os.makedirs(DATA_PATH) if not os.path.exists(CONF_PATH): os.makedirs(CONF_PATH) self.data_list = [] files = os.listdir(DATA_PATH) for file in files: with open('%s%s' %(DATA_PATH, file), 'r') as f: data = json.load(f) self.new_watcher(json.dumps(data)) if os.path.exists(CONF_FILE): with open(CONF_FILE, 'r') as f: try: self.refresh_delay.set(json.load(f)['wait_time']) except: pass self.p = threading.Thread(target=self.run) self.delay = int(self.refresh_delay.get()) self.status_audit() def new_watcher(self, data): logging.info('new_watcher') logging.info(data) info = json.loads(data) try: self.tree.insert('', 'end', info['u_id'], text=info['u_name'], image=image_old, values=['', '', info['url']], tag=['root', 'read']) self.data_list.append(info) except Exception, ex: logging.error(ex)