class per(): def __init__(self,data,y,v='план'): w=Toplevel() w.wm_title('Доп') w.columnconfigure(0,weight=1) w.rowconfigure(0,weight=1) years=sorted(data.keys()) cols=data['2013']['degurs'] # ЗАГЛУШКА : список дежурных self.t=Treeview(w,columns=cols) for c in cols: self.t.heading(c,text=c) self.t.column(c,width=65,anchor='center') self.t.tag_configure('табель',background='green') self.t.tag_configure('ош',background='red') #self.t.tag_configure('табель',background='green') self.scrX=Scrollbar(w,orient='horizontal',command=self.t.xview) self.scrY=Scrollbar(w,orient='vertical',command=self.t.yview) self.t['xscrollcommand']=self.scrX.set self.t['yscrollcommand']=self.scrY.set self.t.grid(row=0,column=0,sticky=N+S+E+W) self.scrX.grid(row=1,column=0,sticky=E+W) self.scrY.grid(row=0,column=1,sticky=N+S) for y in years: x=self.t.insert('','end',text=y) eeY=[] for m in ['01','02','03','04','05','06','07','08','09','10','11','12']: d0=data[y] if m not in d0: continue d=d0[m] rez=dict() tag='' if v=='авто': if 'табель' in d['degur']: vv='табель' tag=vv else: vv='план' elif v=='табель': if 'табель' not in d['degur']: vv='план' tag='ош' else: vv=v tag=vv else: vv=v for j,s in d['degur'][vv].items(): rez[j]=analyse2(s,d) NUL=(0,0,0,0,0,0,0) ee=[rez.get(j,NUL)[0]-rez.get(j,NUL)[3]+rez.get(j,NUL)[4] for j in cols] eeY.append(ee) self.t.insert(x,'end',text=m,values=[x or '-' for x in ee],tag=tag) eeY=[sum(x) for x in zip(*eeY)] self.t.insert(x,'end',text='итого',values=eeY,tag='Y')
def show_dic_command(self): if self.dictionary_in_main_memory == False: messagebox.showwarning( "Error", "first, load dictionary to your main memory.\ndon't look at me like this! just do it with the Load Dictionary button\nif you have some time, you can also start the program and after it will be finished, you will be able to show dictionary" ) else: text_of_waiting = Label( self.bottomFrame, text= "Please Wait.. the dictionary will be shown in 10-20 seconds") text_of_waiting.grid(row=0, column=1) self.window.update() self.dictionaryWindow = Toplevel(self.window) self.dictionaryWindow.geometry("400x600") self.dictionaryWindow.title("Main Dictionary") self.dictionaryWindow.resizable(False, False) tree = Treeview(self.dictionaryWindow, selectmode="extended", columns=("term", "tf")) style = ttk.Style() style.configure("Treeview.Heading", background='lavender') tree.pack(expand=YES, fill=BOTH) tree['show'] = 'headings' tree.column("#0", minwidth=10, width=20, stretch=NO) tree.heading("term", text="Term") tree.column("term", minwidth=250, width=200, stretch=NO) tree.heading("tf", text="Frequency in corpus") tree.column("tf", minwidth=180, width=180, stretch=NO) scrollbar = ttk.Scrollbar(self.dictionaryWindow, orient="vertical", command=tree.yview) scrollbar.place(x=380, y=0, height=600) tree.configure(yscrollcommand=scrollbar.set) main_dictionary_pointer = Controller.getMainDictionaryFromIndexerToGUI( ) sorted_main_dictionary = dict( sorted(main_dictionary_pointer.items())) odd = 'odd' even = 'even' i = 0 for key in sorted_main_dictionary: term = key tf = str(sorted_main_dictionary[key].tf_in_corpus) if i % 2 == 0: tag = odd else: tag = even tree.insert('', 'end', values=(term, tf), tags=(tag, )) i = i + 1 tree.tag_configure(odd, background='gold') tree.tag_configure(even, background='deep sky blue') tree.pack() text_of_waiting.grid_remove()
def listVideos(self, chan, target): self.center = target #get chan id chanid = database.get_channel_id(chan) vids = database.get_channel_videos(chanid) tree = Treeview(self.center) tree["columns"] = ("one", "two") tree.column("#0", width=20, minwidth=10, stretch=YES) tree.column("one", width=390, minwidth=250, stretch=YES) tree.column("two", width=200, minwidth=40) tree.heading("#0", text="ID", anchor=W) tree.heading("one", text="Title", anchor=W) tree.heading("two", text="Date", anchor=W) i = 0 tree.tag_configure('oddrow', background='#88DD88') tree.tag_configure('evenrow', background='#FFFFFF') for videodata in vids: foldername = "folder" + str(i) if i % 2 == 0: color = "evenrow" else: color = "oddrow" # tree.insert("", 1, "", text="Folder 1", values=("23-Jun-17 11:05","File folder","")) ts = int(videodata.publish_date) foldername = tree.insert("", "end", text=videodata.yt_videoid, values=(videodata.title, time.ctime(ts)), tags=(color)) #tree.insert(folder1, "end", "", text="photo1.png", values=("23-Jun-17 11:28","PNG file","2.6 KB")) tree.insert(foldername, "end", text="desc", values=(videodata.description, videodata.watched), tags=(color)) i = i + 1 vertscroll = Scrollbar(self.center) vertscroll.config(command=tree.yview) tree.config(yscrollcommand=vertscroll.set) tree.bind("<Button-" + config.mousebuttons + ">", self.video_action_window) tree.grid(row=5, columnspan=3, sticky="NSEW")
def show_feed(self, body, value): center = body tree = Treeview(center) tree["columns"] = ("one", "two") tree.column("#0", width=20, minwidth=10, stretch=YES) tree.column("one", width=390, minwidth=250, stretch=YES) tree.column("two", width=200, minwidth=40) tree.heading("#0", text="ID", anchor=W) tree.heading("one", text="Title", anchor=W) tree.heading("two", text="Date", anchor=W) i = 0 tree.tag_configure('oddrow', background='#88DD88') tree.tag_configure('evenrow', background='#FFFFFF') vids = self.get_feed(value) for videodata in vids: foldername = "folder" + str(i) if i % 2 == 0: color = "evenrow" else: color = "oddrow" ts = int(videodata.publish_date) foldername = tree.insert("", "end", text=i, values=(videodata.title, time.ctime(ts)), tags=(color)) tree.insert(foldername, "end", text="desc", values=(videodata.description, ""), tags=(color)) i = i + 1 vertscroll = Scrollbar(center) vertscroll.config(command=tree.yview) tree.config(yscrollcommand=vertscroll.set) tree.grid(row=5, columnspan=3, sticky="NSEW") vertscroll.grid(column=3, row=5, sticky='NSE')
def print_messages(self, dataFrame): list_box = Treeview(self.messagesBox, columns=self.col_names, show='headings', height=19) #height is in number of rows:) for col in self.col_names: list_box.heading(col, text=col) list_box.grid(row=0, column=0, sticky='nsew', in_=self.messagesBox) list_box.tag_configure('odd', background='#f9f9f9') list_box.tag_configure('even', background='#DFDFDF') list_box.column("Timestamp", width=150) list_box.column("Data", width=400) scroll_bar = Scrollbar(self.messagesBox, orient="vertical", command=list_box.yview) scroll_bar.grid(row=0, column=1, sticky='ns') list_box.configure(yscrollcommand=scroll_bar.set) for index, row in dataFrame.iterrows(): type = 'even' if (len(list_box.get_children()) % 2 == 1): type = 'odd' list_box.insert("", "end", values=(row.Timestamp, row.Data), tags=(type,)) list_box.bind("<<TreeviewSelect>>", lambda event, t=list_box: self.message_click(event, t))
def lang_command(self): if self.finished_program == False and self.loaded_index == False: messagebox.showwarning( "Error", "first, start indexing your corpus or load index files. then you'll be able to see the languages" ) else: self.lang_window = Toplevel(self.window) self.lang_window.geometry("200x400") self.lang_window.title("Languages List") self.lang_window.resizable(False, False) tree = Treeview(self.lang_window, selectmode="extended", columns=("lang")) tree.pack(expand=YES, fill=BOTH) tree['show'] = 'headings' tree.heading("lang", text="Language") tree.column("lang", minwidth=180, width=180, stretch=NO) scrollbar = ttk.Scrollbar(self.lang_window, orient="vertical", command=tree.yview) scrollbar.place(x=180, y=0, height=400) tree.configure(yscrollcommand=scrollbar.set) odd = 'odd' even = 'even' list_of_langs = Controller.getLangList() sorted_list_of_langs = sorted(list_of_langs) i = 0 for x in sorted_list_of_langs: if i % 2 == 0: tag = odd else: tag = even tree.insert('', 'end', values=(x), tags=(tag, )) i = i + 1 tree.tag_configure(odd, background='hot pink') tree.tag_configure(even, background='deep pink')
def createChat(self, nom, enable=True): """Créer un nouveau chat pour un joueur donné. Arguments: nom - Le nom du joueur avec lequel l'utilisateur pourra parler avec ce chat Keyword Arguments: enable -- Est-ce que le chat doit être activer par défaut. (default: {True}) """ frame = tk.Frame(self.notebook) self.notebook.add(frame, text=nom) chat = Treeview(frame, height=15) chat['columns'] = ('Date') chat.heading("#0", text='Messages', anchor=tk.W) chat.heading('Date', text='Date', anchor=tk.W) chat.column('Date', anchor=tk.W, width=150) chat.grid(row=0, column=0, columnspan=2, rowspan=3, sticky=tk.NSEW) chat.tag_configure('even', background='#DAE5F4') chat.tag_configure('odd', background='#B8D1F3') chat.tag_configure('from_me', font=("Helvetica", 10, "bold")) chat.tag_configure('not_from_me', font=("Helvetica", 10)) messageEntry = tk.Entry(frame) messageEntry.grid(row=4, column=0, sticky=tk.S) messageButton = tk.Button(frame) messageButton["text"] = "Envoyer" if not enable: messageButton["state"] = tk.DISABLED messageButton["bg"] = "#1296EC" messageButton["activebackground"] = "#33A5EF" messageButton["fg"] = "#FFFFFF" messageButton["activeforeground"] = "#FFFFFF" messageButton["relief"] = tk.FLAT messageButton["bd"] = 0 messageButton["command"] = lambda: self.sendMessage(nom, messageEntry) messageButton.grid(row=4, column=1, sticky=tk.S) self.chats[nom] = [frame, chat, messageEntry, messageButton, 0]
class statistic_q(): def __init__(self,data,y,v='план'): w=Toplevel() w.wm_title('Поквартальная статистика за {0} год ({1})'.format(y,v)) w.columnconfigure(0,weight=1) w.rowconfigure(0,weight=1) cols=data[y]['degurs'] # ЗАГЛУШКА : список дежурных self.t=Treeview(w,columns=cols) self.t.column('#0',width=120) for c in cols: self.t.heading(c,text=c) self.t.column(c,width=65,anchor='center') self.t.tag_configure('табель',background='green') self.t.tag_configure('ош',background='red') self.scrX=Scrollbar(w,orient='horizontal',command=self.t.xview) self.scrY=Scrollbar(w,orient='vertical',command=self.t.yview) self.t['xscrollcommand']=self.scrX.set self.t['yscrollcommand']=self.scrY.set self.t.grid(row=0,column=0,sticky=N+S+E+W) self.scrX.grid(row=1,column=0,sticky=E+W) self.scrY.grid(row=0,column=1,sticky=N+S) r=self.t.insert('','end',text='рабочих') w=self.t.insert('','end',text='отработано') e=self.t.insert('','end',text='дополнительные') n=self.t.insert('','end',text='ночные') h=self.t.insert('','end',text='праздничные') x=self.t.insert('','end',text='xxx') rz_root=self.t.insert('','end',text='резерв') rez=dict() wwY=[] rrY=[] eeY=[] xxY=[] nnY=[] hhY=[] rzY=[] for mm in [1,2,3,4]: mmm=[str((mm-1)*3+x).zfill(2) for x in [1,2,3]] mmm=[x for x in mmm if x in data[y]] tag='' k=['табель' in data[y][m]['degur'] for m in mmm] #print(k) if v=='авто': if k==[True, True, True]: vv='табель' tag=vv else: vv='план' elif v=='табель': if k!=[True, True, True]: vv='план' tag='ош' else: vv=v tag=vv else: vv=v ww=[] rr=[] ee=[] xx=[] nn=[] hh=[] rz=[] for m in mmm: d=data[y][m] for j in cols: s=d['degur'][vv].get(j,'*ООООООООООООООООООООООООООООООО*') rez[j]=analyse2(s,d) NUL=(0,0,0,0,0,0,0) ww.append([rez.get(j,NUL)[0] for j in cols]) ee.append([rez.get(j,NUL)[0]-rez.get(j,NUL)[3] + \ rez.get(j,NUL)[4] for j in cols]) xx.append([rez.get(j,NUL)[0]-rez.get(j,NUL)[3] for j in cols]) rr.append([rez.get(j,NUL)[3]-rez.get(j,NUL)[4] for j in cols]) nn.append([rez.get(j,NUL)[1] for j in cols]) hh.append([rez.get(j,NUL)[2] for j in cols]) rz.append([rez.get(j,NUL)[5] for j in cols]) ww=[sum(x) for x in zip(*ww)] rr=[sum(x) for x in zip(*rr)] ee=[sum(x) for x in zip(*ee)] xx=[sum(x) for x in zip(*xx)] nn=[sum(x) for x in zip(*nn)] hh=[sum(x) for x in zip(*hh)] rz=[sum(x) for x in zip(*rz)] wwY.append(ww) rrY.append(rr) eeY.append(ee) xxY.append(xx) nnY.append(nn) hhY.append(hh) rzY.append(rz) self.t.insert(w,'end',text=mm,values=ww,tag=tag) self.t.insert(r,'end',text=mm,values=rr,tag=tag) self.t.insert(n,'end',text=mm,values=nn,tag=tag) self.t.insert(h,'end',text=mm,values=hh,tag=tag) self.t.insert(e,'end',text=mm,values=ee,tag=tag) self.t.insert(x,'end',text=mm,values=xx,tag=tag) self.t.insert(rz_root,'end',text=mm,values=rz,tag=tag) wwY=[sum(x) for x in zip(*wwY)] rrY=[sum(x) for x in zip(*rrY)] eeY=[sum(x) for x in zip(*eeY)] xxY=[sum(x) for x in zip(*xxY)] nnY=[sum(x) for x in zip(*nnY)] hhY=[sum(x) for x in zip(*hhY)] rzY=[sum(x) for x in zip(*rzY)] self.t.insert(w,'end',text='итого',values=wwY,tag='Y') self.t.insert(r,'end',text='итого',values=rrY,tag='Y') self.t.insert(n,'end',text='итого',values=nnY,tag='Y') self.t.insert(h,'end',text='итого',values=hhY,tag='Y') self.t.insert(e,'end',text='итого',values=eeY,tag='Y') self.t.insert(x,'end',text='итого',values=xxY,tag='Y') self.t.insert(rz_root,'end',text='итого',values=rzY,tag='Y')
class show: def __init__(self): self.window=Tk() self.window.title("Show | All Products") self.window.iconbitmap('shop.ico') self.window.geometry("1365x700+10+10") self.window.maxsize(1365,700) self.window.minsize(1365,700) # self.window.resizable(width=False,height=False) def add_background(self): self.image = Image.open("images/back.jpg") self.image = self.image.resize((1365, 700), Image.ANTIALIAS) self.img = ImageTk.PhotoImage(self.image) self.li = Label(image = self.img, text="TALHA") self.li.image = self.img self.li.pack() self.Menubar() def Menubar(self): self.menubar = Menu() self.menuitems_add = Menu(self.menubar, tearoff=0,bg="blue",fg="white") self.menuitems_add.add_command(label="Add Products", command=self.add_products) # self.menuitems.add_separator() self.menuitems_sales = Menu(self.menubar, tearoff=0,bg="blue",fg="white") self.menuitems_sales.add_command(label="Sale Products", command=self.sales_products) self.menuitems_customer = Menu(self.menubar, tearoff=0, bg="blue", fg="white") self.menuitems_customer.add_command(label="Add Customer", command=self.add_customer) self.menuitems_customer.add_command(label="Show Customer Records", command=self.customer_record) self.menuitems_reports = Menu(self.menubar, tearoff=0, bg="blue", fg="white") self.menuitems_reports.add_command(label="Check Products Quantity", command=self.check_products_quantity) self.menuitems_reports.add_command(label="Check Profit/Loss", command=self.check_profit_loss) self.menuitems_reports.add_command(label="Check Sales Products", command=self.check_products_sales) self.menuitems_reports.add_command(label="Check Sent Amount Details", command=self.check_amount) self.menubar.add_cascade(label="Add Products", menu=self.menuitems_add) self.menubar.add_cascade(label="Sales Products", menu=self.menuitems_sales) self.menubar.add_cascade(label="Customer", menu=self.menuitems_customer) self.menubar.add_cascade(label="Reports", menu=self.menuitems_reports) self.menubar.add_cascade(label="Exit", command=quit) self.window.config(menu=self.menubar) def add_table(self): self.l1=Label(self.window,text="**Products Details**",font="Courier 25 bold",bg="black",fg="white",width=61) self.l1.place(x=82,y=20) self.l1 = Label(self.window, text="Developed by : Muhammad Talha | NTU", font="Courier 10 bold") self.l1.place(x=530, y=610) self.l1 = Label(self.window, text="Enter Product Name:", font="courier 16 bold",bg="blue",fg="white") self.l1.place(x=280, y=90) self.Entry_reg = Entry(self.window, font="courior 14 bold") self.Entry_reg.place(x=550, y=90, height=30) self.b1 = Button(self.window, text="Search", font="Times 13 bold",fg="white",bg="blue",width=10) self.b1.place(x=790, y=90) self.b1.bind('<Button-1>', self.search_product) # for Style Table style = Style() style.configure("mystyle.Treeview", highlightthickness=0, bd=0, font=('courier 12 bold'),rowheight=43) # Modify the font of the body style.configure("mystyle.Treeview.Heading", font=('Times 15 bold'),foreground="black") # Modify the font of the headings # style.layout("mystyle.Treeview", [('mystyle.Treeview.treearea', {'sticky': 'nswe'})]) # Remove the borders # import TreeViewe self.tr=Treeview(self.window,columns=('A','B','C','D','E','F','G','H'),selectmode="extended",style='mystyle.Treeview') # heading key+text self.tr.heading("#0", text="Sr.No") self.tr.column("#0", minwidth=0, width=85, stretch=NO) self.tr.heading("#1",text="Product Name") self.tr.column("#1",minwidth=0,width=160,stretch=NO) self.tr.heading("#2", text="Product Catagory") self.tr.column("#2", minwidth=0, width=200, stretch=NO) self.tr.heading("#3", text="Total Quantity") self.tr.column("#3", minwidth=0, width=175, stretch=NO) self.tr.heading("#4", text="Purchase Price") self.tr.column("#4", minwidth=0, width=175, stretch=NO) self.tr.heading("#5", text="Sales Price") self.tr.column("#5", minwidth=0, width=160, stretch=NO) self.tr.heading("#6", text="Update") self.tr.column("#6", minwidth=0, width=85, stretch=NO) self.tr.heading("#7", text="Delete") self.tr.column("#7", minwidth=0, width=85, stretch=NO) self.tr.heading("#8", text="Sales") self.tr.column("#8", minwidth=0, width=100, stretch=NO) j=1 for i in Database.show_product_details(): self.tr.insert('',index=j,tags=i[0],text=j,values=(i[1],i[2],i[3],i[4],i[5],"UPDATE","DELETE","SALES")) j+=1 self.Entry_reg.bind('<KeyRelease>', self.remove) self.tr.bind('<Double-Button-1>',self.action) self.sb = Scrollbar(self.tr) self.sb.place(x=1205,y=2,height=452,width=22,bordermode=OUTSIDE) self.sb.config(command=self.tr.yview) self.tr.config(yscrollcommand=self.sb.set) self.tr.place(x=85,y=150) self.tr.tag_configure('data', background='black') # to excel file self.b1 = Button(self.window, text="Save to Excel", font="Times 12 bold",bg="blue",fg="white",width=20, ) self.b1.place(x=1122, y=610) self.b1.bind('<Button-1>', self.excel) self.window.mainloop() def action(self,event): fcs=self.tr.focus() col=self.tr.identify_column(event.x) x=self.tr.item(fcs).get('values') text=x[1] data=( text, ) if col=="#7": res=msg.askyesno("Message!","Do you want to delete this product?") if res: d=Database.delete_details(data) if d: msg.showinfo("Deleted","Your product has been deleted successfully!!!") self.window.destroy() x=show() x.add_background() x.add_table() else: self.window.destroy() x=show() x.add_table() elif col=="#6": x=Home.data(self.tr.item(fcs)) x.add_frame() elif col=="#8": x = Sales_Products_Records.data(self.tr.item(fcs)) x.add_frame() def remove(self,event): for row in self.tr.get_children(): self.tr.delete(row) j = 1 for i in Database.show_product_details(): self.tr.insert('', index=j, text=j, values=(i[1], i[2], i[3], i[4], i[5], "UPDATE", "DELETE", "SALES")) j += 1 def search_product(self,event): try: data = (self.Entry_reg.get(),) if self.Entry_reg.get() == "": msg.showwarning("Message ! ", "please insert product name !") else: j = 1 D = Database.search_details(data) if D: for row in self.tr.get_children(): self.tr.delete(row) self.Entry_reg.delete(0, END) for i in D: self.tr.insert('', index=j, text=j, values=(i[1],i[2],i[3],i[4],i[5],"UPDATE","DELETE","SALES")) j += 1 else: msg.showwarning("Message!", "No result Found!") except: msg.showwarning("Error!", "Something went wrong! please contact with developer !!!") def excel(self,event): try: x=Database.show_product_details() p_name=[] p_catagory=[] p_quantity=[] p_purchase_price=[] p_sales_price=[] for i in range(len(x)): z=x.__getitem__(i) p_name.append(z[1]) p_catagory.append(z[2]) p_quantity.append(z[3]) p_purchase_price.append(z[4]) p_sales_price.append(z[5]) products = pd.DataFrame({ "Product Name": p_name, "Product Catagory":p_catagory, "Total Quantity":p_quantity, "Purchase Price":p_purchase_price, "Sales Price":p_sales_price }) with pd.ExcelWriter("Excel Files/All_Products.xlsx") as writer: products.to_excel(writer, sheet_name="All_Products", index=False) msg.showinfo("Message ! ", "Your data has been inserted Susccessfully !") except: msg.showwarning("Message!","Something Went Wrong!please contact with developer!!!") def add_products(self): self.window.destroy() home = Home.data() home.add_background() home.add_frame() def sales_products(self): pass def check_products_quantity(self): self.window.destroy() showP = Check_Products_Quantity.show() showP.add_background() showP.add_table() def check_products_sales(self): self.window.destroy() showP = Check_Sales_Products.show() showP.add_background() showP.add_table() def check_profit_loss(self): self.window.destroy() showP = Check_Profit_Loss_GUI.show() showP.add_background() showP.add_table() def add_customer(self): self.window.destroy() home = Add_Customer.data() home.add_background() home.add_frame() def customer_record(self): self.window.destroy() showP = Customer_Records.show() showP.add_background() showP.add_table() def check_amount(self): self.window.destroy() showP = Check_Amount_Details.show() showP.add_background() showP.add_table()
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') root.mainloop()
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)
#定义并绑定Treeview组件的鼠标单击事件 def treeviewClick(event): pass tree.bind('<Button-1>', treeviewClick) #插入演示数据 for i in range(10): tree.insert('', i, values=[str(i)] * 6) #遍历items 设置标签 items = tree.get_children() for each in range(len(items)): print(items[each]) if each % 2 == 1: tree.item(items[each], tags=('oddrow')) #对标签进行设置 foreground, background, image ,font=("微软雅黑", 12, "bold") tree.tag_configure('oddrow', background='#eeeeff', font=("微软雅黑", 12, "bold")) #运行程序,启动事件循环 root.mainloop()
tree_Fornecedor.column('#3', stretch=YES, width=140, minwidth=140, anchor=CENTER) tree_Fornecedor.column('#2', stretch=YES, width=300, minwidth=300, anchor=W) tree_Fornecedor.column('#1', stretch=YES, width=160, minwidth=160, anchor=CENTER) tree_Fornecedor.column('#0', stretch=YES, width=60, minwidth=60, anchor=CENTER) tree_Fornecedor.place(x=0, y=5) #tree_Fornecedor.tag_configure('MonoMetas', background=Branco, font=Fonte12, foreground=Preto) tree_Fornecedor.tag_configure('oddrow', background=Cinza40, font=Fonte12, foreground=Branco) barra3 = Scrollbar(tree_Fornecedor, orient='vertical', command=tree_Fornecedor.yview) barra3.place(x=828, y=1, height=225) tree_Fornecedor.configure(yscrollcommand=barra3.set) # --------------------------------------------------------------------------------------------------------------------- # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-= # Labels do Total da Nota Lb_Desc = Label(FrTotal, bg=Cinza40, text="DESC:", fg=Branco, font=Fonte12B) Lb_Desc.place(x=44, y=8, height=20) LbTotal_Desc = Label(FrTotal, bg=Cinza40, text="R$ 0.00", fg=Branco,
class MainWindowUI: """ rows and columns divide the widget region (row,column) ------------------------------------------------ 0 toolbar filepath ------------------------------------------------ 1 0 filetree | 1 scrbar | 2 lineno| 3 TextArea| -------------|----------| --------|-----------| """ # Rows toolBarRow = 0 fileTreeRow = 1 filePathLabelsRow = 0 searchTextRow = 1 uniScrollbarRow = lineNumbersRow = textAreasRow = 2 horizontalScrollbarRow = 3 # Columns fileTreeCol = 0 fileTreeScrollbarCol = 1 leftFilePathLabelsCol = 3 leftLineNumbersCol = 2 # leftLineNumbersCol = leftFilePathLabelsCol = 3 # should span at least two columns leftTextAreaCol = leftHorizontalScrollbarCol = 4 uniScrollbarCol = 5 rightLineNumbersCol = rightFilePathLabelsCol = 6 # should span at least two columns rightTextAreaCol = rightHorizontalScrollbarCol = 7 leftLineButtonsCol = 3 rightLineButtonscol = 9 # Colors whiteColor = '#ffffff' redColor = '#ffc4c4' darkredColor = '#ff8282' grayColor = '#dddddd' lightGrayColor = '#eeeeee' greenColor = '#c9fcd6' darkgreenColor = '#50c96e' yellowColor = '#f0f58c' darkYellowColor = '#ffff00' def __init__(self, window): self.main_window = window self.main_window.grid_rowconfigure(self.toolBarRow, weight=0) self.main_window.grid_rowconfigure(self.filePathLabelsRow, weight=0) self.main_window.grid_rowconfigure(self.searchTextRow, weight=0) self.main_window.grid_rowconfigure(self.textAreasRow, weight=1) self.main_window.grid_columnconfigure(self.fileTreeCol, weight=0) self.main_window.grid_columnconfigure(self.fileTreeScrollbarCol, weight=0) self.main_window.grid_columnconfigure(self.leftLineNumbersCol, weight=0) self.main_window.grid_columnconfigure(self.leftLineButtonsCol, weight=0) # left buttons col self.main_window.grid_columnconfigure(self.leftTextAreaCol, weight=1) self.main_window.grid_columnconfigure(self.uniScrollbarCol, weight=0) self.main_window.grid_columnconfigure(self.rightLineNumbersCol, weight=0) self.main_window.grid_columnconfigure(self.rightLineButtonscol, weight=0) # right buttons col self.main_window.grid_columnconfigure(self.rightTextAreaCol, weight=1) self.menubar = Menu(self.main_window) self.menus = {} self.text_area_font = 'TkFixedFont' # Center window and set its size def center_window(self): sw = self.main_window.winfo_screenwidth() sh = self.main_window.winfo_screenheight() w = 0.7 * sw h = 0.7 * sh x = (sw - w) / 2 y = (sh - h) / 2 self.main_window.geometry('%dx%d+%d+%d' % (w, h, x, y)) self.main_window.minsize(int(0.3 * sw), int(0.3 * sh)) # Menu bar def add_menu(self, menuName, commandList): self.menus[menuName] = Menu(self.menubar, tearoff=0) for c in commandList: if 'separator' in c: self.menus[menuName].add_separator() else: self.menus[menuName].add_command( label=c['name'], command=c['command'], accelerator=c['accelerator'] if 'accelerator' in c else '') self.menubar.add_cascade(label=menuName, menu=self.menus[menuName]) self.main_window.config(menu=self.menubar) # Labels def create_file_path_labels(self): self.leftFileLabel = Label(self.main_window, anchor='center', width=1000, background=self.lightGrayColor) self.leftFileLabel.grid(row=self.filePathLabelsRow, column=self.leftFilePathLabelsCol, columnspan=2) self.rightFileLabel = Label(self.main_window, anchor='center', width=1000, background=self.lightGrayColor) self.rightFileLabel.grid(row=self.filePathLabelsRow, column=self.rightFilePathLabelsCol, columnspan=2) # Search text entnry def create_search_text_entry(self, searchButtonCallback): self.searchTextDialog = SearchTextDialog( self.main_window, [self.leftFileTextArea, self.rightFileTextArea], searchButtonCallback) self.searchTextDialog.grid(row=self.searchTextRow, column=self.leftFilePathLabelsCol, columnspan=5, sticky=EW) self.searchTextDialog.grid_remove() # File treeview def create_file_treeview(self): self.fileTreeView = Treeview(self.main_window) self.fileTreeYScrollbar = Scrollbar(self.main_window, orient='vertical', command=self.fileTreeView.yview) self.fileTreeXScrollbar = Scrollbar(self.main_window, orient='horizontal', command=self.fileTreeView.xview) self.fileTreeView.configure(yscroll=self.fileTreeYScrollbar.set, xscroll=self.fileTreeXScrollbar.set) self.fileTreeView.grid(row=self.fileTreeRow, column=self.fileTreeCol, sticky=NS, rowspan=3) self.fileTreeYScrollbar.grid(row=self.fileTreeRow, column=self.fileTreeScrollbarCol, sticky=NS, rowspan=3) self.fileTreeXScrollbar.grid(row=self.horizontalScrollbarRow, column=self.fileTreeCol, sticky=EW) self.fileTreeView.tag_configure('red', background=self.redColor) self.fileTreeView.tag_configure('green', background=self.greenColor) self.fileTreeView.tag_configure('yellow', background=self.yellowColor) # hide it until needed self.fileTreeView.grid_remove() self.fileTreeYScrollbar.grid_remove() self.fileTreeXScrollbar.grid_remove() # Line buttons def create_tree_buttons(self): # self.leftLinebuttons = Treeview(self.main_window) # self.leftLinebuttons.grid(row=self.lineNumbersRow, column=self.leftLineButtonsCol, sticky=NS, rowspan=1) # self.leftLinebuttons.tag_configure('green', background=self.greenColor) # # self.rightLinebuttons = Treeview(self.main_window) # self.rightLinebuttons.grid(row=self.lineNumbersRow, column=self.rightLineButtonscol, sticky=NS, rowspan=1) # self.rightLinebuttons.tag_configure('green', background=self.greenColor) # # self.leftLinebuttons.insert('', 'end', text="test", open=True, tags=('green', 'simple')) # self.rightLinebuttons.insert('', 'end', text="test", open=True, tags=('green', 'simple')) # # # disable the line numbers # self.leftLinebuttons.grid_remove() # self.rightLinebuttons.grid_remove() self.leftLinebuttons = Text(self.main_window, width=1, padx=5, pady=5, height=1, bg=self.lightGrayColor) self.leftLinebuttons.grid(row=self.lineNumbersRow, column=self.leftLineButtonsCol, sticky=NS) self.leftLinebuttons.config(font=self.text_area_font) self.leftLinebuttons.tag_configure('line', justify='right') self.leftLinebuttons.tag_configure('green', background=self.greenColor) # self.rightLinebuttons = Text(self.main_window, width=1, padx=5, pady=5, height=1, bg=self.lightGrayColor) # self.rightLinebuttons.grid(row=self.lineNumbersRow, column=self.leftLineButtonsCol, sticky=NS) # self.rightLinebuttons.config(font=self.text_area_font) # self.rightLinebuttons.tag_configure('line', justify='right') # self.rightLinebuttons.tag_configure('green', background=self.greenColor) ops1 = StringVar() ops1.set((11, 22, 33, 44, 55)) self.rightLinebuttons = Listbox(self.main_window, listvariable=ops1) self.rightLinebuttons.grid(row=self.lineNumbersRow, column=self.rightLineButtonscol, sticky=NS, padx=1, ipadx=1) self.rightLinebuttons.config(font=self.text_area_font) # self.rightLinebuttons.bindtags('line', justify='right') # self.rightLinebuttons.bindtags('green', background=self.greenColor) self.leftLinenumbers.config(state=DISABLED) self.rightLinenumbers.config(state=DISABLED) # Text areas def create_text_areas(self): self.leftFileTextArea = Text(self.main_window, padx=5, pady=5, width=1, height=1, bg=self.grayColor) self.leftFileTextArea.grid(row=self.textAreasRow, column=self.leftTextAreaCol, sticky=NSEW) self.leftFileTextArea.config(font=self.text_area_font) self.leftFileTextArea.config(wrap='none') self.rightFileTextArea = Text(self.main_window, padx=5, pady=5, width=1, height=1, bg=self.grayColor) self.rightFileTextArea.grid(row=self.textAreasRow, column=self.rightTextAreaCol, sticky=NSEW) self.rightFileTextArea.config(font=self.text_area_font) self.rightFileTextArea.config(wrap='none') # configuring highlight tags self.leftFileTextArea.tag_configure('red', background=self.redColor) self.leftFileTextArea.tag_configure('darkred', background=self.darkredColor) self.leftFileTextArea.tag_configure('gray', background=self.grayColor) self.leftFileTextArea.tag_configure('search', background=self.darkYellowColor) self.rightFileTextArea.tag_configure('green', background=self.greenColor) self.rightFileTextArea.tag_configure('darkgreen', background=self.darkgreenColor) self.rightFileTextArea.tag_configure('gray', background=self.grayColor) self.rightFileTextArea.tag_configure('search', background=self.darkYellowColor) # disable the text areas self.leftFileTextArea.config(state=DISABLED) self.rightFileTextArea.config(state=DISABLED) # Line numbers def create_line_numbers(self): self.leftLinenumbers = Text(self.main_window, width=3, padx=5, pady=5, height=1, bg=self.lightGrayColor) self.leftLinenumbers.grid(row=self.lineNumbersRow, column=self.leftLineNumbersCol, sticky=NS) self.leftLinenumbers.config(font=self.text_area_font) self.leftLinenumbers.tag_configure('line', justify='right') self.rightLinenumbers = Text(self.main_window, width=3, padx=5, pady=5, height=1, bg=self.lightGrayColor) self.rightLinenumbers.grid(row=self.lineNumbersRow, column=self.rightLineNumbersCol, sticky=NS) self.rightLinenumbers.config(font=self.text_area_font) self.rightLinenumbers.tag_configure('line', justify='right') # disable the line numbers self.leftLinenumbers.config(state=DISABLED) self.rightLinenumbers.config(state=DISABLED) # Scroll bars def scrollBoth(self, action, position, type=None): self.leftFileTextArea.yview_moveto(position) self.rightFileTextArea.yview_moveto(position) self.leftLinenumbers.yview_moveto(position) self.rightLinenumbers.yview_moveto(position) def updateScroll(self, first, last, type=None): self.leftFileTextArea.yview_moveto(first) self.rightFileTextArea.yview_moveto(first) self.leftLinenumbers.yview_moveto(first) self.rightLinenumbers.yview_moveto(first) self.uniScrollbar.set(first, last) def create_scroll_bars(self): self.uniScrollbar = Scrollbar(self.main_window) self.uniScrollbar.grid(row=self.uniScrollbarRow, column=self.uniScrollbarCol, sticky=NS) self.uniScrollbar.config(command=self.scrollBoth) self.leftFileTextArea.config(yscrollcommand=self.updateScroll) self.rightFileTextArea.config(yscrollcommand=self.updateScroll) self.leftLinenumbers.config(yscrollcommand=self.updateScroll) self.rightLinenumbers.config(yscrollcommand=self.updateScroll) leftHorizontalScrollbar = Scrollbar(self.main_window, orient=HORIZONTAL) leftHorizontalScrollbar.grid(row=self.horizontalScrollbarRow, column=self.leftHorizontalScrollbarCol, sticky=EW) leftHorizontalScrollbar.config(command=self.leftFileTextArea.xview) self.leftFileTextArea.config( xscrollcommand=leftHorizontalScrollbar.set) rightHorizontalScrollbar = Scrollbar(self.main_window, orient=HORIZONTAL) rightHorizontalScrollbar.grid(row=self.horizontalScrollbarRow, column=self.rightHorizontalScrollbarCol, sticky=EW) rightHorizontalScrollbar.config(command=self.rightFileTextArea.xview) self.rightFileTextArea.config( xscrollcommand=rightHorizontalScrollbar.set)
class SearchFrame(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.analyzer = analysis.Analyzer() self.controller = controller # set the controller self.title = "Article Search" # ttile of the window #title path = 'cyspider.jpg' self.img = ImageTk.PhotoImage(Image.open(path)) self.panel = Label(self, image=self.img) self.panel.pack() self.searchwindow() #search window populates the window with widgets for searching def searchwindow(self): #keyword entry self.largefont = ('Veranda', 24) self.ent_keyword = Entry(self, width=40, relief='raised', font=self.largefont, bd=1) #todo <Return> and entry is not empty call search() self.ent_keyword.bind('<Escape>', self.clear_text) self.ent_keyword.bind( '<Key>', lambda event: self.callEnable(event, 'DefaultSearch')) self.var = IntVar() self.var.set(0) self.check_filter = Checkbutton(self, text="Advanced Filter", variable=self.var, onvalue=1, offvalue=0, command=self.filter_op, font="Veranda 16") if self.var.get() is 0: self.but_search = Button( self, text='Search', width=15, state='disable', font="Veranda 16", command=lambda: self.search( 'http://cbrown686-test.apigee.net/cyberapi/articles?q=keywordtitlebody&title=' + self.ent_keyword.get() + '&body=' + self.ent_keyword.get( ))) self.but_search.place(relx=.505, rely=.6, anchor=W) else: self.searchButton() #window placements #ENTRY BOX for keyword self.ent_keyword.place(relx=.5, rely=.5, anchor=CENTER) #check button self.check_filter.place(relx=.495, rely=.6, relheight=.059, anchor=E) #todo if the user selects to load a search it will simply jump to results def searchButton(self, event): if self.box.current() is 0: self.but_search = Button( self, text='Search', width=15, state='disable', command=lambda: self.search( 'http://cbrown686-test.apigee.net/cyberapi/articles?q=keywordtitlebody&title=' + self.ent_keyword.get() + '&body=' + self.ent_keyword.get( ))) self.but_search.place(relx=.505, rely=.6, anchor=W) self.enableSearch2() elif self.box.current() is 1: self.but_search = Button( self, text='Search', width=15, state='disable', command=lambda: self.search( 'http://cbrown686-test.apigee.net/cyberapi/articles?q=keywordtitle&title=' + self.ent_keyword.get())) self.but_search.place(relx=.505, rely=.6, anchor=W) self.enableSearch2() elif self.box.current() is 2: self.but_search = Button( self, text='Search', width=15, state='disable', command=lambda: self.search( 'http://cbrown686-test.apigee.net/cyberapi/articles?q=bodyonly&body=' + self.ent_keyword.get())) self.but_search.place(relx=.505, rely=.6, anchor=W) self.enableSearch2() elif self.box.current() is 3: self.but_search = Button( self, text='Search', width=15, state='disable', command=lambda: self.search( 'http://cbrown686-test.apigee.net/cyberapi/articles?q=uri&uripath=' + self.ent_keyword.get())) self.but_search.place(relx=.505, rely=.6, anchor=W) self.enableSearch2() #Hitting escape when editing the ENTRY box will clear it and disable the search button from being able to be used. def clear_text(self, event): self.ent_keyword.delete(0, 'end') self.but_search.configure(state='disable') #filter options populate uppon check box of Advanced search option def filter_op(self): if self.var.get() == 1: #appearing self.appearing_label = Label(self, text='Appearing In:', background='#282828', font=15, foreground='#5DE0DC') self.box_value = StringVar() self.box = Combobox(self, textvariable=self.box_value) self.box['values'] = ('Default', 'Title', 'Body', 'URL') self.box.current(0) self.box.bind('<<ComboboxSelected>>', self.searchButton) #author self.author_label = Label(self, text='Author:', background='#282828', font=15, foreground='#5DE0DC') self.author_entry = Entry(self, width=22, bd=2, background='#9A9A9A') #subjectivity self.fsub_label = Label(self, text='Subjectivity:', background='#282828', font=15, foreground='#5DE0DC') self.var2 = IntVar() self.var2.set(1) self.fsub_nv = Radiobutton(self, text="Don't Care", variable=self.var2, value=1, background='#282828', foreground='#5DE0DC') self.fsub_gt = Radiobutton(self, text='More Subjective', variable=self.var2, value=2, background='#282828', foreground='#5DE0DC') self.fsub_lt = Radiobutton(self, text='More Objective', variable=self.var2, value=3, background='#282828', foreground='#5DE0DC') #date self.fD_label = Label(self, text='Date:', background='#282828', font=15, foreground='#5DE0DC') self.fD_format = Label(self, text='00/00/0000', background='#282828', foreground='#BBBBBB') self.fD_format.configure(foreground='grey') self.fD_beinlab = Label(self, text='From:', background='#282828', foreground='#BBBBBB') self.fD_endlab = Label(self, text='To:', background='#282828', foreground='#BBBBBB') self.fD_ent = Entry(self, width=10, bd=2, background='#9A9A9A') self.fD_ent.insert('end', '01/01/0001') self.fD_ent2 = Entry(self, width=10, bd=2, background='#9A9A9A') self.fD_ent2.insert('end', strftime('%m/%d/%Y')) # window placements #appearing labael offset = 100 self.appearing_label.place(x=400, y=380 + offset) #appearing pick self.box.place(x=510, y=380 + offset) #author label self.author_label.place(x=400, y=405 + offset) #author entry self.author_entry.place(x=510, y=405 + offset) #subjectivity self.fsub_label.place(x=400, y=430 + offset) self.fsub_nv.place(x=510, y=430 + offset) self.fsub_gt.place(x=510, y=455 + offset) self.fsub_lt.place(x=510, y=480 + offset) #date self.fD_label.place(x=400, y=505 + offset) self.fD_format.place(x=440, y=507 + offset) self.fD_beinlab.place(x=510, y=505 + offset) self.fD_ent.place(x=555, y=505 + offset) self.fD_endlab.place(x=590, y=505 + offset) self.fD_ent2.place(x=625, y=505 + offset) # if the button gets unchecked it will destroy the labels and entry widgets. elif self.var.get() == 0: self.appearing_label.destroy() self.box.destroy() self.author_label.destroy() self.author_entry.destroy() self.fsub_label.destroy() self.fsub_nv.destroy() self.fsub_gt.destroy() self.fsub_lt.destroy() self.fD_label.destroy() self.fD_format.destroy() self.fD_ent.destroy() self.fD_beinlab.destroy() self.fD_endlab.destroy() self.fD_ent2.destroy() # does just that clears some shit bra def clearshit(self): # check to see if the lables and entry boxes exist from a previous search options # if they do then destroy them then create the new search label and entry box self.ent_keyword.destroy() self.check_filter.destroy() self.but_search.destroy() if hasattr(self, 'appearing_label'): self.ent_keyword.destroy() self.check_filter.destroy() self.but_search.destroy() self.appearing_label.destroy() self.box.destroy() self.author_label.destroy() self.author_entry.destroy() self.fsub_label.destroy() self.fsub_nv.destroy() self.fsub_gt.destroy() self.fsub_lt.destroy() self.fD_label.destroy() self.fD_format.destroy() self.fD_ent.destroy() self.fD_beinlab.destroy() self.fD_endlab.destroy() self.fD_ent2.destroy() #undoes the hide of the seach buttons so that they can edit the search def undohide(self): self.ent_keyword.place(relx=.5, rely=.5, anchor=CENTER) self.check_filter.place(relx=.495, rely=.6, relheight=.059, anchor=E) self.but_search.place(relx=.505, rely=.6, anchor=W) offset = 100 if self.var.get() == 1: # window placements # appearing labael self.appearing_label.place(x=400, y=380 + offset) # appearing pick self.box.place(x=510, y=380 + offset) # author label self.author_label.place(x=400, y=405 + offset) # author entry self.author_entry.place(x=510, y=405 + offset) # subjectivity self.fsub_label.place(x=400, y=430 + offset) self.fsub_nv.place(x=510, y=430 + offset) self.fsub_gt.place(x=510, y=455 + offset) self.fsub_lt.place(x=510, y=480 + offset) # date self.fD_label.place(x=400, y=505 + offset) self.fD_format.place(x=440, y=507 + offset) self.fD_beinlab.place(x=510, y=505 + offset) self.fD_ent.place(x=555, y=505 + offset) self.fD_endlab.place(x=590, y=505 + offset) self.fD_ent2.place(x=625, y=505 + offset) #hides the widgets to display the search results def hideshit(self): self.ent_keyword.place_forget() self.check_filter.place_forget() self.but_search.place_forget() if self.var.get() == 1: # self.ent_keyword.place(x=(-100), y=(-100)) # self.check_filter.place(x=(-100), y=(-100)) # self.but_search.place(x=(-100), y=(-100)) self.appearing_label.place(x=(-100), y=(-100)) self.box.place(x=(-100), y=(-100)) self.author_label.place(x=(-100), y=(-100)) self.author_entry.place(x=(-100), y=(-100)) self.fsub_label.place(x=(-100), y=(-100)) self.fsub_nv.place(x=(-100), y=(-100)) self.fsub_gt.place(x=(-100), y=(-100)) self.fsub_lt.place(x=(-100), y=(-100)) self.fD_label.place(x=(-100), y=(-100)) self.fD_format.place(x=(-100), y=(-100)) self.fD_ent.place(x=(-100), y=(-100)) self.fD_beinlab.place(x=(-100), y=(-100)) self.fD_endlab.place(x=(-100), y=(-100)) self.fD_ent2.place(x=(-100), y=(-100)) #search for that almighty data mine. def search(self, url): print(url) if self.var.get(): au = self.author_entry.get() au = au.replace(' ', '+') # var2 is the state of the radio check button if self.var2.get() == 2: url = url + '&author=' + au + '&sub=gt&sdate=' + self.fD_ent.get( ) + '&edate=' + self.fD_ent2.get() # print(url) elif self.var2.get() == 3: url = url + '&author=' + au + '&sub=gt&sdate=' + self.fD_ent.get( ) + '&edate=' + self.fD_ent2.get() else: url = url + '&author=' + au + '&sub=&sdate=' + self.fD_ent.get( ) + '&edate=' + self.fD_ent2.get() else: url = url + '&author=&sub=&sdate=01/01/0001&edate=' + strftime( '%m/%d/%Y') print(url) self.data = requests.get(url).json() #print(data) self.hideshit() style = Style(self) style.configure("Treeview", rowheight=30) self.tree = Treeview(self) self.tree.heading('#0', text='Results by Title') self.tree.column('#0', stretch=True) self.tree.place(relx=.3, relheight=1, relwidth=.7) # sunken box that topics print out into self.style = Style() self.style.configure('My.TFrame', background='#383838') # frame for individual analysis self.sf = Frame(self, width=550, height=150, style='My.TFrame') self.sf['relief'] = 'sunken' self.sf.place(relx=0, rely=.055, relwidth=.3, relheight=.4) # labels for article topics self.topicsHead = Label(self, text='Key Article Subjects', font="times 16 underline", background='#282828', foreground='#5DE0DC') self.topics = Label(self, text='Click on an article to see more info', wraplength=500, font='times 14', background='#383838', foreground='#5DE0DC', anchor=W, justify=LEFT) self.topicsHead.place(relx=.01, rely=.01, relwidth=.28) self.topics.place(relx=.01, rely=.065, relwidth=.28) # frame for results analysis self.sf2 = Frame(self, width=550, height=150, style='My.TFrame') self.sf2['relief'] = 'sunken' self.sf2.place(relx=0, rely=.51, relwidth=.3, relheight=.4) self.resultTopicHead = Label(self, text='Most Mentioned Phrases in Results', font="times 16 underline", background='#282828', foreground='#5DE0DC') self.resultTopics = Label(self, text='', wraplength=500, font='times 14', background='#383838', foreground='#5DE0DC', anchor=W, justify=LEFT) self.resultTopicHead.place(relx=.01, rely=.465, relwidth=.28) self.resultTopics.place(relx=.01, rely=.52, relwidth=.28) # New Search Edit Search Save Search self.new_search = Button(self, text='New Search', background='#383838', foreground='#5DE0DC', command=self.NewSearch) self.edit_search = Button(self, text='Edit Search', background='#383838', foreground='#5DE0DC', command=self.EditSearch) self.save_search = Button(self, text='Save Search', background='#383838', foreground='#5DE0DC', command=self.saveMenu) if self.data: for item in self.data: # remove BOM images first from body >uffff item['body'] = ''.join( c for c in unicodedata.normalize('NFC', item['body']) if c <= '\uFFFF') self.tree.insert( '', 'end', text=item['title'], values=(item['uri'], item['body'], item['title'], item['author'], parser.parse(item['date']).strftime('%B, %d, %Y')), tag='data') self.tree.tag_configure('data', font='Verdana 14') self.tree.bind('<Double-1>', self.on_click) self.tree.bind('<<TreeviewSelect>>', self.on_single_click) results = '\n\n'.join([ '\n'.join( textwrap.wrap('*({}): '.format(phrase[1]) + str(phrase[0]), width=33)) for phrase in self.master.master.analyzer.getMostCommonNounPhrases( 5, [item['body'] for item in self.data]) ]) self.resultTopics.config(text=results) self.new_search.place(x=1, y=675) self.edit_search.place(x=75, y=675) self.save_search.place(x=145, y=675) else: self.edit_search = Button(self, text='Edit Search', background='#383838', foreground='#5DE0DC', command=self.EditSearch) self.edit_search.place(x=1, y=675) self.topics.config(text='No Articles Matching Search') self.resultTopics.config(text='') # on_click "double clicking on the article from the tree window opens up the article to be viewed" def NewSearch(self): self.deletesearch() self.searchwindow() def EditSearch(self): self.deletesearch() self.undohide() def saveMenu(self): # create main directory and subdir(current date) if not made already path = os.getcwd() + "/Sessions/" + str(datetime.date.today()) if not os.path.exists(path): os.makedirs(path) # get a filename from the user or default to current time currentTime = datetime.datetime.now().strftime("%H_%M_%S") filename = filedialog.asksaveasfilename(defaultextension="txt", initialdir=path, initialfile=currentTime) if filename: self.saveFilename = filename with open(filename, 'w') as outfile: json.dump(self.data, outfile) # with open(filename, 'w') as f: # f.write("Testing Save As/No Current Save") #defind clear search def deletesearch(self): self.tree.destroy() self.sf.destroy() self.topicsHead.destroy() self.topics.destroy() self.sf2.destroy() self.resultTopicHead.destroy() self.resultTopics.destroy() self.new_search.destroy() self.edit_search.destroy() self.save_search.destroy() #on click gets the articles information and displays it in the Key Article Subjects window def on_single_click(self, event): self.topicsHead.config(text="Key Article Subjects") item = self.tree.item(self.tree.selection()[0], 'values') topicStr = '\n\n'.join([ '\n'.join(textwrap.wrap('*' + phrase[0], width=33)) for phrase in self.master.master.analyzer.getMostCommonNounPhrases( 5, [item[1]]) ]) self.topics.config(text=topicStr) #on d click will open the article for display def on_click(self, event): item = self.tree.selection()[0] self.n = self.tree.item(item, 'values') tw = Toplevel(self) xoffset = int(self.winfo_screenwidth() / 2 - 1280 / 2) yoffset = int(self.winfo_screenheight() / 2 - 800 / 2) tw.geometry("%dx%d+%d+%d" % (800, 600, xoffset, yoffset)) # set geometry of window tw.title(self.n[2]) tb = Text(tw, width=90, height=40, font="Times 14", wrap=WORD) tb.insert('end', self.n[1]) link = Label(tw, text=self.n[0]) link.configure(foreground='blue', cursor='hand2') link.bind('<1>', self.op_link) auth = Label(tw, text='Author: ' + self.n[3]) articledate = Label(tw, text='Date Published: ' + self.n[4]) # window formatting for tw link.place(x=0, y=0, relwidth=1) tb.place(y=20, relwidth=1, relheight=1) auth.pack(side=LEFT, anchor='sw') articledate.pack(side=RIGHT, anchor='se') # op_link "double click on the link at the top of the page opens up the url link def op_link(self, event): webbrowser.open_new(self.n[0]) def callEnable(self, event, searchType): self.after(100, lambda: self.enableSearch(event, searchType)) # event bind when Return is entered after a title keyword is entered will enable the search button. def enableSearch(self, event, searchType): string = '' if searchType == 'DefaultSearch': string = self.ent_keyword.get() if string.strip() != '': self.but_search.configure(state='normal') else: self.but_search.configure(state='disabled') # check for when no event bind is present to be used to pass in and no need for searchType def enableSearch2(self): string = self.ent_keyword.get() if string.strip() != '': self.but_search.configure(state='normal') else: self.but_search.configure(state='disabled')
class StartFrame(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) #container = Frame(self) self.controller = controller # set the controller self.title = "CreepyCrawler" #ttile of the window path = 'spiderweb2.jpg' self.img = ImageTk.PhotoImage(Image.open(path)) self.panel = Label(self, image=self.img) self.panel.pack() #Progress Bar self.s = Style() self.s.theme_use('clam') self.s.configure("mongo.Horizontal.TProgressbar", foreground='#38494C', background='#5AE9FF') self.progress = Progressbar(self, orient="horizontal", style='mongo.Horizontal.TProgressbar', length=700, mode="determinate") self.controller.attributes('-transparentcolor', '#38494C') #Menu Frame window self.style = Style() self.style.configure('My.TFrame', background='#434343') self.sf = Frame(self, width=179, height=76, style='My.TFrame') self.sf['relief'] = 'sunken' #todo to be populated with old searches to be able to reopen. self.menutree = Treeview(self) self.menutree.column('#0', stretch=True) #Menu Labels self.wl = Label(self, text='WELCOME', width=15, font='bold') self.wl.configure(background='#434343', foreground='#06c8e6') self.ns = Label(self, text='-New Session-', width=24, height=1) self.ns.configure(height=2, background='#828282', foreground='#06c8e6') self.ns.bind('<1>', self.start) self.rs = Label(self, text='Restore Search', width=28, height=2) self.rs.configure(background='#434343', foreground='#06c8e6') #window placements self.sf.place(x=298, y=162) self.wl.place(x=315, y=165) self.ns.place(x=300, y=200) self.rs.place(x=0, relwidth=.25) self.menutree.place(x=0, y=10, relwidth=.25, relheight=.96) self.progress.place(y=440) self.bytes = 0 self.maxbytes = 0 self.openMenu() def openMenu(self): # set initial directory to savedScans folder path = os.path.join(os.getcwd(), "Sessions") filenames = os.listdir(path) for file in filenames: filetoprint = file.replace('2017-', '') self.menutree.insert('', 'end', text=filetoprint, tags='date') self.menutree.tag_configure('date', background='grey', foreground='yellow', font='bold, 10') path = os.path.join(os.getcwd(), 'Sessions' + '\\' + file) psr = os.listdir(path) for f in psr: filetoprint = f.replace('.txt', '') filetosend = f #.replace(' ', '') self.menutree.insert('', 'end', text=' -' + filetoprint, values=(file, filetosend), tags='article') self.menutree.tag_configure('article', background='#434343', foreground='#06c8e6') #print(file) self.menutree.bind('<<TreeviewSelect>>', self.onmenuclick) #fill tree with greay past files for i in range(1, 20): self.menutree.insert('', 'end', text='', tags='clean') self.menutree.tag_configure('clean', background='#434343') def onmenuclick(self, event): item = self.menutree.item(self.menutree.selection()[0], 'values') path = 'Sessions' + '\\' + item[0] + '\\' + item[1] with open(path, "rb") as fin: self.content = json.load(fin) #print(self.content) xoffset = int(self.winfo_screenwidth() / 2 - 1280 / 2) yoffset = int(self.winfo_screenheight() / 2 - 800 / 2) self.controller.geometry( "%dx%d+%d+%d" % (1100, 700, xoffset, yoffset)) # set geometry of window self.controller.show_frame('SearchFrame') def start(self, event): self.progress["value"] = 0 self.maxbytes = 50000 self.progress["maximum"] = 50000 self.after(400, self.master.master.analyzer.loadSpacy) self.read_bytes() # self.master.master.analyzer.loadSpacy() def read_bytes(self): '''simulate reading 500 bytes; update progress bar''' self.bytes += 1500 self.progress["value"] = self.bytes if self.bytes < self.maxbytes: # read more bytes after 100 ms self.after(25, self.read_bytes) else: self.welcomewindowing() def welcomewindowing(self): xoffset = int(self.winfo_screenwidth() / 2 - 1280 / 2) yoffset = int(self.winfo_screenheight() / 2 - 800 / 2) self.controller.geometry( "%dx%d+%d+%d" % (1100, 700, xoffset, yoffset)) # set geometry of window self.controller.show_frame('SearchFrame')
def Tree(fr,outVar): s = Style() s.theme_use('default') s.map('Treeview', foreground=fixed_map(s,'foreground'), background=fixed_map(s,'background')) test_length = font.Font(family="Times", size=12, weight="bold").measure('Test') fact = int(test_length / 30 * 20.45) # 30 is the length of Test in Idle s.configure('Treeview', rowheight= fact) s.configure('font.Treeview', font='TkDefaultFont') # determine Heading font based on TkDefaultFont s.configure('font.Treeview', font='TkDefaultFont') def_font = font.nametofont('TkDefaultFont') font_family = def_font.actual()['family'] font_size = def_font.actual()['size'] + 1 s.configure('font.Treeview.Heading', font=(font_family,font_size,'bold')) # function to enable selection def selectItem(evt): curItem = tree.focus() lvar.set(tree.item(curItem)['values']) outVar.set(tree.item(curItem)['values']) def sortBy(tree, col, descending): # When a column is clicked on sort tree contents . # grab values to sort data = [(tree.set(child, col), child) for child in tree.get_children('')] # reorder data data.sort(reverse=descending) for indx, item in enumerate(data): tree.move(item[1], '', indx) # switch the heading so that it will sort in the opposite direction tree.heading(col, command=lambda col=col: sortBy(tree, col, int(not descending))) # reconfigure tags after ordering list_of_items = tree.get_children('') for i in range(len(list_of_items)): tree.tag_configure(list_of_items[i], background=backg[i%2]) # headings and data treeColumns = ['Colours', 'Hash', 'RGB', 'Extra long header'] treeData = (('red', '#FF0000', (255,0,0)), ('yellow', '#FFFF00', (255,255,0)), ('blue', '#0000FF', (0,0,255)), ('green', '#00FF00', (0,255,0)), ('magenta', '#FF00FF', (255,0,255)), ('cyan', '#00FFFF', (0,255,255)), ('foo', 'bar', 'bong', 'ding a ling ping')) backg = ["white",'#f0f0ff'] # create Treeview widget tree = Treeview(fr, column=treeColumns, show='headings',style='font.Treeview') tree.grid(column=0, row=0, sticky='nsew') tree.bind("<<TreeviewSelect>>", selectItem) vsb = Scrollbar(fr,orient="vertical", command=tree.yview) vsb.grid(column=1, row=0, sticky='ns') hsb = Scrollbar(fr,orient="horizontal", command=tree.xview) hsb.grid(column=0, row=1, sticky='ew') tree.configure(xscrollcommand=hsb.set,yscrollcommand=vsb.set) fr.grid_columnconfigure(0, weight=1) fr.grid_rowconfigure(0, weight=1) # insert header, data and tag configuration for ix,col in enumerate(treeColumns): tree.heading(col, text=col.title(), command=lambda c=col: sortBy(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(treeData): itemID = tree.insert('', 'end', values=item) tree.item(itemID, tags=itemID) tree.tag_configure(itemID, 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(treeColumns[indx], width=None) < ilen +10: tree.column(treeColumns[indx], width=ilen + 10) # you should see the widths adjust #print('col',tree.column(treeColumns[indx]),ilen) # display selection lvar = StringVar() lbl = Label(fr, textvariable=lvar, text="Ready") lbl.grid(column=0, row=2, sticky='nsew')
class App(Frame): def __init__(self, parent): # screen_width = 768 screen_width = parent.winfo_screenwidth() print('Screen width: ' + str(screen_width)) # screen_height = 1366 screen_height = parent.winfo_screenheight() print('Screen height: ' + str(screen_height)) # font_factor = 28 font_factor = 27 if screen_width <= screen_height: # font_factor = 15 font_factor = 16 print('Font factor: ' + str(font_factor)) self.default_font_size = int(screen_width/font_factor) print('Font size: ' + str(self.default_font_size)) self.team = 0 self.dir = path.dirname(__file__) self.start_list_file = None self.start_list_file_time = None self.add_prewarnings_to_bottom = False # self.start_list_observer = Observer() # self.start_list_observer.schedule(self, '.') # self.start_list_observer.start() self.punches_url = None self.response_encoding = 'utf-8' self.competition_id = None self.last_received_punch_id = 0 self.competition_date = 0 self.competition_zero_time = 0 self.use_competition_date = False self.use_competition_time = False self.fetch_punch_interval = 10 self.prewarn_codes = {} self.sound_enabled = True self.default_language = 'sv' self.last_sound_time = None self.intro_sound_delay = timedelta(seconds=15) self.intro_sound = 'sounds/ding.mp3' self.test_sound = 'sounds/en/Testing.mp3' self.startlist_update_sound = 'sounds/half_ding.mp3' self.config_update_sound = 'sounds/half_ding.mp3' self.announce_ip = True self.team_names = dict() self.teams = dict() self.runners = dict() self.config_file = 'prewarning.ini' self.config_file_time = None self.read_config() self.data_file = 'prewarning.dat' self.read_data() self.punch_queue = Queue() self.sound_queue = Queue() self.font_size = self.default_font_size self.last_item = None self.parent = parent self.style = Style(parent) self.style.configure('Treeview', rowheight=int(self.font_size*1.5)) self.main_container = Frame(parent) self.main_container.pack(side=TOP, fill=BOTH, expand=True) self.top_frame = Frame(self.main_container) self.prewarn = Label(self.top_frame, text='Förvarning', font=('Arial', self.font_size, 'bold')) self.prewarn.pack(anchor=CENTER, side=LEFT, fill=BOTH, expand=True) self.clock = Label(self.top_frame, font=('times', self.font_size, 'bold')) self.clock.pack(side=RIGHT, fill=BOTH, ipadx=10, expand=False) self.tick() self.top_frame.pack(side=TOP, fill=X, anchor=N, expand=False) self.treeview = Treeview(self.main_container) self.treeview['columns'] = ('team', 'leg') self.treeview.heading("#0", text='Tid', anchor=W) # self.treeview.column("#0", minwidth=int(screen_width/2), width=int(screen_width/2), anchor="w", stretch=False) self.treeview.column("#0", anchor=W, stretch=True) self.treeview.heading('team', text='Lag', anchor=W) self.treeview.column('team', anchor=W, stretch=False) self.treeview.heading('leg', text='Sträcka', anchor=W) self.treeview.column('leg', minwidth=100, width=100, anchor=W, stretch=False) self.treeview.tag_configure('T', font=('Arial', self.font_size, 'bold')) self.treeview.pack(side=BOTTOM, fill=BOTH, anchor=N, expand=True) self.punch_fetcher = Thread(target=self.fetch_punches) self.punch_fetcher.setDaemon(True) self.punch_processor = Thread(target=self.process_punches) self.punch_processor.setDaemon(True) self.sound_player = Thread(target=self.play_sound) self.sound_player.setDaemon(True) self.file_watcher = Thread(target=self.check_files) self.file_watcher.setDaemon(True) self.webapp = None def set_webapp(self, webapp): self.webapp = webapp def notify_ip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 0)) # connecting to a UDP address doesn't send packets local_ip_address = s.getsockname()[0] print(local_ip_address) if self.announce_ip: for number in local_ip_address.split("."): call(['mpg123', '-q', self.add_path('sounds/' + self.default_language + '/' + number + '.mp3')]) s.close() def start(self): #self.read_startlist() self.punch_fetcher.start() self.punch_processor.start() self.sound_player.start() self.file_watcher.start() def add_path(self, file): file_path = path.join(self.dir, file) return file_path def read_config(self): config = ConfigParser() config.read(self.add_path(self.config_file)) common = config['Common'] new_start_list_file = common.get('StartListFile', fallback='startlist.zip') self.add_prewarnings_to_bottom = common.getboolean('AddPrewarningsToBottom', fallback=False) punch_source = config['PunchSource'] self.punches_url = punch_source.get('PunchSourceUrl', fallback='http://roc.olresultat.se/getpunches.asp') self.competition_id = punch_source['CompetitionId'] self.use_competition_date = punch_source.getboolean('UseCompetitionDate', fallback=True) self.use_competition_time = punch_source.getboolean('UseCompetitionTime', fallback=True) self.fetch_punch_interval = punch_source.getint('FetchPunchesIntervalSeconds', fallback=10) self.prewarn_codes = punch_source['PreWarningCodes'].split(',') sound = config['Sound'] self.sound_enabled = sound.getboolean('SoundEnabled', fallback=True) self.default_language = sound.get('DefaultLanguage', fallback='sv') self.announce_ip = sound.getboolean('AnnounceIp', fallback=True) self.intro_sound_delay = timedelta(seconds=sound.getint('IntroSoundDelaySeconds', fallback=10)) self.intro_sound = sound.get('IntroSoundFile', fallback='sounds/ding.mp3') self.test_sound = sound.get('TestSoundFile', fallback='sounds/en/Testing.mp3') # print(self.intro_sound) call(['mpg123', '-q', self.add_path(self.config_update_sound)]) if self.config_file_time == None: self.notify_ip() self.config_file_time = stat(self.add_path(self.config_file)).st_mtime if self.start_list_file != new_start_list_file: self.start_list_file = new_start_list_file self.read_startlist() def read_data(self): data = ConfigParser() data.read(self.add_path(self.data_file)) punch_source = data['PunchSource'] self.last_received_punch_id = punch_source.getint('LastReceivedPunchId', fallback=self.last_received_punch_id) def write_data(self): data = ConfigParser() data.read(self.add_path(self.data_file)) punch_source = data['PunchSource'] punch_source['LastReceivedPunchId'] = str(self.last_received_punch_id) with open(self.add_path(self.data_file), 'w') as datafile: data.write(datafile) def update_size(self): self.style.configure('Treeview', rowheight=int(self.font_size*1.5)) self.prewarn['font'] = ('Arial', self.font_size, 'bold') self.clock['font'] = ('times', self.font_size, 'bold') self.treeview.tag_configure('T', font=('Arial', self.font_size, 'bold')) self.scroll_to_last() def add_prewarning(self, time, team): # last_item = None # if self.last_item is not None: # last_item = self.treeview.item(self.last_item) # # if last_item is not None: # if last_item['text'] == time: # new_value = '' # for tt in last_item['values']: # if len(new_value) is not 0: # new_value += ', ' # new_value += str(tt) # new_value = '"' + new_value + ', ' + team + '"' # self.treeview.item(self.last_item, values=new_value) # else: # self.last_item = self.treeview.insert('', 'end', text=time, values=team, tags='T') # else: # self.last_item = self.treeview.insert('', 'end', text=time, values=team, tags='T') if self.add_prewarnings_to_bottom: self.last_item = self.treeview.insert('', 'end', text=time, values=team, tags='T') else: self.last_item = self.treeview.insert('', 0, text=time, values=team, tags='T') self.scroll_to_last() def scroll_to_last(self): if self.last_item is not None: self.treeview.see(self.last_item) def clear(self): self.treeview.delete(*self.treeview.get_children()) self.last_item = None def tick(self): # get the current local time from the PC new_time = strftime('%H:%M:%S') # if time string has changed, update it if new_time != self.clock["text"]: self.clock["text"] = new_time # calls itself every 200 milliseconds # to update the time display as needed # could use >200 ms, but display gets jerky # self.clock.after(200, self.tick) self.clock.after(200, self.tick) def fetch_punches(self): while True: date = 0 time = 0 if self.use_competition_date: date = self.competition_date if self.use_competition_time: time = self.competition_zero_time values = {'unitId': self.competition_id, 'lastId': self.last_received_punch_id, 'date': date, 'time': time} url_values = urlencode(values) url = self.punches_url + '?' + url_values # print(url) req = Request(url) try: response = urlopen(req) response_encoding = response.info().get_content_charset() if response_encoding is None: response_encoding = self.response_encoding data = response.read().decode(response_encoding) splitlines = data.splitlines() if splitlines: print(data) for line in splitlines: punch_dict = dict(zip(('id', 'code', 'card', 'time'), line.split(';'))) print(punch_dict) self.punch_queue.put(punch_dict) self.last_received_punch_id = punch_dict['id'] print(self.last_received_punch_id) self.write_data() except HTTPError as e: print('The server couldn\'t fulfill the request.') print('Error code: ', e.code) except URLError as e: print('We failed to reach a server.') print('Reason: ', e.reason) sleep(self.fetch_punch_interval) def process_punches(self): while True: punch = self.punch_queue.get() print('Processing: ' + punch['card'] + ' from: ' + punch['code']) if punch['code'] in self.prewarn_codes: runner = self.runners.get(punch['card']) if runner is not None: time = punch['time'].rpartition(' ')[2] bib_number = runner['team_bib_number'] leg = runner['leg'] self.add_prewarning(time, (bib_number, leg)) self.sound_queue.put('sounds/' + self.default_language + '/' + bib_number + '.mp3') # if time.endswith('6'): # self.add_prewarning(time, (str(int(bib_number) + 1), leg)) # self.add_prewarning(time, (str(int(bib_number) + 2), leg)) # self.add_prewarning(time, (str(int(bib_number) + 3), leg)) # self.add_prewarning(time, (str(int(bib_number) + 4), leg)) # self.add_prewarning(time, (str(int(bib_number) + 5), leg)) # self.add_prewarning(time, (str(int(bib_number) + 6), leg)) else: print('Not found') else: print('Wrong code') def play_sound(self): while True: # print('play_sound') sound = self.sound_queue.get() if self.sound_enabled: # print(self.last_sound_time) if self.last_sound_time is None or (datetime.now()-self.last_sound_time).total_seconds() >= self.intro_sound_delay.total_seconds(): # print(self.intro_sound) call(['mpg123', '-q', self.add_path(self.intro_sound)]) # print(sound) call(['mpg123', '-q', self.add_path(sound)]) self.last_sound_time = datetime.now() # print(self.last_sound_time) def on_modified(self, event): print(event) if self.add_path(self.start_list_file) in event.src_path: self.read_startlist() elif self.add_path('test.txt') in event.src_path: print('TEST!') def check_files(self): while True: if stat(self.add_path(self.config_file)).st_mtime != self.config_file_time: print('config_file changed!') self.read_config() if stat(self.add_path(self.start_list_file)).st_mtime != self.start_list_file_time: print('start_list_file changed!') self.read_startlist() sleep(1) def read_startlist(self): if self.start_list_file.lower().endswith('.zip'): archive = ZipFile(self.add_path(self.start_list_file), 'r') data = archive.read('SOFTSTRT.XML') else: f = open(self.add_path(self.start_list_file), 'r', encoding='windows-1252') data = f.read() startlist = ElementTree.fromstring(data) ns = {'ns': 'http://www.orienteering.org/datastandard/3.0'} event_id = self.get_data(startlist, 'ns:Event/ns:Id', ns) event_name = self.get_data(startlist, 'ns:Event/ns:Name', ns) event_date = self.get_data(startlist, 'ns:Event/ns:StartTime/ns:Date', ns) organiser_id = self.get_data(startlist, 'ns:Event/ns:Organiser/ns:Id', ns) organiser_name = self.get_data(startlist, 'ns:Event/ns:Organiser/ns:Name', ns) if event_date is not None: self.competition_date = event_date print('Event: ' + str(event_name) + ' (' + str(event_id) + ') ' + str(event_date)) print('Organiser: ' + str(organiser_name) + ' (' + str(organiser_id) + ')') self.team_names.clear() self.teams.clear() self.runners.clear() xml_teams = startlist.findall('ns:ClassStart/ns:TeamStart', ns) for xml_team in xml_teams: team_name = self.get_data(xml_team, 'ns:Name', ns) team_bib_number = self.get_data(xml_team, 'ns:BibNumber', ns) self.team_names[team_bib_number] = team_name team = dict() team_members = xml_team.findall('ns:TeamMemberStart', ns) for team_member in team_members: team_member_id = self.get_data(team_member, 'ns:Person/ns:Id', ns) team_member_name_family = self.get_data(team_member, 'ns:Person/ns:Name/ns:Family', ns) team_member_name_given = self.get_data(team_member, 'ns:Person/ns:Name/ns:Given', ns) team_member_leg = self.get_data(team_member, 'ns:Start/ns:Leg', ns) team_member_leg_order = self.get_data(team_member, 'ns:Start/ns:LegOrder', ns) team_member_bib_number = self.get_data(team_member, 'ns:Start/ns:BibNumber', ns) team_member_control_card = self.get_data(team_member, 'ns:Start/ns:ControlCard', ns) if team_member_control_card is not None: self.runners[team_member_control_card] = {'id': team_member_id, 'family': team_member_name_family, 'given': team_member_name_given, 'leg': team_member_leg, 'leg_order': team_member_leg_order, 'team_bib_number': team_bib_number, 'bib_number': team_member_bib_number, 'control_card': team_member_control_card} if team_member_leg not in team: team[team_member_leg] = dict() leg = team[team_member_leg] leg[team_member_leg_order] = self.runners[team_member_control_card] team = OrderedDict(natsorted(team.items())) self.teams[team_bib_number] = team # for leg in team.items(): # for subleg in leg: # self.team_names = OrderedDict(natsorted(self.team_names.items())) self.teams = OrderedDict(natsorted(self.teams.items())) self.start_list_file_time = stat(self.add_path(self.start_list_file)).st_mtime # print('Teams: ' + str(self.team_names)) # print('Runners: ' + str(self.runners)) # print(strftime('%H:%M:%S')) # print(self.intro_sound) call(['mpg123', '-q', self.add_path(self.startlist_update_sound)]) def web_index(self): return render_template('index.html') def web_prewarning(self): return render_template('prewarning.html') def web_config(self): config = ConfigParser() config.read(self.add_path(self.config_file)) # config_dict = {s: dict(config.items(s)) for s in config.sections()} return render_template('config.html', config=config) def web_config_post(self): config = ConfigParser() config.read(self.add_path(self.config_file)) value_changed = False for section in config.sections(): print(section) for key, old_value in config.items(section): name = "%s@%s" % (key, section) value = request.form[name] print("\t%s: %s" % (key, value)) if value != old_value: print("\t\tchanged!") config.set(section, key, value) value_changed = True if value_changed: with open(self.add_path(self.config_file), 'w') as configfile: config.write(configfile) return render_template('config.html', config=config) def web_startlist(self): return render_template('startlist.html', teams=self.team_names) def web_team(self, team_nr): if team_nr not in self.teams: return redirect('/team/') return render_template('team.html', team=self.teams[team_nr], team_name=self.team_names[team_nr], team_nr=team_nr) @staticmethod def get_data(element, selector, ns): data = element.find(selector, ns) if data is not None: return data.text else: return None def on_key_press(self, event: Event): print('Key symbol: ' + str(event.keysym)) if event.keysym == 'space' or event.keysym == 'p': self.team += 1 self.add_prewarning(strftime('%H:%M:%S'), (self.team, 1)) self.sound_queue.put('sounds/' + self.default_language + '/' + str(self.team) + '.mp3') if event.keysym == 't': self.sound_queue.put(self.test_sound) if event.keysym == 'i': self.notify_ip() elif event.keysym == 'c': self.clear() elif event.keysym == 'q': exit() elif event.keysym == 'plus' or event.keysym == 'KP_Add': self.font_size += 1 print('Font size: ' + str(self.font_size)) self.update_size() elif event.keysym == 'minus' or event.keysym == 'KP_Subtract': self.font_size -= 1 print('Font size: ' + str(self.font_size)) self.update_size() elif event.keysym == '0' or event.keysym == 'KP_0': self.font_size = self.default_font_size print('Font size: ' + str(self.font_size)) self.update_size()
class handleDatasSurface(): def __init__(self, master, transaction, tuple_result, args): self.transaction = transaction self.master = master self.args = args self.tuple_result = tuple_result self.deleteurls = [] self.frame2 = Frame(self.master, width=10, height=2) # self.frame2.pack() self.frame2.grid(row=0, column=0) label = Label(self.frame2, text="本次运行时候使用的数据", width=30, height=3) label.grid(row=1, column=1) self.tree_date = Treeview(self.master, columns=['URL', 'Lable', 'Time'], show='headings', height=23) # self.tree_date.pack() self.tree_date.grid(row=2, column=0) # 设置列宽度 self.tree_date.column('URL', width=450, anchor='center') self.tree_date.column('Lable', width=500, anchor='center') self.tree_date.column('Time', width=250, anchor='center') # 添加列名 self.tree_date.heading('URL', text='URL') self.tree_date.heading('Lable', text='标签') self.tree_date.heading('Time', text='上次下载时间') # 绑定事件 # 绑定左键单击 选中 self.tree_date.bind('<Double-Button-1>', self.selectone) # 绑定右键单击 取消选中 self.tree_date.bind('<Double-3>', self.refuseone) # 绑定键盘 Enter事件,展示URL self.tree_date.bind('<Return>', self.infoURL) self.frame3 = Frame(self.master) btn_yes = tk.Button(self.frame3, text='删除已经选择的数据', command=self.useSelectedData) # btn_no = tk.Button(self.frame3, text='使用数据库数据', command=self.usingOldData) self.frame3.grid(row=3) # btn_no.grid(row=3, column=1) btn_yes.grid(row=3, column=2) self.vsb = tk.ttk.Scrollbar(self.master, orient="vertical", command=self.tree_date.yview) # vsb.place(x=30 + 1100, y=95, height=300 + 20) self.tree_date.configure(yscrollcommand=self.vsb.set) # vsb.grid(row=2, columns = 1,sticky=NS) self.vsb.place(x=1182, y=60, height=480 + 20) # vsb.place(x=50 + 200, y=95, height=200 + 20) # 将存在于数据库中的URL数据展示出来 # for key, value in self.tuple_result[1].items(): # self.tree_date.insert('', 1, values=(key, self.orilable[self.oriurl.index(key)], value['creattime_'])) tuple_ = self.tuple_result[0].copy() tuple_.update(self.tuple_result[1]) for key,value in tuple_.items(): self.tree_date.insert('', 1, values=(key, value['lable_'], value['creattime_']), tags=self.getrandomtgs()) def deleteItem(self, event): # 右键双击删除 for item in self.tree_date.selection(): self.tree_date.delete(item) def selectone(self, event): for item in self.tree_date.selection(): # self.tree_date.columnconfigure (0,weight=1,background='yellow', foreground="red") # self.tree_date.configure ( background = 'yellow',foreground="red") # tages = self.tree_date.item(item, "values")[0] tages = self.tree_date.item(item, "tags")[0] url_ = self.tree_date.item(item, "values")[0].strip() if url_ not in self.deleteurls: self.deleteurls.append(url_) self.tree_date.tag_configure(tages, background='yellow', foreground="red") def refuseone(self, event): for item in self.tree_date.selection(): tages = self.tree_date.item(item, "tags")[0] try: self.deleteurls.remove(self.tree_date.item(item, "values")[0].strip()) except: pass self.tree_date.tag_configure(tages, background='white', foreground="black") def infoURL(self, event): for item in self.tree_date.selection(): url_ = self.tree_date.item(item, "values")[0].strip() lable_ = self.tree_date.item(item, "values")[1] pyperclip.copy(url_) tkinter.messagebox.showinfo('TBProject Info', '选中的url为:\r\n%s' % url_ + "\r\n选中的标签为:\r\n%s" % lable_) def getrandomtgs(self): return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(6)) def useSelectedData(self): try: if len(self.deleteurls) != 0: t_classify = threading.Thread(target=self.transaction.deleteOldDatas, args=(self.deleteurls,)) t_classify.start() except: tkinter.messagebox.showerror('TBProject Error', 'tryAnalysize: 数据库链接出现错误,请重试!') return tuple_ = self.tuple_result[0].copy() tuple_.update(self.tuple_result[1]) for item in self.deleteurls: tuple_[item]['creattime_'] = "- Deleted -" self.frame2.destroy() self.frame3.destroy() self.tree_date.destroy() self.vsb.destroy() # self.transaction.urllists = 1 WorkSurface(self.master, self.transaction, self.tuple_result, self.args, ishandle = True)
class SelectionSurface(): def __init__(self, master, transaction, result_data): self.transaction = transaction self.master = master self.result_data = result_data self.selecturl = [] self.selectlable = [] self.selecttime = [] self.frame2 = Frame(self.master, width=10, height=2) # self.frame2.pack() self.frame2.grid(row=0, column=0) label = Label(self.frame2, text="数据库中已经存在的数据", width=30, height=3) label.grid(row=1, column=1) self.tree_date = Treeview(self.master, columns=['URL', 'Lable', 'Time'], show='headings', height=23) # self.tree_date.pack() self.tree_date.grid(row=2,column=0) # 设置列宽度 self.tree_date.column('URL', width=450, anchor='center') self.tree_date.column('Lable', width=500, anchor='center') self.tree_date.column('Time', width=250, anchor='center') # 添加列名 self.tree_date.heading('URL', text='URL') self.tree_date.heading('Lable', text='标签') self.tree_date.heading('Time', text='上次下载时间') # 绑定事件 # 绑定左键单击 选中 self.tree_date.bind('<Double-Button-1>', self.selectone) # 绑定右键单击 取消选中 self.tree_date.bind('<Double-3>', self.refuseone) # 绑定键盘 Enter事件,展示URL self.tree_date.bind('<Return>', self.infoURL) self.frame3 = Frame(self.master) btn_yes = tk.Button(self.frame3, text='使用已经挑选的数据', command=self.useSelectedData) # btn_no = tk.Button(self.frame3, text='使用数据库数据', command=self.usingOldData) self.frame3.grid(row=3) # btn_no.grid(row=3, column=1) btn_yes.grid(row=3, column=2) self.vsb = tk.ttk.Scrollbar(self.master, orient="vertical", command=self.tree_date.yview) # vsb.place(x=30 + 1100, y=95, height=300 + 20) self.tree_date.configure(yscrollcommand=self.vsb.set) # vsb.grid(row=2, columns = 1,sticky=NS) self.vsb.place(x=1182, y=60, height=480 + 20) # vsb.place(x=50 + 200, y=95, height=200 + 20) # 将存在于数据库中的URL数据展示出来 # for key, value in self.tuple_result[1].items(): # self.tree_date.insert('', 1, values=(key, self.orilable[self.oriurl.index(key)], value['creattime_'])) for item in self.result_data: self.tree_date.insert('', 1, values=(item[0], item[1], item[2]), tags=self.getrandomtgs()) def deleteItem(self, event): # 右键双击删除 for item in self.tree_date.selection(): self.tree_date.delete(item) def selectone(self, event): for item in self.tree_date.selection(): # self.tree_date.columnconfigure (0,weight=1,background='yellow', foreground="red") # self.tree_date.configure ( background = 'yellow',foreground="red") # tages = self.tree_date.item(item, "values")[0] tages = self.tree_date.item(item, "tags")[0] url_ = self.tree_date.item(item, "values")[0].strip() lable_ = self.tree_date.item(item, "values")[1] time_ = self.tree_date.item(item, "values")[2] if url_ not in self.selecturl: self.selecturl.append(url_) self.selectlable.append(lable_) self.selecttime.append(time_) self.tree_date.tag_configure (tages, background = 'yellow',foreground="red") def refuseone(self, event): for item in self.tree_date.selection(): tages = self.tree_date.item(item, "tags")[0] try: self.selecturl.remove(self.tree_date.item(item, "values")[0].strip()) self.selectlable.remove(self.tree_date.item(item, "values")[1]) self.selecttime.remove(self.tree_date.item(item, "values")[2]) except: pass self.tree_date.tag_configure(tages, background='white', foreground="black") def infoURL(self, event): for item in self.tree_date.selection(): url_ = self.tree_date.item(item, "values")[0].strip() lable_ = self.tree_date.item(item, "values")[1] pyperclip.copy(url_) tkinter.messagebox.showinfo('TBProject Info', '选中的url为:\r\n%s'%url_+"\r\n选中的标签为:\r\n%s"%lable_) def getrandomtgs(self): return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(6)) def useSelectedData(self): self.frame2.destroy() self.frame3.destroy() self.tree_date.destroy() self.vsb.destroy() self.transaction.urllists = 1 initface(self.master, self.transaction, [self.selecturl,self.selectlable, self.selecttime])
class SearchBox(Frame): '''A Treeview widget on top, Entry on bottom, using queues for interaction with outside functions''' def __init__(self, parent=None, db=DB, fdict={}): Frame.__init__(self, parent) self.Tests = Tests self.db = db self.fdict = dbm.open(self.db, 'c') #self.fdict['**']='' self.db_update = False #will hold the query to be processed self.query = None self.drives = self.get_drives() self.start_func = StartFunc( ) #platform dependent double-click response self.results = iter( ()) #initiating query results as an empty generator self.total_width = self.winfo_screenwidth( ) #to adjust column widths relative to screen size #Remember scorch mode self.scorch = False self.encoding = ENCODING #for scorch mode #self.keylist=self.fdict.keys() self.keylist_index = 0 self.keylist_counter = 0 #keystroke indicator self.counter = 0 #queues for passing search queries and results self.query_queue = Queue() self.result_queue = Queue() #for usage by db generating function self.dbinit_queue = Queue() #--Search Results panel at top self.panel = Treeview(columns=('Path', 'Size', 'Date')) self.panel.pack(expand=True, fill='both') self.panel.heading('#0', text='Name') self.panel.heading(0, text='Path') self.panel.heading(1, text='Size') self.panel.heading(2, text='Date Modified') #--Starting geometry of the search panel try: #start maximized self.panel.master.attributes('-zoomed', 1) except: self.panel.master.state('zoomed') self.panel_width = self.panel.winfo_width() #Name - 2/5-----Path - 2/5-----Size -1/25-----Date -4/25 # '#0' is the 'Name' column self.panel.column('#0', width=int(self.total_width * 0.4)) self.panel.column('Path', width=int(self.total_width * 0.4)) self.panel.column('Size', width=int(self.total_width * 0.06)) self.panel.column('Date', width=int(self.total_width * 0.14)) #--Panel font, style self.font = Font(family='Helvetica', size=11) '''TkDefaultFont - {'family': 'Segoe UI', 'overstrike': 0, 'size': 9, 'slant': 'roman', 'underline': 0, 'weight': normal'}''' self.style = Style() #linespace - adjust the row height to the font, doesn't happen on its own in tkinter self.style.configure('SearchBox.Treeview', font=self.font, rowheight=self.font.metrics('linespace')) self.panel.config(style='SearchBox.Treeview') #alternating background colors self.panel.tag_configure('color1', background='gray85') #, foreground='white') self.panel.tag_configure('color2', background='gray90') #, foreground='white') #'dark sea green', 'wheat3', 'black' #--App title and icon, currently transparent self.panel.master.title('Jiffy') self.icon = PhotoImage(height=16, width=16) self.icon.blank() #transparent icon, works on all but Py35/Win #loading the transparent icon. black on Py35/Win try: self.master.wm_iconphoto('True', self.icon) except: #For some reason this jammed Python 3.5 with Tk 8.6 on Windows self.tk.call('wm', 'iconphoto', self.master._w, self.icon) #--A string variable to monitor input to the Entry box self.entry_var = StringVar() #self.entry_var.set('Type to search. [F5 - Refresh Database]. [F12 - Scorch Mode]') # [Ctrl-O - Options]. [Ctrl-I - Info] self.entry_var.trace('w', self.update_query) #--Entry line on the bottom self.entry_box = Entry(textvariable=self.entry_var) #keep it as a single line on all window sizes self.entry_box.pack(side='bottom', fill='x') #--Widget Bindings #self.master.bind('<Ctrl-Z>', self.quit) #alternative to Alt-F4 self.master.bind('<Control-equal>', self.scaleup) self.master.bind('<Control-Button-4>', self.scaleup) self.master.bind('<Control-minus>', self.scaledown) self.master.bind('<Control-Button-5>', self.scaledown) self.master.bind('<Control-MouseWheel>', self.scale_mouse) self.panel.bind('<Double-1>', self.doubleclick) self.panel.bind('<Return>', self.doubleclick) #allow scrolling and typing without switching focus self.entry_box.bind('<MouseWheel>', self.scroll_from_entry) self.entry_box.bind('<Button-4>', self.scroll_from_entry) self.entry_box.bind('<Button-5>', self.scroll_from_entry) self.master.bind('<F5>', self.make_database) #self.master.bind('<F12>', self.scorch_mode) #--Starting up with entry box active self.entry_box.focus_set() #--Generating a starting message based on existence of a database if not self.fdict: self.panel.insert('', 'end', text='No cache database found', values=('Hit F5 to generate database', )) else: self.panel.insert( '', 'end', text='Type to search. [F5 - Refresh Database]', values=('[Ctrl - +/-/MouseWheel - Adjust font size]', )) # [Ctrl-O - Options]. [Ctrl-I - Info] #self.panel.insert('', 'end', text='Scorch Mode is faster but uses more memory', values=('Loads the entire database into RAM',)) self.update_searchbox() #Initializing the query managing function in a separate thread (upgrade to pool?) thread.start_new_thread( TMakeSearch, (self.fdict, self.query_queue, self.result_queue)) ##GUI functionality-------------------------------------------------------- #O change to initiation from parameter to SearchBox for more modularity def get_drives(event): return GetDrives() def scroll_from_entry(self, event): '''Scroll results without deactivating entry box, called from entry_box''' self.panel.yview_scroll(1, 'units') def scaleup(self, event): '''The Treeview widget won't auto-adjust the row height, so requires manual resetting upon font changing''' self.font['size'] += 1 self.style.configure('SearchBox.Treeview', rowheight=self.font.metrics('linespace') + 1) def scaledown(self, event): self.font['size'] -= 1 self.style.configure('SearchBox.Treeview', rowheight=self.font.metrics('linespace') + 1) def scale_mouse(self, event): self.scaleup(event) if event.delta > 0 else self.scaledown(event) def doubleclick(self, event): '''Invoke default app on double-click or Enter''' #getting file/folder name and removing '[' and ']' for folders selection = self.panel.item(self.panel.focus()) filename = selection['text'] #remove folder indicating square brackets if filename[0] == '[': filename = filename[1:-2] #SPLIT_TOKEN='\\' if 'win' in sys.platform else '/' full_path = selection['values'][0] + SPLIT_TOKEN + filename self.start_func(full_path) def quit(self, event): '''Currently Alt-F4 exits program, in case I want to add more shortcuts. Also add thread closing management here''' self.master.destroy() ##Cheese: update_database()->is_sb_generated(), trace_results(), update_query() def make_database(self, event): '''Using a thread to generate the dictionary to prevent GUI freezing''' #* dbm might not be thread safe - best might be to restart TMakeSearch self.gtime = time() # for testing self.entry_var.set('Updating Database') self.entry_box.icursor('end') #Resulting dicitionay will be passed via dbinint_queue thread.start_new_thread(RecursiveCreateDict, (self.drives, self.dbinit_queue, self.fdict)) #Wait for the dictionary to be generated self.is_db_generated() def is_db_generated(self): '''Update database if available or sleep and try again''' if not self.dbinit_queue.empty(): #A new dictionary was passed #retrieving new dict self.newdict, self.unsearched = self.dbinit_queue.get() #Messaging TMakeSearch to stop querying the dictionary self.db_update = True self.query_queue.put(None) sleep(0.11) #TMakeSearch takes 0.1s naps. Check further ''' if whichdb(self.db) == ('dbhash'): '''For dumbdbm, this jams the app, as does manual updating. it's not dumb, it's just not worthy''' self.fdict.update(self.newdict) else: for key in self.newdict: self.fdict[key] = self.newdict[key] print('fdict is created') self.db_update = False #save new database self.fdict.sync() print('fdict synced') #Open a new TMakeSearch with the updated database #thread.start_new_thread(TMakeSearch, (self.fdict, self.query_queue, self.result_queue)) #Cleaning up self.newdict.clear() self.newdict = None self.gtime = time() - self.gtime #to read about {}.format #also, a label may be simpler self.entry_var.set('Database generation time- ' + str(self.gtime) + 's. Type to search. [F5 - Refresh Database]') #Pass a signal to close TMakeSearch, then reopen it self.query_queue.put(True) thread.start_new_thread( TMakeSearch, (self.fdict, self.query_queue, self.result_queue)) self.entry_box.icursor(0) #self.loading.destroy() self.panel.delete(*self.panel.get_children()) self.panel.insert( '', 0, text='Scorch Mode is faster but uses more memory', values=('Loads database into RAM', )) #self.keylist=fdict.keys() #for scorch mode self.counter = 0 #self.IS_1ST_PRESS=True #for testing #print time()-self.start #print self.dict_size() else: self.after(100, self.is_db_generated) def update_searchbox(self): '''Update GUI with new result batches ''' self.even = True #for splitting size and date from the keys self.separator = ' * '.encode(self.encoding) while not self.result_queue.empty(): qresult = self.result_queue.get() #print ('is_batch_recieved:', qresult) #if qcounter==self.counter: #currently assuming results will arrive by querying order #break try: #if nothing in queue this will raise an error, saves a preemptive if clause self.results, self.is_new = qresult if Tests.is_batch_recieved: print('is_batch_recieved:', self.results) except: pass #no new results if Tests.is_batch_recieved: print('is_batch_recieved: no new results') else: #if self.panel.get_children()!=(): #results for a newer query, erase old results if self.is_new: self.panel.delete(*self.panel.get_children()) for key in self.results: try: name, size, date = key.decode(self.encoding).split(u'*') #name, size, date=key.split(self.separator) if Tests.is_result_parsed: print(name) except: if Tests.is_result_parsed: print('parsing issue with', key) else: path = self.fdict[key].decode(self.encoding) '''if 'win' in sys.platform and top[0] is u'/': top=u'C:\\'+top[1:] ''' color = 'color1' if self.even else 'color2' self.even = not self.even self.panel.insert('', 'end', text=name, values=(path, size, date), tags=(color, )) self.after(60, self.update_searchbox) def update_query(self, x=None, y=None, z=None): '''Invoked by StringVar().trace() method, which passes 3 arguments that are honorably ditched ''' #Deactivate while switching dictionaries if self.db_update: pass #Cleaning up for 1st keystroke or after a message in the Entry box if not self.counter: '''Entry box needs to be cleaned, the new char put in and the cursor placed after it''' #get&set the 1st search char. user may've changed cursor location b4 typing self.entry_var.set( self.entry_var.get()[self.entry_box.index(INSERT) - 1]) #move cursor after the first char self.entry_box.icursor(1) #counter goes up either way self.counter += 1 self.query = self.entry_var.get() self.query_queue.put(self.query) if Tests.is_query_sent: print(self.query) print(self.counter) ##Not in use ---------------------------------------------------------------- def trace_query(self): '''If I opt for periodically checking the StringVar''' if self.counter: #when counter=0 there's a message/notification in the entry box if self.query != self.entry_var.get(): self.query = self.entry_var.get() self.query_queue.put(self.query) self.after(100, self.trace_query) def trace_and_update(self): ''' In-GUI implementation of query searching, uses a list for iterating over the keys''' '''works smoother when results are generated quickly, but with sparse results GUI becomes unresponsive for short whiles. Relevant only if results are guaranteed to be generated swiftly''' #print self.query #if new query, resetting search parameters and GUI if self.query != self.entry_var.get(): self.keylist_counter = 0 self.query = self.entry_var.get() self.search_list = self.query.lower().split() self.panel.delete(*self.panel.get_children()) self.insertion_counter = 0 self.keylist_index = self.keylist_counter for key in self.keylist[self.keylist_index:]: filename = key.split('*')[0].lower() #If a match, parse and add to the Treeview if self.all(token in filename for token in self.search_list): name, size, date = key.split('*') self.panel.insert('', 'end', text=name, values=(self.fdict[key], size, date)) self.insertion_counter += 1 self.keylist_counter += 1 if self.insertion_counter >= self.INSERTIONS_PER_CYCLE: #50 ##or not dict_counter: break #nap time self.after(60, self.trace_and_update)
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 tabel(): def __init__(self,data,y,m): w=Toplevel() w.geometry('{0}x{1}+0+0'.format(120+25*21,w.winfo_screenheight()-80)) w.columnconfigure(0,weight=1) w.rowconfigure(0,weight=1) d=data[y][m] v='план' if 'табель' in d['degur']: v='табель' w.wm_title('{0} {1} {2}'.format(v,y,m)) #deg=data['2013']['11']['degurs'] # ЗАГЛУШКА : список дежурных deg=d['degurs'] # ЗАГЛУШКА : список дежурных cc=list(range(1,17)) cols=[str(c) for c in cc]+['s','сум','ноч','пра','доп'] self.t=Treeview(w,columns=cols) self.t.column('#0',width=100) for c in cols: self.t.heading(c,text=c) self.t.column(c,width=25,anchor='center') self.t.tag_configure('title',background='gray') self.scrX=Scrollbar(w,orient='horizontal',command=self.t.xview) self.scrY=Scrollbar(w,orient='vertical',command=self.t.yview) self.t['xscrollcommand']=self.scrX.set self.t['yscrollcommand']=self.scrY.set self.t.grid(row=0,column=0,sticky=N+S+E+W) self.scrX.grid(row=1,column=0,sticky=E+W) self.scrY.grid(row=0,column=1,sticky=N+S) rez=dict() for j,s in d['degur'][v].items(): rez[j]=analyse2(s,d) for j in deg: ww1=[] ww2=[] a=0 nn1=[] for x in d['degur'][v].get(j,''): if a: if x=='Д': ww1.append('!!') nn1+=[0,0] y=a+12 a=0 elif x in [str(xx) for xx in range(1,10)]: ww1.append('Я') nn1+=[0,0] y=a+int(x) a=0 elif x=='Н': ww1.append('!') nn1+=[2,6] y=a+4 a=8 elif x=='-': ww1.append('Н') nn1+=[0,0] y=a+0 a=0 else: ww1.append('!') nn1+=[0,0] y=a+0 a=0 else: if x=='Д': ww1.append('Я') nn1+=[0,0] y=12 a=0 elif x in [str(xx) for xx in range(1,10)]: ww1.append('Я') nn1+=[0,0] y=int(x) a=0 elif x=='Н': ww1.append(x) nn1+=[2,6] y=4 a=8 elif x=='-': ww1.append('В') nn1+=[0,0] y=0 a=0 else: ww1.append(x) nn1+=[0,0] y=0 a=0 ww2.append(y) ww=rez.get(j,(0,0,0,0))[0] ee=rez.get(j,(0,0,0,0))[0] -rez.get(j,(0,0,0,0))[3] #ee=rez.get(j,(0,0,0,0))[3] nn=rez.get(j,(0,0,0,0))[1] hh=rez.get(j,(0,0,0,0))[2] s1=sum([x and 1 for x in ww2[1:16]]) s2=sum([x and 1 for x in ww2[16:-1]]) n0=sum([x=='Н' and 1 or 0 for x in ww1[1:-1]]) z=self.t.insert('','end',text=j) self.t.insert(z,'end',text='',values=list(range(1,16)),tag='title') self.t.insert(z,'end',text='',values=ww1[1:16]+['',s1]) self.t.insert(z,'end',text='',values=[x or '-' for x in ww2[1:16]]+ \ ['']+[sum(ww2[1:16])]) self.t.insert(z,'end',text='',values=list(range(16,32)),tag='title') self.t.insert(z,'end',text='',values=ww1[16:-1]+['']*(33-len(ww1))+ \ [s2,s1+s2,n0]) self.t.insert(z,'end',text='',values=[x or '-' for x in ww2[16:-1]]+ \ ['']*(16-len(ww2[16:-1]))+[sum(ww2[16:-1]),sum(ww2[1:-1]),sum(nn1[1:-3]),hh,ee])
def listchans(self, index=None, tagsearch="", archived=0, ob=Channel.displayname, so=asc): self.center = Frame(root, bg=config.bgcolor, width=50, height=40, padx=3, pady=3) # layout all of the main containers root.grid_rowconfigure(1, weight=1) root.grid_columnconfigure(0, weight=1) self.center.grid(row=1, sticky="nsew") channels = database.get_channels(archived, ob, so) if so == desc: so = asc else: so = desc tree = Treeview(self.center) sstring = Entry(self.center, width=config.textBoxWidth) sstring.bind( "<KeyRelease-Return>", lambda e: self.listchans(None, sstring.get(), archived, ob, so)) sstring.grid(column=0, row=0) if len(tagsearch) >= 1: sstring.focus() sstring.insert(0, tagsearch) searchbutton = Button(self.center, text="Search", command=lambda: self.listchans( None, sstring.get(), archived, ob, so)) searchbutton.grid(column=1, row=0) clearbutton = Button(self.center, text="Clear Search") clearbutton.configure(command=lambda: self.listchans(archived)) clearbutton.grid(column=3, row=0) tree["columns"] = ("one", "two") tree.column("#0", width=210, minwidth=10, stretch=YES) tree.column("one", width=350, minwidth=250, stretch=YES) tree.column("two", width=210, minwidth=10, stretch=YES) tree.heading("#0", text="Last Check", anchor=W, command=lambda: self.listchans(None, sstring.get( ), archived, Channel.lastcheck, so)) tree.heading("one", text="Channel Name", anchor=E, command=lambda: self.listchans(None, sstring.get( ), archived, Channel.displayname, so)) tree.heading("two", text="Last Published", command=lambda: self.listchans(None, sstring.get( ), archived, Channel.lastpub, so)) i = 0 tree.tag_configure('oddrow', background='#88DD88') tree.tag_configure('evenrow', background='#FFFFFF') tree.tag_configure('archivedodd', background="#88DD88", foreground="#aaaaaa") tree.tag_configure('archivedeven', background='#FFFFFF', foreground="#cccccc") for item in channels: foldername = "folder" + str(i) if i % 2 == 0: color = "evenrow" else: color = "oddrow" if item.archive == True: if i % 2 == 0: color = "archivedeven" else: color = "archivedodd" if tagsearch.lower() in str( item.displayname).lower() or tagsearch.lower() in str( item.dldir).lower() or tagsearch.lower() in str( item.yt_channelid).lower(): if item.lastpub == None: lastpub = "N/A" else: lastpub = time.ctime(item.lastpub) foldername = tree.insert("", "end", text=time.ctime(item.lastcheck), values=(item.displayname, lastpub), tags=(color, item.displayname, item.dldir, item.yt_channelid)) tree.insert(foldername, "end", text="Directory", values=(item.dldir, ), tags=(color)) tree.insert(foldername, "end", text="Last Published", values=(lastpub, ), tags=(color)) i = i + 1 vertscroll = Scrollbar(self.center) vertscroll.config(command=tree.yview) tree.config(yscrollcommand=vertscroll.set, height=20) vertscroll.grid(column=4, row=1, sticky='NSE') tree.bind("<Double-1>", self.item_selected) tree.grid(row=1, columnspan=4, sticky="NSEW") tree.focus(index) tree.selection_set(index) tree.see(index)
class Manager(Toplevel): def __init__(self, master): Toplevel.__init__(self, master, class_=APP_NAME) self.title(_("Manage Feeds")) self.grab_set() self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.im_moins = PhotoImage(master=self, file=IM_MOINS) self.im_moins_sel = PhotoImage(master=self, file=IM_MOINS_SEL) self.im_moins_clicked = PhotoImage(master=self, file=IM_MOINS_CLICKED) self.im_plus = PhotoImage(master=self, file=IM_PLUS) self._no_edit_entry = self.register(lambda: False) self.change_made = False self.categories = set(LATESTS.sections()) self.categories.remove('All') self.categories.add('') # --- treeview self.tree = Treeview(self, columns=('Title', 'URL', 'Category', 'Remove'), style='manager.Treeview', selectmode='none') self.tree.heading('Title', text=_('Title'), command=lambda: self._sort_column('Title', False)) self.tree.heading('URL', text=_('URL'), command=lambda: self._sort_column('URL', False)) self.tree.heading('Category', text=_('Category'), command=lambda: self._sort_column('Category', False)) self.tree.column('#0', width=6) self.tree.column('Title', width=250) self.tree.column('URL', width=350) self.tree.column('Category', width=150) self.tree.column('Remove', width=20, minwidth=20, stretch=False) y_scroll = AutoScrollbar(self, orient='vertical', command=self.tree.yview) x_scroll = AutoScrollbar(self, orient='horizontal', command=self.tree.xview) self.tree.configure(xscrollcommand=x_scroll.set, yscrollcommand=y_scroll.set) self.tree.bind('<Motion>', self._highlight_active) self.tree.bind('<Leave>', self._leave) self._last_active_item = None # --- populate treeview for title in sorted(FEEDS.sections(), key=lambda x: x.lower()): item = self.tree.insert('', 'end', values=(title, FEEDS.get(title, 'url'), FEEDS.get(title, 'category', fallback=''), '')) if FEEDS.getboolean(title, 'active', fallback=True): self.tree.selection_add(item) self.tree.item(item, tags=item) self.tree.tag_configure(item, image=self.im_moins) self.tree.tag_bind( item, '<ButtonRelease-1>', lambda event, i=item: self._click_release(event, i)) self.tree.tag_bind(item, '<ButtonPress-1>', lambda event, i=item: self._press(event, i)) self.tree.tag_bind(item, '<Double-1>', lambda event, i=item: self._edit(event, i)) self.tree.grid(row=0, column=0, sticky='ewsn') x_scroll.grid(row=1, column=0, sticky='ew') y_scroll.grid(row=0, column=1, sticky='ns') Button(self, image=self.im_plus, command=self.feed_add, style='manager.TButton').grid(row=2, column=0, columnspan=2, sticky='e', padx=4, pady=4) self._check_add_id = '' def destroy(self): try: self.after_cancel(self._check_add_id) except ValueError: pass Toplevel.destroy(self) def _edit(self, event, item): """Edit feed title.""" column = self.tree.identify_column(event.x) if column in ['#1', '#2']: bbox = self.tree.bbox(item, column) entry = Entry(self.tree) entry.place(x=bbox[0], y=bbox[1], width=bbox[2], height=bbox[3], anchor='nw') entry.bind('<Escape>', lambda e: entry.destroy()) entry.bind('<FocusOut>', lambda e: entry.destroy()) if column == '#1': entry.insert(0, self.tree.item(item, 'values')[0]) entry.configure(style='manager.TEntry') def ok(event): name = entry.get() if name: name = self.master.feed_rename( self.tree.set(item, 'Title'), name) self.tree.set(item, 'Title', name) entry.destroy() entry.bind('<Return>', ok) else: entry.insert(0, self.tree.item(item, 'values')[1]) entry.configure(style='no_edit.TEntry', validate='key', validatecommand=self._no_edit_entry) entry.selection_range(0, 'end') entry.focus_set() elif column == '#3': def focus_out(event): x, y = self.tree.winfo_pointerxy() x0 = combo.winfo_rootx() x1 = x0 + combo.winfo_width() y0 = combo.winfo_rooty() y1 = y0 + combo.winfo_height() if not (x0 <= x <= x1 and y0 <= y <= y1): combo.destroy() def ok(event): category = combo.get().strip() self.categories.add(category) self.master.feed_change_cat(self.tree.set(item, 'Title'), self.tree.set(item, 'Category'), category) self.tree.set(item, 'Category', category) combo.destroy() bbox = self.tree.bbox(item, column) cat = list(self.categories) combo = AutoCompleteCombobox(self.tree, values=cat, allow_other_values=True) combo.place(x=bbox[0], y=bbox[1], width=bbox[2], height=bbox[3], anchor='nw') combo.bind('<Escape>', lambda e: combo.destroy()) combo.bind('<FocusOut>', focus_out) combo.bind('<Return>', ok) combo.bind('<<ComboboxSelected>>', ok) combo.current(cat.index(self.tree.set(item, '#3'))) def _press(self, event, item): if self.tree.identify_column(event.x) == '#4': self.tree.tag_configure(item, image=self.im_moins_clicked) def _click_release(self, event, item): """Handle click on items.""" if self.tree.identify_row(event.y) == item: if self.tree.identify_column(event.x) == '#4': title = self.tree.item(item, 'values')[0] rep = True if CONFIG.getboolean('General', 'confirm_remove', fallback=True): rep = askokcancel( _('Confirmation'), _('Do you want to remove the feed {feed}?').format( feed=title)) if rep: self.master.feed_remove(title) self.tree.delete(item) self.change_made = True elif self.tree.identify_element( event.x, event.y) == 'Checkbutton.indicator': sel = self.tree.selection() if item in sel: self.tree.selection_remove(item) self.master.feed_set_active(self.tree.set(item, '#1'), False) else: self.tree.selection_add(item) self.master.feed_set_active(self.tree.set(item, '#1'), True) self.change_made = True else: self.tree.tag_configure(item, image=self.im_moins) def _leave(self, event): """Remove highlight when mouse leave the treeview.""" if self._last_active_item is not None: self.tree.tag_configure(self._last_active_item, image=self.im_moins) def _highlight_active(self, event): """Highlight minus icon under the mouse.""" if self._last_active_item is not None: self.tree.tag_configure(self._last_active_item, image=self.im_moins) if self.tree.identify_column(event.x) == '#4': item = self.tree.identify_row(event.y) if item: self.tree.tag_configure(item, image=self.im_moins_sel) self._last_active_item = item else: self._last_active_item = None else: self._last_active_item = None def _sort_column(self, column, reverse): """Sort column by (reversed) alphabetical order.""" l = [(self.tree.set(c, column), c) for c in self.tree.get_children('')] l.sort(reverse=reverse, key=lambda x: x[0].lower()) for index, (val, c) in enumerate(l): self.tree.move(c, "", index) self.tree.heading( column, command=lambda: self._sort_column(column, not reverse)) def feed_add(self): dialog = Add(self) self.wait_window(dialog) url = dialog.url if url: self.configure(cursor='watch') queue = self.master.feed_add(url, manager=True) self._check_add_id = self.after(1000, self._check_add_finished, url, queue) def _check_add_finished(self, url, queue): if queue.empty(): self._check_add_id = self.after(1000, self._check_add_finished, url, queue) else: title = queue.get(False) if title: item = self.tree.insert('', 'end', values=(title, url, '')) self.tree.item(item, tags=item) self.tree.tag_configure(item, image=self.im_moins) self.tree.tag_bind( item, '<ButtonRelease-1>', lambda event: self._click_release(event, item)) self.tree.tag_bind(item, '<ButtonPress-1>', lambda event: self._press(event, item)) self.tree.tag_bind(item, '<Double-1>', lambda event: self._edit(event, item)) self.tree.selection_add(item) self.change_made = True self.configure(cursor='arrow') self.focus_set() self.grab_set()
class StartFrame(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller # set the controller self.title = "CySpyder" #ttile of the window path = os.getcwd() + '\\resources\spiderweb2.jpg' self.img = ImageTk.PhotoImage(Image.open(path)) self.panel = Label(self, image=self.img) self.panel.pack() #Progress Bar self.s = Style() self.s.theme_use('clam') self.s.configure("mongo.Horizontal.TProgressbar", foreground='#38494C', background='#5AE9FF') self.progress = Progressbar(self, orient="horizontal", style='mongo.Horizontal.TProgressbar', length=700, mode="determinate") self.controller.attributes('-transparentcolor', '#38494C') #Menu Frame window self.style = Style() self.style.configure('My.TFrame', background='#434343') self.sf = Frame(self, width=179, height=76, style='My.TFrame') self.sf['relief'] = 'sunken' #todo to be populated with old searches to be able to reopen. self.menutree = Treeview(self) self.menutree.column('#0', stretch=True) #Menu Labels self.wl = Label(self, text='Welcome', width=24, font='ariel 18') self.wl.configure(background='#434343', foreground='#06c8e6', relief='groove') self.ns = Label(self, text='-New Session-', width=24, height=1, relief='raised', font="ariel 12 bold") self.ns.configure(height=2, background='#828282', foreground='#06c8e6') self.ns.bind('<1>', self.start) self.ns.bind('<Enter>', self.enter) self.ns.bind('<Leave>', self.leave) self.rs = Label(self, text='Recent Searches', width=28, height=2, bd=3, relief='ridge', font="Ariel 12 bold underline") self.rs.configure(background='#434343', foreground='#06c8e6') #window placements self.sf.place(relx=.625, rely=.5, relwidth=.26, relheight=.22, anchor=CENTER) self.wl.place(relx=.624, rely=.449, relwidth=.25, relheight=.1, anchor=CENTER) self.ns.place(relx=.626, rely=.555, relwidth=.25, relheight=.10, anchor=CENTER) self.rs.place(x=0, relwidth=.25, relheight=.1) self.menutree.place(x=0, rely=.045, relwidth=.25, relheight=.92) self.progress.place(y=435) self.bytes = 0 self.maxbytes = 0 self.openMenu() def openMenu(self): # set initial directory to savedScans folder path = os.path.join(os.getcwd(), "Sessions") filenames = os.listdir(path) for file in filenames: filetoprint = file.replace('2017-', '') self.menutree.insert('', 'end', text=filetoprint, tags='date') self.menutree.tag_configure('date', background='grey', foreground='yellow', font='bold, 11') path = os.path.join(os.getcwd(), 'Sessions' + '\\' + file) psr = os.listdir(path) for f in psr: filetoprint = f.replace('.txt', '') filetosend = f #.replace(' ', '') self.menutree.insert('', 'end', text=' -' + filetoprint, values=(file, filetosend), tags='article') self.menutree.tag_configure('article', background='#434343', foreground='#06c8e6', font='bold, 12') self.menutree.bind('<<TreeviewSelect>>', self.onmenuclick) #fill tree with greay past files for i in range(1, 20): self.menutree.insert('', 'end', text='', tags='clean') self.menutree.tag_configure('clean', background='#434343') def onmenuclick(self, event): item = self.menutree.item(self.menutree.selection()[0], 'values') path = 'Sessions' + '\\' + item[0] + '\\' + item[1] with open(path, "r") as fin: SearchFrame.content = json.load(fin) self.start(event='open file') def start(self, event): self.progress["value"] = 0 self.maxbytes = 50000 self.progress["maximum"] = 50000 self.after(400, self.master.master.analyzer.loadSpacy) self.read_bytes(event) def read_bytes(self, event): # simulate reading 500 bytes; update progress bar self.bytes += 1500 self.progress["value"] = self.bytes if self.bytes < self.maxbytes: # read more bytes after 100 ms self.after(25, lambda e=event: self.read_bytes(e)) else: self.welcomewindowing() if event == "open file": self.master.master.frames['SearchFrame'].helper.hidesearch() self.master.master.frames['SearchFrame'].search('') def welcomewindowing(self): xoffset = int(self.winfo_screenwidth() / 2 - 1280 / 2) yoffset = int(self.winfo_screenheight() / 2 - 800 / 2) self.controller.geometry( "%dx%d+%d+%d" % (1100, 700, xoffset, yoffset)) # set geometry of window self.controller.show_frame('SearchFrame') def enter(self, event): self.ns.config(bg="#d3d3d3") def leave(self, event): self.ns.config(bg="#828282")
class NotebookDemo: def __init__(self, fr): self.fr = fr self.style = Style() # ts.ThemedStyle() # Style() self._create_demo_panel() # run this before allBtns self.allBtns = self.ttkbut + self.cbs[1:] + self.rb try: piratz_theme.install('piratz') except Exception: import warnings warnings.warn("piratz theme being used without images") def _create_demo_panel(self): demoPanel = Frame(self.fr, name="demo") demoPanel.pack(side='top', fill='both', expand='y') # create the notebook self.nb = nb = Notebook(demoPanel, name="nb") nb.bind("<<NotebookTabChanged>>", self._on_tab_changed) # extend bindings to top level window allowing # CTRL+TAB - cycles thru tabs # SHIFT+CTRL+TAB - previous tab # ALT+K - select tab using mnemonic (K = underlined letter) nb.enable_traversal() nb.pack(fill='both', expand='y', padx=2, pady=3) self._create_descrip_tab(nb) self._create_treeview_tab(nb) self._create_text_tab(nb) def _create_descrip_tab(self, nb): # frame to hold contents frame = Frame(nb, name='descrip') # widgets to be displayed on 'Description' tab # position and set resize behaviour frame.rowconfigure(1, weight=1) frame.columnconfigure((0, 1), weight=1, uniform=1) lf = LabelFrame(frame, text='Animals') lf.pack(pady=5, padx=5, side='left', fill='y') themes = ['horse', 'elephant', 'crocodile', 'bat', 'grouse'] self.ttkbut = [] for t in themes: b = Button(lf, text=t) b.pack(pady=2) self.ttkbut.append(b) lF2 = LabelFrame(frame, text="Theme Combobox") lF2.pack(pady=5, padx=5) themes = list(sorted( self.style.theme_names())) # get_themes # used in ttkthemes themes.insert(0, "Pick a theme") self.cb = cb = Combobox(lF2, values=themes, state="readonly", height=10) cb.set(themes[0]) #cb.bind('<<ComboboxSelected>>', self.change_style) cb.grid(row=0, column=0, sticky='nw', pady=5) lf1 = LabelFrame(frame, text='Checkbuttons') lf1.pack(pady=5, padx=5, side='left', fill='y') # control variables self.enabled = IntVar() self.cheese = IntVar() self.tomato = IntVar() self.basil = IntVar() self.oregano = IntVar() # checkbuttons self.cbOpt = Checkbutton(lf1, text='Enabled', variable=self.enabled, command=self._toggle_opt) cbCheese = Checkbutton(text='Cheese', variable=self.cheese, command=self._show_vars) cbTomato = Checkbutton(text='Tomato', variable=self.tomato, command=self._show_vars) sep1 = Separator(orient='h') cbBasil = Checkbutton(text='Basil', variable=self.basil, command=self._show_vars) cbOregano = Checkbutton(text='Oregano', variable=self.oregano, command=self._show_vars) sep2 = Separator(orient='h') self.cbs = [ self.cbOpt, sep1, cbCheese, cbTomato, sep2, cbBasil, cbOregano ] for opt in self.cbs: if opt.winfo_class() == 'TCheckbutton': opt.configure(onvalue=1, offvalue=0) opt.setvar(opt.cget('variable'), 0) opt.pack(in_=lf1, side='top', fill='x', pady=2, padx=5, anchor='nw') lf2 = LabelFrame(frame, text='Radiobuttons', labelanchor='n') lf2.pack(pady=5, padx=5, side='left', fill='y') self.rb = [] self.happiness = StringVar() for s in ['Great', 'Good', 'OK', 'Poor', 'Awful']: b = Radiobutton(lf2, text=s, value=s, variable=self.happiness, command=lambda s=s: self._show_vars()) b.pack(anchor='nw', side='top', fill='x', pady=5, padx=5) self.rb.append(b) right = LabelFrame(frame, text='Control Variables') right.pack(pady=5, padx=5, side='left', fill='y') self.vb0 = Label(right, font=('Courier', 10)) self.vb1 = Label(right, font=('Courier', 10)) self.vb2 = Label(right, font=('Courier', 10)) self.vb3 = Label(right, font=('Courier', 10)) self.vb4 = Label(right, font=('Courier', 10)) self.vb5 = Label(right, font=('Courier', 10)) self.vb0.pack(anchor='nw', pady=5, padx=5) self.vb1.pack(anchor='nw', pady=5, padx=5) self.vb2.pack(anchor='nw', pady=5, padx=5) self.vb3.pack(anchor='nw', pady=5, padx=5) self.vb4.pack(anchor='nw', pady=5, padx=5) self.vb5.pack(anchor='nw', pady=5, padx=5) self._show_vars() # add to notebook (underline = index for short-cut character) nb.add(frame, text='Description', underline=0, padding=2) # ============================================================================= def _create_treeview_tab(self, nb): # Populate the second pane. Note that the content doesn't really matter tree = None self.backg = ["white", '#f0f0ff'] tree_columns = ("country", "capital", "currency") tree_data = [("Argentina", "Buenos Aires", "ARS"), ("Australia", "Canberra", "AUD"), ("Brazil", "Brazilia", "BRL"), ("Canada", "Ottawa", "CAD"), ("China", "Beijing", "CNY"), ("France", "Paris", "EUR"), ("Germany", "Berlin", "EUR"), ("India", "New Delhi", "INR"), ("Italy", "Rome", "EUR"), ("Japan", "Tokyo", "JPY"), ("Mexico", "Mexico City", "MXN"), ("Russia", "Moscow", "RUB"), ("South Africa", "Pretoria", "ZAR"), ("United Kingdom", "London", "GBP"), ("United States", "Washington, D.C.", "USD")] container = Frame(nb) container.pack(fill='both', expand=False) self.tree = Treeview(container, columns=tree_columns, show="headings") vsb = Scrollbar(container, orient="vertical", command=self.tree.yview) hsb = Scrollbar(container, orient="horizontal", command=self.tree.xview) self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.tree.grid(column=0, row=0, sticky='ns', in_=container) vsb.grid(column=1, row=0, sticky='ns', in_=container) hsb.grid(column=0, row=1, sticky='ew', in_=container) container.grid_columnconfigure(0, weight=1) container.grid_rowconfigure(0, weight=1) for col in tree_columns: self.tree.heading( col, text=col.title(), command=lambda c=col: self.sortby(self.tree, c, 0)) # XXX tkFont.Font().measure expected args are incorrect according # to the Tk docs self.tree.column(col, width=Font().measure(col.title()), stretch=False) for ix, item in enumerate(tree_data): itemID = self.tree.insert('', 'end', values=item) self.tree.item(itemID, tags=itemID) self.tree.tag_configure(itemID, background=self.backg[ix % 2]) # adjust columns lengths if necessary for indx, val in enumerate(item): ilen = Font().measure(val) if self.tree.column(tree_columns[indx], width=None) < ilen: self.tree.column(tree_columns[indx], width=ilen) sg = Sizegrip(container) sg.grid(sticky='e') nb.add(container, text='Treeview', underline=0, padding=2) # ============================================================================= def _create_text_tab(self, nb): self.dir0 = 1 self.dir1 = 1 # populate the third frame with other widgets fr = Frame(nb, name='fr') lF = LabelFrame(fr, text="Slider") fr1 = Frame(lF) fr1.grid(row=0, column=0, sticky='nsew') from_ = 100 to = 0 value = 0 step = 10 fontSize = 9 self.scvar = IntVar() scRange = self.any_number_range(from_, to, step) scLen = len(scRange[1]) * (fontSize + 10) self.sc = Scale(fr1, from_=from_, to=to, variable=self.scvar, orient='vertical', length=scLen, command=self.v_scale) self.sc.set(value) l1 = Label(fr1, textvariable=self.scvar, width=5) l1.grid(row=0, column=0, padx=5, pady=5) self.sc.grid(row=0, column=1, padx=5, pady=5) fr4 = Frame(fr1) fr4.grid(row=0, column=2) sc_split = '\n'.join(scRange[0].split()) lb = Label(fr1, text=sc_split, font=('Courier New', str(fontSize))) lb.grid(row=0, column=2, padx=5, pady=5) fr2 = Frame(lF, name='fr2') fr2.grid(row=0, column=1, sticky='nsew') self.schvar = IntVar() a = 0 b = 100 schRange = self.any_number_range(a, b, s=10) schLen = Font().measure(schRange[0]) self.sch = Scale(fr2, from_=a, to=b, length=schLen, variable=self.schvar, orient='horizontal', command=self.h_scale) self.sch.set(0) l2 = Label(fr2, textvariable=self.schvar) l2.grid(row=1, column=1, pady=2) self.sch.grid(row=2, column=1, padx=5, pady=5, sticky='nsew') l3 = Label(fr2, text=schRange[0], font=('Courier New', str(fontSize))) l3.grid(row=3, column=1, padx=5, pady=5) lF.grid(row=0, column=0, sticky='nesw', pady=5, padx=5) lF1 = LabelFrame(fr, text="Progress", name='lf') pb1var = IntVar() pb2var = IntVar() self.pbar = Progressbar(lF1, variable=pb1var, length=150, mode="indeterminate", name='pb1', orient='horizontal') self.pb2 = Progressbar(lF1, variable=pb2var, length=150, mode='indeterminate', name='pb2', orient='vertical') self.pbar["value"] = 25 self.h_progress() self.v_progress() self.pbar.grid(row=1, column=0, padx=5, pady=5, sticky='nw') self.pb2.grid(row=1, column=1, padx=5, pady=5, sticky='nw') l3 = Label(lF1, textvariable=pb1var) l3.grid(row=0, column=0, pady=2, sticky='nw') l4 = Label(lF1, textvariable=pb2var) l4.grid(row=0, column=1, pady=2, sticky='nw') sg1 = Sizegrip(fr) sg1.grid(row=2, column=2, sticky='e') lF1.grid(row=1, column=0, sticky='nesw', pady=5, padx=5) # add to notebook (underline = index for short-cut character) nb.add(fr, text='Sliders & Others', underline=0) #========================================================================= def _toggle_opt(self): # state of the option buttons controlled # by the state of the Option frame label widget for opt in self.allBtns: if opt.winfo_class() != 'TSeparator': if self.cbOpt.instate(('selected', )): opt['state'] = '!disabled' # enable option self.nb.tab(1, state='normal') else: opt['state'] = 'disabled' self.nb.tab(1, state='disabled') self._show_vars() def _show_vars(self): # set text for labels in var_panel to include the control # variable name and current variable value self.vb0['text'] = '{:<11} {:<8}'.format('enabled:', self.enabled.get()) self.vb1['text'] = '{:<11} {:<8}'.format('cheese:', self.cheese.get()) self.vb2['text'] = '{:<11} {:<8}'.format('tomato:', self.tomato.get()) self.vb3['text'] = '{:<11} {:<8}'.format('basil:', self.basil.get()) self.vb4['text'] = '{:<11} {:<8}'.format('oregano:', self.oregano.get()) self.vb5['text'] = '{:<11} {:<8}'.format('happiness:', self.happiness.get()) def sortby(self, tree, col, descending): """Sort tree contents when a column is clicked on.""" # grab values to sort data = [(tree.set(child, col), child) for child in tree.get_children('')] # reorder data data.sort(reverse=descending) for indx, item in enumerate(data): tree.move(item[1], '', indx) # switch the heading so that it will sort in the opposite direction tree.heading(col, command=lambda col=col: self.sortby( tree, col, int(not descending))) # reconfigure tags after ordering list_of_items = tree.get_children('') for i in range(len(list_of_items)): tree.tag_configure(list_of_items[i], background=self.backg[i % 2]) def any_number_range(self, a, b, s=1): """ Generate consecutive values list between two numbers with optional step (default=1).""" if (a == b): return a else: mx = max(a, b) mn = min(a, b) result = [] output = '' # inclusive upper limit. If not needed, delete '+1' in the line below while (mn < mx + 1): # if step is positive we go from min to max if s > 0: result.append(mn) mn += s # if step is negative we go from max to min if s < 0: result.append(mx) mx += s # val maxLen = 0 output = "" for ix, res in enumerate(result[:-1]): # last value ignored if len(str(res)) > maxLen: maxLen = len(str(res)) if maxLen == 1: output = ' '.join(str(i) for i in result) # converts list to string else: for ix, res in enumerate(result): if maxLen == 2: if len(str(res)) == 1: output = output + str(res) + " " * maxLen elif len(str(res)) == 2: output = output + str(res) + " " else: output = output + str(res) #print(output) return output, result def change_style(self, event=None): """set the Style to the content of the Combobox""" content = self.cb.get() try: self.style.theme_use(content) except TclError as err: messagebox.showerror('Error', err) else: root.title(content) def change_theme(self, theme): window = ttktheme.ThemedTk() window.set_theme(theme) root.title(theme) def _on_tab_changed(self, event): event.widget.update_idletasks() tab = event.widget.nametowidget(event.widget.select()) event.widget.configure(height=tab.winfo_reqheight(), width=tab.winfo_reqwidth()) def h_progress(self): widg = self.pbar widg['value'] += 1 * self.dir0 if widg['value'] == 100: widg.state(['background', '!active']) self.dir0 = -1 widg.after(50, self.h_progress) elif widg['value'] == 0: widg.state(['active', '!background']) self.dir0 = 1 widg.after(50, self.h_progress) else: widg.after(50, self.h_progress) def v_progress(self): widg1 = self.pb2 widg1['value'] += 1 * self.dir1 if widg1['value'] == 0: # (dir1-1)*100+16 widg1.state(['active', '!invalid', '!background']) self.dir1 = 1 widg1.after(40, self.v_progress) elif widg1['value'] == 16: # (dir1-1)*100+16 widg1.state(['background', '!invalid', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 33: widg1.state(['invalid', '!background', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 50: widg1.state(['active', '!invalid', '!background']) widg1.after(40, self.v_progress) elif widg1['value'] == 66: widg1.state(['background', '!invalid', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 83: widg1.state(['invalid', '!background', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 100: widg1.state(['active', '!invalid', '!background']) self.dir1 = -1 widg1.after(40, self.v_progress) else: widg1.after(40, self.v_progress) def h_scale(self, schvar): v = int(float(schvar)) widg = self.sch imgw = { 0: ['readonly', '!selected', '!background', '!focus', '!active'], 1: ['selected', '!readonly', '!background', '!focus', '!active'] } if v >= 0 and v < 10: widg.state(['active', '!readonly', '!selected']) elif v > 80 and v < 91: widg.state(['focus', '!background', '!readonly', '!selected']) elif v > 90 and v < 100: widg.state(['background', '!invalid', '!focus']) elif v == 100: widg.state(['invalid', '!background']) else: widg.state(imgw[v % 2]) def v_scale(self, scvar): v = int(float(scvar)) widg1 = self.sc imgw = { 0: ['background', '!selected', '!invalid', '!active'], 1: ['selected', '!invalid', '!background', '!active'] } if v >= 0 and v < 5: widg1.state(['active', '!background', '!selected']) elif v > 90: widg1.state(['invalid', '!selected', '!background']) else: widg1.state(imgw[v % 2])
class LabelTool: def __init__(self): self.wildcard = ".png .jpg" page = Tk() page.title('标记小工具') self.pathStr = StringVar() Button(page, text='打开文件夹', background='pink', command=self.open_path, height=2).grid(pady=5) Label(page, textvariable=self.pathStr, anchor=W).grid(row=0, column=1, columnspan=5, padx=5, sticky='W') self.pathStr.set('点击按钮选择要标记的图片路径') tree_title = { 0: ('序号', 60, CENTER), 1: ('图片名称', 200, W), 2: ('标记数', 60, CENTER) } self.tree_image = Treeview(page, height=10, show="headings", columns=tree_title.keys()) for k, v in tree_title.items(): self.tree_image.column(k, width=v[1], anchor=v[2]) self.tree_image.heading(k, text=v[0]) self.tree_image.grid(row=3, column=0, columnspan=3, padx=5, pady=5) scrolly_image = Scrollbar(page, width=20, orient="vertical", command=self.tree_image.yview) # 纵向绑定 scrolly_image.grid(row=3, column=3, sticky=NS) self.tree_image['yscrollcommand'] = scrolly_image.set # 绑定滚动条 self.tree_image.bind('<Double-Button-1>', self.load_image) # self.listbox_label.bind('<Double-Button-1>', self.label_all) # 双击选中所有 page.mainloop() def updata_path(self): files = get_files_from_dir(self.pathStr.get(), self.wildcard) for i in range(len(files)): self.tree_image.insert("", "end", values=[i, files[i], -1], tags=str(i)) self.tree_image.tag_configure(str(i), background='gray') # 选择图片文件夹获取图片 def open_path(self): path = filedialog.askdirectory(title='标注图片路径', initialdir=os.path.dirname(os.getcwd()), mustexist=True) if not path: # showwarning("Warning", "请选择图片文件夹") return self.pathStr.set(path) self.updata_path() def load_image(self, event): print( '_load_image ', event, ) # 获取点击的值 num, name, count = self.tree_image.item(self.tree_image.selection()[0], "values") image_path = os.path.join(self.pathStr.get(), name) # assert os.path.isfile(image_path) if not os.path.isfile(image_path): showwarning('警告', f'错误的图片路径,请确认选择的文件夹\n{image_path}') Thread(target=self._show, args=(self.pathStr.get(), name, self.tree_image, num)).start() print('end ', os.getpid()) def del_image(self, event): print('_del_image ', event) name = self.file_box.get(self.file_box.curselection()[0]).split(' ')[0] image_path = os.path.join(self.path, name + '.jpg') label_path = os.path.join(self.path, name + '.txt') if os.path.isfile(image_path): os.remove(image_path) if os.path.isfile(label_path): os.remove(label_path) self.file_box.delete(self.file_box.curselection()[0]) def del_label(self, event): pass @staticmethod def _show(path, file, tree_image, num): print('_show ', file, ' ', os.getpid()) image = LabelImage(path, file) tree_image.tag_configure(str(num), background='yellow') image.show(file) if image.saveStatus: print('change') tree_image.set(tree_image.get_children()[num], 2, len(image.labels)) tree_image.tag_configure(str(num), background='green') else: tree_image.tag_configure(str(num), background='gray')
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 ConsultaSaldo: def __init__(self, master, produto, main=None): self.app_main = tkinter.Toplevel(master) self.app_main.title("Cadastro de Tipo de Carregamento") self.centralizar_tela() self.main = main self.tipo_carregamento_atual = None self.produto_atual = produto self.entry_nome = None self.cb_inspecao_veiculo = None self.cb_inspecao_produto = None self.cb_remover_a = None self.rb_nao_informar_lacres = None self.rb_informar_lacres_lona = None self.rb_informar_lacres = None self.rb_informar_lacres_lona = None self.entry_codigo_transportador = None self.entry_tipo_frete = None self.entry_destino_frete = None self.entry_docs_diversos = None self.entry_numero_ordem = None self.entry_numero_pedido_frete = None self.nome = StringVar() self.inspecao_produto = IntVar() self.inspecao_veiculo = IntVar() self.remover_a = IntVar() self.tipo_lacre = IntVar() self.codigo_transportador = StringVar() self.tipo_frete = StringVar() self.destino_frete = StringVar() self.numero_ordem = StringVar() self.numero_pedido_frete = StringVar() self.quantidade_item_remessa = StringVar() self.entry_cnpj = None self.entry_data_inicial = None self.entry_data_final = None self.dif_icms = StringVar() self.cnpj = StringVar() self.data_inicial = StringVar() self.data_final = StringVar() self.treeview_itens = None self.atualizando_cadastro = False Label(self.app_main, text="CNPJ").grid(sticky=W, column=0, row=0, padx=10) self.entry_cnpj = Entry(self.app_main, textvariable=self.cnpj) self.entry_cnpj.grid(sticky="we", column=0, row=1, padx=10, ipady=2, columnspan=7) self.entry_cnpj.config(validate="key", validatecommand=(self.app_main.register(NumberUtils.eh_inteiro), '%P')) self.entry_cnpj.bind('<Return>', self.consultar_saldo) Label(self.app_main, text="Data Inicial", ).grid(sticky=W, column=7, row=0, padx=10) self.entry_cnpj = Entry(self.app_main, textvariable=self.data_inicial) self.entry_cnpj.grid(sticky="we", column=7, row=1, padx=10, ipady=2) Label(self.app_main, text="Data Final").grid(sticky=W, column=8, row=0, padx=10) self.entry_cnpj = Entry(self.app_main, textvariable=self.data_final) self.entry_cnpj.grid(sticky="we", column=8, row=1, padx=10, ipady=2) Button(self.app_main, text='Pesquisar', command=self.consultar_saldo) \ .grid(sticky="we", column=9, row=1, padx=10) self.treeview_itens = Treeview(self.app_main, height=10, column=("c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8") , show="headings") self.treeview_itens.bind("<Double-1>", self.inserir_quantidade_item) self.treeview_itens.heading("#1", text="Data") self.treeview_itens.heading("#2", text="Ordem") self.treeview_itens.heading("#3", text="Material") self.treeview_itens.heading("#4", text="Cliente") self.treeview_itens.heading("#5", text="Cidade") self.treeview_itens.heading("#6", text="Qtd") self.treeview_itens.heading("#7", text="Qtd. Disp.") self.treeview_itens.heading("#8", text="Pedido") self.treeview_itens.heading("#9", text="Tipo") self.treeview_itens.column("c0", width=70, stretch=NO, anchor=CENTER) self.treeview_itens.column("c1", width=60, stretch=NO, anchor=CENTER) self.treeview_itens.column("c2", width=120, stretch=NO, anchor=CENTER) self.treeview_itens.column("c3", width=150, stretch=NO, anchor=CENTER) self.treeview_itens.column("c4", width=100, stretch=NO, anchor=CENTER) self.treeview_itens.column("c5", width=70, stretch=NO, anchor=CENTER) self.treeview_itens.column("c6", width=70, stretch=NO, anchor=CENTER) self.treeview_itens.column("c7", width=70, stretch=NO, anchor=CENTER) self.treeview_itens.column("c8", width=50, stretch=NO, anchor=CENTER) self.treeview_itens.tag_configure('teste', background='red') self.treeview_itens.tag_configure('fg', foreground='red') self.treeview_itens.grid(sticky="we", row=7, padx=10, pady=5, columnspan=10) Label(self.app_main, text="Quantidade: ").grid(sticky=W, row=8, padx=10) self.entry_data_inicial = Entry(self.app_main, textvariable=self.quantidade_item_remessa) self.entry_data_inicial.grid(sticky="we", row=9, column=0, padx=10, ipady=2, pady=(0, 15)) self.entry_data_inicial.config(validate="key", validatecommand=(self.app_main.register(NumberUtils.eh_decimal), '%P')) Button(self.app_main, text='Inserir', command=self.inserir_main) \ .grid(sticky="we", column=1, row=9, pady=(0, 15)) self.setar_datas() def centralizar_tela(self): # Gets the requested values of the height and widht. window_width = self.app_main.winfo_reqwidth() window_height = self.app_main.winfo_reqheight() # Gets both half the screen width/height and window width/height position_right = int(self.app_main.winfo_screenwidth() / 2.3 - window_width / 2) position_down = int(self.app_main.winfo_screenheight() / 3 - window_height / 2) # Positions the window in the center of the page. self.app_main.geometry("+{}+{}".format(position_right, position_down)) def setar_datas(self): hoje = date.today() hoje_formatado = hoje.strftime("%d.%m.%Y") data_inicial = hoje - relativedelta(years=1) data_inicial_formatada = data_inicial.strftime("%d.%m.%Y") self.data_inicial.set(data_inicial_formatada) self.data_final.set(hoje_formatado) def consultar_saldo(self, event=None): try: session = SAPGuiApplication.connect() ordens = ZSD020.consultar_saldo_cliente( session, self.cnpj.get(), self.data_inicial.get(), self.data_final.get(), self.produto_atual) self.inserir_item_remessa(ordens) except Exception as e: traceback.print_exc(file=sys.stdout) messagebox.showerror("Erro", e) def inserir_item_remessa(self, ordens): try: self.validar_novo_item() except RuntimeError as e: messagebox.showerror("Erro", str(e)) return self.limpar_treeview() for ordem in ordens: self.treeview_itens.insert("", "end", values=(ordem.data, ordem.numero, ordem.material, ordem.cliente, ordem.cidade, ordem.qtd, ordem.qtd_disponivel, ordem.pedido, ordem.tipo), tags='teste') def inserir_quantidade_item(self, event): selection = self.treeview_itens.selection() tipo_ordem = self.treeview_itens.item(selection, "values")[8] if tipo_ordem == 'ZORT': confirmar_op_triangular = messagebox.askokcancel("Atenção", "Ordem referente a uma 'OPERAÇÂO TRIANGULAR'." "\nConfirmar utilização ?") if confirmar_op_triangular: saldo = self.treeview_itens.item(selection, "values")[6] self.quantidade_item_remessa.set(saldo) def inserir_main(self): selection = self.treeview_itens.selection() ordem = self.treeview_itens.item(selection, "values")[1] self.main.ordem_item_remessa.set(ordem) self.main.quantidade_item_remessa.set(self.quantidade_item_remessa.get()) self.main.inserir_item_remessa(None) def limpar_treeview(self): for item in self.treeview_itens.get_children(): self.treeview_itens.delete(item) def validar_novo_item(self): return True def eliminar_item_remessas(self): selected_items = self.treeview_itens.selection() if len(selected_items) == 0: messagebox.showerror("Erro", "Sem ítens para eliminar!") return for item in selected_items: self.treeview_itens.delete(item) def salvar(self): self.tipo_carregamento_atual = TipoCarregamento() self.tipo_carregamento_atual.nome = self.nome.get().strip() self.tipo_carregamento_atual.inspecao_veiculo = self.inspecao_veiculo.get() self.tipo_carregamento_atual.inspecao_produto = self.inspecao_produto.get() self.tipo_carregamento_atual.remover_a = self.remover_a.get() self.tipo_carregamento_atual.tipo_lacre = self.tipo_lacre.get() self.tipo_carregamento_atual.numero_ordem = self.numero_ordem.get().strip() self.tipo_carregamento_atual.numero_pedido_frete = self.numero_pedido_frete.get().strip() self.tipo_carregamento_atual.tipo_frete = self.tipo_frete.get().strip() self.tipo_carregamento_atual.destino_frete = self.destino_frete.get().strip() self.tipo_carregamento_atual.doc_diversos = self.entry_docs_diversos.get("1.0", END) self.tipo_carregamento_atual.codigo_transportador = self.codigo_transportador.get() self.tipo_carregamento_atual.itens_str = self.extrair_itens() try: TipoCarregamentoService.inserir_tipo_carregamento(self.tipo_carregamento_atual) messagebox.showinfo("Sucesso", "Tipo de carregamento salvo com sucesso!") self.app_main.destroy() except Exception as e: messagebox.showerror("Erro", "Erro ao salvar tipo de carregamento\n{}".format(e)) def verificar_campos_obrigatorios(self): return True def extrair_itens(self): lista = [] itens = self.treeview_itens.get_children() for item in itens: i = ';'.join(self.treeview_itens.item(item, "values")) lista.append('[{}]'.format(i)) return ''.join(lista)
for index, content in enumerate(category): var = IntVar() var.set(1) chkBtn.append(var) c = Checkbutton(f, text=content, variable=var, command=cb, font=(None, 10)) c.grid(row=0, column=index) chkBtn[-1].set(0) f.pack() scrollbar = Scrollbar(root) scrollbar.pack(side=RIGHT, fill=Y) tree = Treeview(root, columns=enlab, yscrollcommand=scrollbar.set, height=20) style = ttk.Style() style.configure("Treeview.Heading", rowheight=40, font=(None, 10)) style.configure("Treeview", rowheight=40, font=(None, 10)) for i, l in enumerate(chlab): tree.heading("#" + str(i), text=chlab[i]) tree.column("#" + str(i), minwidth=0, width=120, stretch=NO, anchor=CENTER) cb() tree.tag_configure('available', background='#E8E8E8') tree.pack(fill='x') scrollbar.config(command=tree.yview) root.mainloop()
class Gr(): def __init__(self,root,data,SCRY=None): self.data=data self.columns=[x for x in range(1,8)]+['day'] root.rowconfigure(1,weight=1) root.columnconfigure(0,weight=1) root.columnconfigure(1,weight=1) root.columnconfigure(2,weight=1) f=Frame(root) f.columnconfigure(0,weight=1) f.rowconfigure(1,weight=1) self.v=Combobox(root) self.v.grid(row=0,column=0) self.v.bind('<<ComboboxSelected>>',self.select_ver) f.grid(row=1,column=0,columnspan=3,sticky=N+S) self.tree=Treeview(f, columns=self.columns, displaycolumns=['day']+self.columns[:-1], show='headings') #self.tree.tag_configure('odd',background='white') #self.tree.tag_configure('even',background='gray') self.tree.tag_configure('dif',foreground='brown') self.tree.tag_configure('work',background='white') self.tree.tag_configure('short',background='#F5EFE0') self.tree.tag_configure('rest',background='#E0B0B0') self.tree.tag_configure('holyday',background='#E7B7A4') for c in self.columns: self.tree.heading(c,text=c) self.tree.column(c,width=65,anchor='center') self.tree.column('day',width=30) scrX=Scrollbar(f,orient='horizontal',command=self.tree.xview) self.tree['xscrollcommand']=scrX.set if not SCRY: self.scrY=Scrollbar(f,orient='vertical',command=self.yview) self.tree['yscrollcommand']=self.scrY.set else: self.tree['yscrollcommand']=SCRY.set self.tree.grid(row=1,column=0,sticky=N+S) if not SCRY: self.scrY.grid(row=1,column=1,sticky=N+S) scrX.grid(row=2,column=0,sticky=E+W) def set(self,y,m): self.y=y self.m=m self.show() def yview(self,*args): self.tree.yview(*args) self.yview2(*args) def yview2(self,*args): pass def show(self): d=self.data[self.y][self.m] V=list(d['degur'].keys()) self.v['values']=V self.v.set(V[0]) self.select_ver() def select_ver(self,*e): self.tree.delete(*self.tree.get_children()) d=self.data[self.y][self.m] offset=d['offset'] v=self.v.get() col=[] for i,deg in enumerate(d['degurs']): self.tree.heading(i+1,text=deg) col.append(i+1) self.tree.configure(displaycolumns=['day']+col) items=dict() if 'табель' in d['degur']: a=[''.join(x) for x in zip(*[[x for x in d['degur']['план'][j]] \ for j in d['degurs']])] b=[''.join(x) for x in zip(*[[x for x in d['degur']['табель'][j]] \ for j in d['degurs']])] c=[x!=y for x,y in zip(a,b)] else: c=[False]*32 for i in range(1,d['days']+1): tag = (i+offset) % 7 in [0,6] and 'rest' or 'work' if i in d['holydays'] : tag='holyday' elif i in d['restdays'] : tag='rest' elif i in d['shortdays'] : tag='short' elif i in d['workdays'] : tag='work' if c[i]: tag=[tag,'dif'] ii=self.tree.insert('','end',values=['-','-','-','-','-'],tag=tag) self.tree.set(ii,column='day',value=i) items[i]=ii for j,s in d['degur'][v].items(): # j-degur if not s: continue for i,val in enumerate(s[1:-1]): if val=='J': val='до' elif val=='j': val='од' elif val=='a': val='10' self.tree.set(items[i+1],column=d['degurs'].index(j)+1,value=val) if s[0]=='Н': if s[1]=='-': self.tree.set(items[1],column=d['degurs'].index(j)+1,value='Н(8)') else: self.tree.set(items[1],column=d['degurs'].index(j)+1,value='!') if s[-2]=='Н': if s[-1]=='-': self.tree.set(items[len(s)-2],column=d['degurs'].index(j)+1,value='Н(4)') else: self.tree.set(items[len(s)-2],column=d['degurs'].index(j)+1,value='!') self.calc(self.y,self.m) def calc(self,y,m): d=self.data[y][m] offset=d['offset'] WH=0 for i in range(1,d['days']+1): if i in d['holydays']: wh=0 elif i in d['restdays'] : wh=0 elif i in d['shortdays'] : wh=7 elif i in d['workdays'] : wh=8 elif (i+offset) % 7 in [0,6]: wh=0 else: wh=8 WH+=wh
class statistic_xx(): def __init__(self,data,y,v='план'): w=Toplevel() w.wm_title('Итоги по месяцам за {0} год ({1}) '.format(y,v)) w.columnconfigure(0,weight=1) w.rowconfigure(0,weight=1) cols=data[y]['degurs'] # ЗАГЛУШКА : список дежурных self.t=Treeview(w,columns=cols) self.t.column('#0',width=120) for c in cols: self.t.heading(c,text=c) self.t.column(c,width=65,anchor='center') self.t.tag_configure('табель',background='green') self.t.tag_configure('ош',background='red') self.scrX=Scrollbar(w,orient='horizontal',command=self.t.xview) self.scrY=Scrollbar(w,orient='vertical',command=self.t.yview) self.t['xscrollcommand']=self.scrX.set self.t['yscrollcommand']=self.scrY.set self.t.grid(row=0,column=0,sticky=N+S+E+W) self.scrX.grid(row=1,column=0,sticky=E+W) self.scrY.grid(row=0,column=1,sticky=N+S) roots=dict() for m in ['01','02','03','04','05','06','07','08','09','10','11','12']: d0=data[y] if m not in d0: continue roots[m]=self.t.insert('','end',text=m+' ('+data[y][m]['month']+')') #r=self.t.insert('','end',text='рабочих') #x=self.t.insert('','end',text='xxx') #w=self.t.insert('','end',text='отработано') #e=self.t.insert('','end',text='дополнительные') #n=self.t.insert('','end',text='ночные') #h=self.t.insert('','end',text='праздничные') #rz_root=self.t.insert('','end',text='резерв') for m in ['01','02','03','04','05','06','07','08','09','10','11','12']: d0=data[y] if m not in d0: continue d=d0[m] rez=dict() tag='' if v=='авто': if 'табель' in d['degur']: vv='табель' tag=vv else: vv='план' elif v=='табель': if 'табель' not in d['degur']: vv='план' tag='ош' else: vv=v tag=vv else: vv=v for j,s in d['degur'][vv].items(): rez[j]=analyse2(s,d) NUL=(0,0,0,0,0,0,0) ww=[rez.get(j,NUL)[0] for j in cols] ee=[rez.get(j,NUL)[0]-rez.get(j,NUL)[3]+rez.get(j,NUL)[4] for j in cols] xx=[rez.get(j,NUL)[0]-rez.get(j,NUL)[3] for j in cols] nn=[rez.get(j,NUL)[1] for j in cols] hh=[rez.get(j,NUL)[2] for j in cols] rr=[rez.get(j,NUL)[3]-rez.get(j,NUL)[4] for j in cols] rz=[rez.get(j,NUL)[5] for j in cols] self.t.insert(roots[m],'end',text='отработано',values=ww,tag=tag) self.t.insert(roots[m],'end',text='рабочие',values=rr,tag=tag) self.t.insert(roots[m],'end',text='дополнительные',values=ee,tag=tag) self.t.insert(roots[m],'end',text='ночные',values=nn,tag=tag) self.t.insert(roots[m],'end',text='праздничные',values=hh,tag=tag)
class SearchFrame(Frame): content = None def __init__(self, parent, controller): Frame.__init__(self, parent) self.analysisthread = None self.controller = controller # set the controller self.title = "Article Search" # title of the window #title path = os.getcwd() + '\\resources\cyspider.jpg' self.img = ImageTk.PhotoImage(Image.open(path)) self.panel = Label(self, image=self.img) self.panel.pack() # widgets for results page # frame for individual analysis self.sf = LabelFrame(self, width=550, height=150, background='#383838', bd=6) # frame for results analysis self.sf2 = LabelFrame(self, width=550, height=150, background='#383838', bd=6) # labels for article topics self.topicsHead = Label(self, text='Key Article Subjects', font="times 16 underline", background='#282828', foreground='#5DE0DC') self.topics = Label(self, text='Click on an article to see more info', wraplength=500, font='times 16', background='#383838', foreground='#5DE0DC', anchor=W, justify=LEFT) calltipwindow.createToolTip( self.topicsHead, "These are a few subjects that were mentioned in the article") # labels for results analysis self.resultTopicHead = Label(self, text='Most Mentioned Phrases in Results', font="times 16 underline", background='#282828', foreground='#5DE0DC') self.resultTopics = Label(self, text='Processing Data (0%)', wraplength=500, font='times 16', background='#383838', foreground='#5DE0DC', anchor=W, justify=LEFT) calltipwindow.createToolTip( self.resultTopicHead, "These are the most mentioned phrases in the resulting articles.") # helper class to improve code readability self.helper = cyhelper.SearchHelper(self) self.helper.showsearch() def search(self, url): # queue to share between gui and threads q = queue.Queue() self.helper.hidefilters() if SearchFrame.content is None: searchprogress = Progressbar(self, orient="horizontal", style='mongo.Horizontal.TProgressbar', length=700, mode="indeterminate") searchprogress.place(relx=.5, rely=.8, anchor=CENTER) searchprogress.start() proglabel = Label(self, text="Fetching Results...", font="Times 14", bg="#282828", fg="#FFFFFF") proglabel.place(relx=.5, rely=.765, anchor=CENTER) # get additional info from filters if they exist url = self.helper.addurlfilters(url) # start thread to get data from url thread = GetDataThread(url, q) thread.start() # wait until thread is done, then get data from queue self.updateuntildata(q, searchprogress) self.data = q.get(0) # get rid of progress bar searchprogress.destroy() proglabel.destroy() else: self.data = SearchFrame.content # make sure search didn't time out if self.data != "ReadTimeout": self.master.master.updateque.queue.clear() # start thread to analyze data and repeat process self.analysisthread = ResultsAnalysisThread( self.data, self.master.master.analyzer, q, self.resultTopics) self.analysisthread.start() self.resultTopics.config(text="Processing Data...(0%)") self.processingloop('percent') self.processingloop('dots') self.helper.hidesearch() style = Style(self) style.configure("Treeview", rowheight=30, fieldbackground='#bdbdbd') style.configure("Treeview.Heading", background="#707070", rowheight=60, font="Ariel 14 bold") self.tree = Treeview(self, columns=('date', 'title'), selectmode='browse') self.tree['show'] = 'headings' self.tree.column('date', width=100, anchor=CENTER) self.tree.heading('date', text="Date", command=lambda: self.treeview_sort_column( self.tree, 'date', False)) self.tree.column('title', width=900) self.tree.heading('title', text="Article Title", anchor=W, command=lambda: self.treeview_sort_column( self.tree, 'title', False)) self.tree.heading('title', text="Article Title", anchor=W, command=lambda: self.treeview_sort_column( self.tree, 'title', False)) #self.tree.place(relx=.3, relheight=1, width=1200) self.tree.place(x=330, relheight=1, width=760) self.treeyscb = Scrollbar(self, orient="vertical", command=self.tree.yview) self.treeyscb.place(relx=1, rely=.5, relheight=1, anchor=E) self.tree.configure(yscrollcommand=self.treeyscb.set) self.treexscb = Scrollbar(self, orient="horizontal", command=self.tree.xview) self.treexscb.place(relx=.3, rely=.999, width=755, anchor=SW) self.tree.configure(xscrollcommand=self.treexscb.set) self.sf.place(relx=0, rely=.055, relwidth=.30, relheight=.4) self.topicsHead.place(relx=.01, rely=.024, relwidth=.28, relheight=.03) self.topics.place(relx=.01, rely=.065, relwidth=.28) # frame for results analysis self.sf2.place(relx=0, rely=.51, relwidth=.30, relheight=.4) self.resultTopicHead.place(relx=.01, rely=.475, relwidth=.28, relheight=.03) self.resultTopics.place(relx=.01, rely=.52, relwidth=.28) # New Search Edit Search Save Search self.new_search = Button(self, text='New Search', background='#383838', foreground='#5DE0DC', font="Veranda 14", command=self.NewSearch) self.edit_search = Button(self, text='Edit Search', background='#383838', foreground='#5DE0DC', font="Veranda 14", command=self.EditSearch) self.save_search = Button(self, text='Save Search', background='#383838', foreground='#5DE0DC', font="Veranda 14", command=self.saveMenu) if self.data: for count, item in enumerate(self.data): # remove BOM images first from body >uffff item['body'] = ''.join( c for c in unicodedata.normalize('NFC', item['body']) if c <= '\uFFFF') tagname = 'even' if count % 2 == 0 else 'odd' self.tree.insert('', 'end', values=(parser.parse( item['date']).strftime('%m/%d/%y'), item['title'], item['uri'], item['author'], item['body']), tag=tagname) self.tree.tag_configure('even', font='Verdana 14', background="#9fedea") self.tree.tag_configure('odd', font='Verdana 14', background="#dedede") self.tree.bind('<Double-1>', self.on_click) self.tree.bind('<<TreeviewSelect>>', self.on_single_click) self.treeview_sort_column(self.tree, 'date', True) else: self.topics.config(text='No Articles Matching Search') self.resultTopics.config(text='') self.new_search.place(relx=0, rely=.95, relwidth=.1, relheight=.05, anchor=NW) if SearchFrame.content is None: self.edit_search.place(relx=.1, rely=.95, relwidth=.1, relheight=.05, anchor=NW) if len(self.data) > 0: self.save_search.place(relx=.2, rely=.95, relwidth=.1, relheight=.05, anchor=NW) else: messagebox.showerror( "Too Broad", "Search is too broad. Try refining with filters.") self.helper.ent_keyword.focus_set() SearchFrame.content = None pass def NewSearch(self): self.analysisthread.stopthread() self.deletesearch() self.helper.resetsearch() self.helper.showsearch() def EditSearch(self): self.analysisthread.stopthread() self.deletesearch() self.helper.showsearch() def saveMenu(self): # create main directory and subdir(current date) if not made already path = os.getcwd() + "/Sessions/" + str(datetime.date.today()) if not os.path.exists(path): os.makedirs(path) # get a filename from the user or default to current time currentTime = datetime.datetime.now().strftime("%H_%M_%S") filename = filedialog.asksaveasfilename(defaultextension="txt", initialdir=path, initialfile=currentTime) if filename: self.saveFilename = filename with open(filename, 'w') as outfile: json.dump(self.data, outfile) # with open(filename, 'w') as f: # f.write("Testing Save As/No Current Save") #defind clear search def deletesearch(self): self.tree.destroy() self.sf.place_forget() self.topicsHead.place_forget() self.topics.place_forget() self.sf2.place_forget() self.resultTopicHead.place_forget() self.resultTopics.place_forget() self.new_search.destroy() self.treexscb.destroy() self.treeyscb.destroy() try: self.edit_search.destroy() self.save_search.destroy() except AttributeError: pass #on click gets the articles information and displays it in the Key Article Subjects window def on_single_click(self, event): self.topicsHead.config(text="Key Article Subjects") item = self.tree.item(self.tree.selection()[0], 'values') topicStr = '\n\n'.join([ '\n '.join(textwrap.wrap('\u27a2' + phrase[0], width=33)) for phrase in self.master.master.analyzer.getMostCommonNounPhrases( 5, [item[4]], threading.Event(), 'one') ]) self.topics.config(text=topicStr) #on d click will open the article for display def on_click(self, event): try: item = self.tree.selection()[0] except IndexError: return self.n = self.tree.item(item, 'values') tw = Toplevel(self) xoffset = int(self.winfo_screenwidth() / 2 - 1280 / 2) yoffset = int(self.winfo_screenheight() / 2 - 800 / 2) tw.geometry("%dx%d+%d+%d" % (800, 600, xoffset, yoffset)) # set geometry of window tw.title(self.n[1]) tb = Text(tw, width=90, height=40, font="Times 14", wrap=WORD) makemenu.ArticleMenu(tw, tb, self.n) tb.insert('end', self.n[4]) tb.config(state=DISABLED) link = Label(tw, text=self.n[2]) link.configure(foreground='blue', cursor='hand2') link.bind('<1>', self.op_link) auth = Label(tw, text='Author: ' + self.n[3]) articledate = Label(tw, text='Date Published: ' + self.n[0]) # window formatting for tw link.place(x=0, y=0, relwidth=1) tb.place(y=20, relwidth=1, relheight=1) auth.pack(side=LEFT, anchor='sw') articledate.pack(side=RIGHT, anchor='se') # op_link "double click on the link at the top of the page opens up the url link def op_link(self, event): webbrowser.open_new(self.n[2]) def callEnable(self, event, searchtype): self.helper.callenable(event, searchtype) def updateuntildata(self, q, progress): while q.empty(): time.sleep(.01) progress.step(1) progress.master.update() def processingloop(self, updatetype): string = self.resultTopics.cget('text') if len(string) and string[0] == 'P': if updatetype == 'percent': if not self.master.master.updateque.empty(): string = "{}({}%)".format( re.search('Processing Data(\.|\s)*', string).group(0), str(self.master.master.updateque.get(0))) self.after(300, lambda: self.processingloop('percent')) else: self.after(100, lambda: self.processingloop('percent')) elif updatetype == 'dots': numdots = len(string.split('.')) % 4 string = "Processing Data" + numdots * '.' + ( 3 - numdots) * ' ' + re.search('\(.+\)', string).group(0) self.after(300, lambda: self.processingloop('dots')) self.resultTopics.config(text=string) def treeview_sort_column(self, tv, col, reverse=False): l = [(tv.set(k, col), k) for k in tv.get_children('')] if col == 'date': l.sort(key=lambda t: "{}/{}/{}".format(t[0].split('/')[2], t[ 0].split('/')[0], t[0].split('/')[1]), reverse=reverse) else: l.sort(key=lambda t: t[0], reverse=reverse) for index, (val, k) in enumerate(l): tv.move(k, '', index) for count, child in enumerate(tv.get_children()): tagn = 'even' if count % 2 == 0 else 'odd' tv.item(child, tag=tagn) tv.heading( col, command=lambda: self.treeview_sort_column(tv, col, not reverse))
class Multicolumn_Listbox(Frame): _style_index = 0 class List_Of_Rows(object): def __init__(self, multicolumn_listbox): self._multicolumn_listbox = multicolumn_listbox def data(self, index): return self._multicolumn_listbox.row_data(index) def get(self, index): return Row(self._multicolumn_listbox, index) def insert(self, data, index=None): self._multicolumn_listbox.insert_row(data, index) def delete(self, index): self._multicolumn_listbox.delete_row(index) def update(self, index, data): self._multicolumn_listbox.update_row(index, data) def select(self, index): self._multicolumn_listbox.select_row(index) def deselect(self, index): self._multicolumn_listbox.deselect_row(index) def set_selection(self, indices): self._multicolumn_listbox.set_selection(indices) def __getitem__(self, index): return self.get(index) def __setitem__(self, index, value): return self._multicolumn_listbox.update_row(index, value) def __delitem__(self, index): self._multicolumn_listbox.delete_row(index) def __len__(self): return self._multicolumn_listbox.number_of_rows class List_Of_Columns(object): def __init__(self, multicolumn_listbox): self._multicolumn_listbox = multicolumn_listbox def data(self, index): return self._multicolumn_listbox.get_column(index) def get(self, index): return Column(self._multicolumn_listbox, index) def delete(self, index): self._multicolumn_listbox.delete_column(index) def update(self, index, data): self._multicolumn_listbox.update_column(index, data) def __getitem__(self, index): return self.get(index) def __setitem__(self, index, value): return self._multicolumn_listbox.update_column(index, value) def __delitem__(self, index): self._multicolumn_listbox.delete_column(index) def __len__(self): return self._multicolumn_listbox.number_of_columns def __init__(self, master, columns, data=None, command=None, sort=True, select_mode=None, heading_anchor=CENTER, cell_anchor=W, style=None, height=None, padding=None, adjust_heading_to_content=False, stripped_rows=None, selection_background=None, selection_foreground=None, field_background=None, heading_font=None, heading_background=None, heading_foreground=None, cell_pady=2, cell_background=None, cell_foreground=None, cell_font=None, headers=True): self._stripped_rows = stripped_rows self._columns = columns self._number_of_rows = 0 self._number_of_columns = len(columns) self.row = self.List_Of_Rows(self) self.column = self.List_Of_Columns(self) s = Style() if style is None: style_name = "Multicolumn_Listbox%s.Treeview" % self._style_index self._style_index += 1 else: style_name = style style_map = {} if selection_background is not None: style_map["background"] = [('selected', selection_background)] if selection_foreground is not None: style_map["foeground"] = [('selected', selection_foreground)] if style_map: s.map(style_name, **style_map) style_config = {} if cell_background is not None: style_config["background"] = cell_background if cell_foreground is not None: style_config["foreground"] = cell_foreground if cell_font is None: font_name = s.lookup(style_name, "font") cell_font = nametofont(font_name) else: if not isinstance(cell_font, Font): if isinstance(cell_font, basestring): cell_font = nametofont(cell_font) else: if len(Font) == 1: cell_font = Font(family=cell_font[0]) elif len(Font) == 2: cell_font = Font(family=cell_font[0], size=cell_font[1]) elif len(Font) == 3: cell_font = Font(family=cell_font[0], size=cell_font[1], weight=cell_font[2]) else: raise ValueError( "Not possible more than 3 values for font") style_config["font"] = cell_font self._cell_font = cell_font self._rowheight = cell_font.metrics("linespace") + cell_pady style_config["rowheight"] = self._rowheight if field_background is not None: style_config["fieldbackground"] = field_background s.configure(style_name, **style_config) heading_style_config = {} if heading_font is not None: heading_style_config["font"] = heading_font if heading_background is not None: heading_style_config["background"] = heading_background if heading_foreground is not None: heading_style_config["foreground"] = heading_foreground heading_style_name = style_name + ".Heading" s.configure(heading_style_name, **heading_style_config) treeview_kwargs = {"style": style_name} if height is not None: treeview_kwargs["height"] = height if padding is not None: treeview_kwargs["padding"] = padding if headers: treeview_kwargs["show"] = "headings" else: treeview_kwargs["show"] = "" if select_mode is not None: treeview_kwargs["selectmode"] = select_mode self.interior = Treeview(master, columns=columns, **treeview_kwargs) if command is not None: self._command = command self.interior.bind("<<TreeviewSelect>>", self._on_select) for i in range(0, self._number_of_columns): if sort: self.interior.heading( i, text=columns[i], anchor=heading_anchor, command=lambda col=i: self.sort_by(col, descending=False)) else: self.interior.heading(i, text=columns[i], anchor=heading_anchor) if adjust_heading_to_content: self.interior.column(i, width=Font().measure(columns[i])) self.interior.column(i, anchor=cell_anchor) if data is not None: for row in data: self.insert_row(row) @property def row_height(self): return self._rowheight @property def font(self): return self._cell_font def configure_column(self, index, width=None, minwidth=None, anchor=None, stretch=None): kwargs = {} for config_name in ("width", "anchor", "stretch", "minwidth"): config_value = locals()[config_name] if config_value is not None: kwargs[config_name] = config_value self.interior.column('#%s' % (index + 1), **kwargs) def row_data(self, index): try: item_ID = self.interior.get_children()[index] except IndexError: raise ValueError("Row index out of range: %d" % index) return self.item_ID_to_row_data(item_ID) def update_row(self, index, data): try: item_ID = self.interior.get_children()[index] except IndexError: raise ValueError("Row index out of range: %d" % index) if len(data) == len(self._columns): self.interior.item(item_ID, values=data) else: raise ValueError("The multicolumn listbox has only %d columns" % self._number_of_columns) def delete_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.delete(item_ID) self._number_of_rows -= 1 if self._stripped_rows: for i in range(index, self._number_of_rows): self.interior.tag_configure(list_of_items[i + 1], background=self._stripped_rows[i % 2]) def insert_row(self, data, index=None): if len(data) != self._number_of_columns: raise ValueError("The multicolumn listbox has only %d columns" % self._number_of_columns) if index is None: index = self._number_of_rows - 1 item_ID = self.interior.insert('', index, values=data) self.interior.item(item_ID, tags=item_ID) self._number_of_rows += 1 if self._stripped_rows: list_of_items = self.interior.get_children() self.interior.tag_configure(item_ID, background=self._stripped_rows[index % 2]) for i in range(index + 1, self._number_of_rows): self.interior.tag_configure(list_of_items[i], background=self._stripped_rows[i % 2]) def column_data(self, index): return [ self.interior.set(child_ID, index) for child_ID in self.interior.get_children('') ] def update_column(self, index, data): for i, item_ID in enumerate(self.interior.get_children()): data_row = self.item_ID_to_row_data(item_ID) data_row[index] = data[i] self.interior.item(item_ID, values=data_row) return data def clear(self): # Another possibility: # self.interior.delete(*self.interior.get_children()) for row in self.interior.get_children(): self.interior.delete(row) self._number_of_rows = 0 def update(self, data): self.clear() for row in data: self.insert_row(row) def focus(self, index=None): if index is None: return self.interior.item(self.interior.focus()) else: item = self.interior.get_children()[index] self.interior.focus(item) def state(self, state=None): if state is None: return self.interior.state() else: self.interior.state(state) @property def number_of_rows(self): return self._number_of_rows @property def number_of_columns(self): return self._number_of_columns def toogle_selection(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.selection_toggle(item_ID) def select_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.selection_add(item_ID) def deselect_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.selection_remove(item_ID) def deselect_all(self): self.interior.selection_remove(self.interior.selection()) def set_selection(self, indices): list_of_items = self.interior.get_children() self.interior.selection_set(" ".join(list_of_items[row_index] for row_index in indices)) @property def selected_rows(self): data = [] for item_ID in self.interior.selection(): data_row = self.item_ID_to_row_data(item_ID) data.append(data_row) return data @property def indices_of_selected_rows(self): list_of_indices = [] for index, item_ID in enumerate(self.interior.get_children()): if item_ID in self.interior.selection(): list_of_indices.append(index) return list_of_indices def delete_all_selected_rows(self): selected_items = self.interior.selection() for item_ID in selected_items: self.interior.delete(item_ID) number_of_deleted_rows = len(selected_items) self._number_of_rows -= number_of_deleted_rows return number_of_deleted_rows def _on_select(self, event): for item_ID in event.widget.selection(): data_row = self.item_ID_to_row_data(item_ID) self._command(data_row) def item_ID_to_row_data(self, item_ID): item = self.interior.item(item_ID) return item["values"] @property def table_data(self): data = [] for item_ID in self.interior.get_children(): data_row = self.item_ID_to_row_data(item_ID) data.append(data_row) return data @table_data.setter def table_data(self, data): self.update(data) def cell_data(self, row, column): """Get the value of a table cell""" try: item = self.interior.get_children()[row] except IndexError: raise ValueError("Row index out of range: %d" % row) return self.interior.set(item, column) def update_cell(self, row, column, value): """Set the value of a table cell""" item_ID = self.interior.get_children()[row] data = self.item_ID_to_row_data(item_ID) data[column] = value self.interior.item(item_ID, values=data) def __getitem__(self, index): if isinstance(index, tuple): row, column = index return self.cell_data(row, column) else: raise Exception("Row and column indices are required") def __setitem__(self, index, value): if isinstance(index, tuple): row, column = index self.update_cell(row, column, value) else: raise Exception("Row and column indices are required") def bind(self, event, handler): self.interior.bind(event, handler) def sort_by(self, col, descending): """ sort tree contents when a column header is clicked """ # grab values to sort data = [(self.interior.set(child_ID, col), child_ID) for child_ID in self.interior.get_children('')] # if the data to be sorted is numeric change to float try: data = [(float(number), child_ID) for number, child_ID in data] except ValueError: pass # now sort the data in place data.sort(reverse=descending) for idx, item in enumerate(data): self.interior.move(item[1], '', idx) # switch the heading so that it will sort in the opposite direction self.interior.heading( col, command=lambda col=col: self.sort_by(col, not descending)) if self._stripped_rows: list_of_items = self.interior.get_children('') for i in range(len(list_of_items)): self.interior.tag_configure(list_of_items[i], background=self._stripped_rows[i % 2]) def destroy(self): self.interior.destroy() def item_ID(self, index): return self.interior.get_children()[index]
class MainWindowUI: # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | # +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ # | menu bar | # +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ # | | search bar | # | | search entry | button| # | +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ # | | | | # | | | | # | | | | # | treeview | | | # | | text area 1 | text area 2 | # | | | | # | | | | # | | | | # | | | | # +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | # Rows fileTreeRow = filePathLabelsRow = 0 searchTextRow = 1 uniScrollbarRow = lineNumbersRow = textAreasRow = 2 horizontalScrollbarRow = 3 # Columns fileTreeCol = 0 fileTreeScrollbarCol = 1 leftLineNumbersCol = leftFilePathLabelsCol = 2 # should span at least two columns leftTextAreaCol = leftHorizontalScrollbarCol = 3 uniScrollbarCol = 4 rightLineNumbersCol = rightFilePathLabelsCol = 5 # should span at least two columns rightTextAreaCol = rightHorizontalScrollbarCol = 6 # Colors whiteColor = '#ffffff' redColor = '#ffc4c4' darkredColor = '#ff8282' grayColor = '#dddddd' lightGrayColor = '#eeeeee' greenColor = '#c9fcd6' darkgreenColor = '#50c96e' yellowColor = '#f0f58c' darkYellowColor = '#ffff00' def __init__(self, window): self.main_window = window self.main_window.grid_rowconfigure(self.filePathLabelsRow, weight=0) self.main_window.grid_rowconfigure(self.searchTextRow, weight=0) self.main_window.grid_rowconfigure(self.textAreasRow, weight=1) self.main_window.grid_columnconfigure(self.fileTreeCol, weight=0) self.main_window.grid_columnconfigure(self.fileTreeScrollbarCol, weight=0) self.main_window.grid_columnconfigure(self.leftLineNumbersCol, weight=0) self.main_window.grid_columnconfigure(self.leftTextAreaCol, weight=1) self.main_window.grid_columnconfigure(self.uniScrollbarCol, weight=0) self.main_window.grid_columnconfigure(self.rightLineNumbersCol, weight=0) self.main_window.grid_columnconfigure(self.rightTextAreaCol, weight=1) self.menubar = Menu(self.main_window) self.menus = {} self.text_area_font = 'TkFixedFont' # Center window and set its size def center_window(self): sw = self.main_window.winfo_screenwidth() sh = self.main_window.winfo_screenheight() w = 0.7 * sw h = 0.7 * sh x = (sw - w)/2 y = (sh - h)/2 self.main_window.geometry('%dx%d+%d+%d' % (w, h, x, y)) self.main_window.minsize(int(0.3 * sw), int(0.3 * sh)) # Menu bar def add_menu(self, menuName, commandList): self.menus[menuName] = Menu(self.menubar,tearoff=0) for c in commandList: if 'separator' in c: self.menus[menuName].add_separator() else: self.menus[menuName].add_command(label=c['name'], command=c['command'], accelerator=c['accelerator'] if 'accelerator' in c else '') self.menubar.add_cascade(label=menuName, menu=self.menus[menuName]) self.main_window.config(menu=self.menubar) # Labels def create_file_path_labels(self): self.leftFileLabel = Label(self.main_window, anchor='center', width=1000, background=self.lightGrayColor) self.leftFileLabel.grid(row=self.filePathLabelsRow, column=self.leftFilePathLabelsCol, columnspan=2) self.rightFileLabel = Label(self.main_window, anchor='center', width=1000, background=self.lightGrayColor) self.rightFileLabel.grid(row=self.filePathLabelsRow, column=self.rightFilePathLabelsCol, columnspan=2) # Search text entnry def create_search_text_entry(self, searchButtonCallback): self.searchTextDialog = SearchTextDialog(self.main_window, [self.leftFileTextArea, self.rightFileTextArea], searchButtonCallback) self.searchTextDialog.grid(row=self.searchTextRow, column=self.leftFilePathLabelsCol, columnspan=5, sticky=EW) self.searchTextDialog.grid_remove() # File treeview def create_file_treeview(self): self.fileTreeView = Treeview(self.main_window) self.fileTreeYScrollbar = Scrollbar(self.main_window, orient='vertical', command=self.fileTreeView.yview) self.fileTreeXScrollbar = Scrollbar(self.main_window, orient='horizontal', command=self.fileTreeView.xview) self.fileTreeView.configure(yscroll=self.fileTreeYScrollbar.set, xscroll=self.fileTreeXScrollbar.set) self.fileTreeView.grid(row=self.fileTreeRow, column=self.fileTreeCol, sticky=NS, rowspan=3) self.fileTreeYScrollbar.grid(row=self.fileTreeRow, column=self.fileTreeScrollbarCol, sticky=NS, rowspan=3) self.fileTreeXScrollbar.grid(row=self.horizontalScrollbarRow, column=self.fileTreeCol, sticky=EW) self.fileTreeView.tag_configure('red', background=self.redColor) self.fileTreeView.tag_configure('green', background=self.greenColor) self.fileTreeView.tag_configure('yellow', background=self.yellowColor) # hide it until needed self.fileTreeView.grid_remove() self.fileTreeYScrollbar.grid_remove() self.fileTreeXScrollbar.grid_remove() # Text areas def create_text_areas(self): self.leftFileTextArea = Text(self.main_window, padx=5, pady=5, width=1, height=1, bg=self.grayColor) self.leftFileTextArea.grid(row=self.textAreasRow, column=self.leftTextAreaCol, sticky=NSEW) self.leftFileTextArea.config(font=self.text_area_font) self.leftFileTextArea.config(wrap='none') self.rightFileTextArea = Text(self.main_window, padx=5, pady=5, width=1, height=1, bg=self.grayColor) self.rightFileTextArea.grid(row=self.textAreasRow, column=self.rightTextAreaCol, sticky=NSEW) self.rightFileTextArea.config(font=self.text_area_font) self.rightFileTextArea.config(wrap='none') # configuring highlight tags self.leftFileTextArea.tag_configure('red', background=self.redColor) self.leftFileTextArea.tag_configure('darkred', background=self.darkredColor) self.leftFileTextArea.tag_configure('gray', background=self.grayColor) self.leftFileTextArea.tag_configure('search', background=self.darkYellowColor) self.rightFileTextArea.tag_configure('green', background=self.greenColor) self.rightFileTextArea.tag_configure('darkgreen', background=self.darkgreenColor) self.rightFileTextArea.tag_configure('gray', background=self.grayColor) self.rightFileTextArea.tag_configure('search', background=self.darkYellowColor) # disable the text areas self.leftFileTextArea.config(state=DISABLED) self.rightFileTextArea.config(state=DISABLED) # Line numbers def create_line_numbers(self): self.leftLinenumbers = Text(self.main_window, width=3, padx=5, pady=5, height=1, bg=self.lightGrayColor) self.leftLinenumbers.grid(row=self.lineNumbersRow, column=self.leftLineNumbersCol, sticky=NS) self.leftLinenumbers.config(font=self.text_area_font) self.leftLinenumbers.tag_configure('line', justify='right') self.rightLinenumbers = Text(self.main_window, width=3, padx=5, pady=5, height=1, bg=self.lightGrayColor) self.rightLinenumbers.grid(row=self.lineNumbersRow, column=self.rightLineNumbersCol, sticky=NS) self.rightLinenumbers.config(font=self.text_area_font) self.rightLinenumbers.tag_configure('line', justify='right') # disable the line numbers self.leftLinenumbers.config(state=DISABLED) self.rightLinenumbers.config(state=DISABLED) # Scroll bars def scrollBoth(self, action, position, type=None): self.leftFileTextArea.yview_moveto(position) self.rightFileTextArea.yview_moveto(position) self.leftLinenumbers.yview_moveto(position) self.rightLinenumbers.yview_moveto(position) def updateScroll(self, first, last, type=None): self.leftFileTextArea.yview_moveto(first) self.rightFileTextArea.yview_moveto(first) self.leftLinenumbers.yview_moveto(first) self.rightLinenumbers.yview_moveto(first) self.uniScrollbar.set(first, last) def create_scroll_bars(self): self.uniScrollbar = Scrollbar(self.main_window) self.uniScrollbar.grid(row=self.uniScrollbarRow, column=self.uniScrollbarCol, sticky=NS) self.uniScrollbar.config(command=self.scrollBoth) self.leftFileTextArea.config(yscrollcommand=self.updateScroll) self.rightFileTextArea.config(yscrollcommand=self.updateScroll) self.leftLinenumbers.config(yscrollcommand=self.updateScroll) self.rightLinenumbers.config(yscrollcommand=self.updateScroll) leftHorizontalScrollbar = Scrollbar(self.main_window, orient=HORIZONTAL) leftHorizontalScrollbar.grid(row=self.horizontalScrollbarRow, column=self.leftHorizontalScrollbarCol, sticky=EW) leftHorizontalScrollbar.config(command=self.leftFileTextArea.xview) self.leftFileTextArea.config(xscrollcommand=leftHorizontalScrollbar.set) rightHorizontalScrollbar = Scrollbar(self.main_window, orient=HORIZONTAL) rightHorizontalScrollbar.grid(row=self.horizontalScrollbarRow, column=self.rightHorizontalScrollbarCol, sticky=EW) rightHorizontalScrollbar.config(command=self.rightFileTextArea.xview) self.rightFileTextArea.config(xscrollcommand=rightHorizontalScrollbar.set)