def styling(root): # tell tcl where to find the awthemes packages root.tk.eval(""" set base_theme_dir awthemes/ package ifneeded awthemes 10.2.1 \ [list source [file join $base_theme_dir awthemes.tcl]] package ifneeded colorutils 4.8 \ [list source [file join $base_theme_dir colorutils.tcl]] package ifneeded awdark 7.11 \ [list source [file join $base_theme_dir awdark.tcl]] """) # remove maximize/mininize button root.resizable(0,0) # load the awdark and awlight themes root.tk.call("package", "require", 'awdark') # Initialising Style and loading in a dark thene style = Style() style.theme_use('awdark') #configure buttons style.configure("TButton", padding=6, relief="flat", font=menu_font) # button active/hover tweaks style.map("C.TButton", foreground=[('pressed', 'black'), ('active', 'black')], background=[('pressed', '!disabled', 'gray'), ('active', 'gray')] )
def _style(self) -> tuple[str, Style]: name = f'{self.id}.customtable.Treeview' tk_style = Style() style = self.style tk_style.theme_use(style.ttk_theme) font = style.font tk_style.configure(name, rowheight=self.row_height or style.char_height) cfg_keys = ('font', 'foreground', 'background', 'fieldbackground') bg = style.bg.default if base := { k: v for k, v in zip(cfg_keys, (font, style.fg.default, bg, bg)) if v is not None }: tk_style.configure(name, **base) if (selected_row_color := self.selected_row_color) and ('foreground' in base or 'background' in base): for i, color in enumerate(('foreground', 'background')): if color in base and selected_row_color[i] is not None: tk_style.map( name, **{ color: _fixed_style_map(tk_style, name, color, selected_row_color) })
def create_protocols_tree(): """ 创建协议导航树 :return: 协议导航树 """ protocols_tree.heading('#0', text='选择网络协议', anchor='w') # 参数:parent, index, iid=None, **kw (父节点,插入的位置,id,显示出的文本) # 应用层 applicatoin_layer_tree_entry = protocols_tree.insert("", 0, "应用层", text="应用层") # ""表示父节点是根 http_packet_tree_entry = protocols_tree.insert(applicatoin_layer_tree_entry, 1, "HTTP包", text="HTTP包") dns_packet_tree_entry = protocols_tree.insert(applicatoin_layer_tree_entry, 1, "DNS包", text="DNS包") # 传输层 transfer_layer_tree_entry = protocols_tree.insert("", 1, "传输层", text="传输层") tcp_packet_tree_entry = protocols_tree.insert(transfer_layer_tree_entry, 0, "TCP包", text="TCP包") upd_packet_tree_entry = protocols_tree.insert(transfer_layer_tree_entry, 1, "UDP包", text="UDP包") # 网络层 ip_layer_tree_entry = protocols_tree.insert("", 2, "网络层", text="网络层") ip_packet_tree_entry = protocols_tree.insert(ip_layer_tree_entry, 0, "IP包", text="IP包") icmp_packet_tree_entry = protocols_tree.insert(ip_layer_tree_entry, 1, "ICMP包", text="ICMP包") arp_packet_tree_entry = protocols_tree.insert(ip_layer_tree_entry, 2, "ARP包", text="ARP包") # 网络接入层 ether_layer_tree_entry = protocols_tree.insert("", 3, "网络接入层", text="网络接入层") mac_frame_tree_entry = protocols_tree.insert(ether_layer_tree_entry, 1, "MAC帧", text="MAC帧") protocols_tree.bind('<<TreeviewSelect>>', on_click_protocols_tree) style = Style(tk) # get disabled entry colors disabled_bg = style.lookup("TEntry", "fieldbackground", ("disabled",)) style.map("Treeview", fieldbackground=[("disabled", disabled_bg)], foreground=[("disabled", "gray")], background=[("disabled", disabled_bg)]) protocols_tree.pack() return protocols_tree
def createprotocolsTree(self): """ 生成协议导航树 :return: """ self.protocolsTree.heading('#0', text='选择发送报文类型', anchor='w') # 参数:parent, index, iid=NOne, **kw(父节点,插入的位置,id,显示的文本) # 应用层 applicatoin_layer_tree_entry = self.protocolsTree.insert('', 0, "应用层", text="应用层") dns_packet_tree_entry = self.protocolsTree.insert( applicatoin_layer_tree_entry, 1, "DNS数据包", text="DNS数据包") # 传输层 transfer_layer_tree_entry = self.protocolsTree.insert('', 1, "传输层", text="传输层") tcp_packet_tree_entry = self.protocolsTree.insert( transfer_layer_tree_entry, 0, "TCP数据包", text="TCP数据包") udp_packet_tree_entry = self.protocolsTree.insert( transfer_layer_tree_entry, 1, "UDP数据包", text="UDP数据包") # 网络层协议 ip_layer_tree_entry = self.protocolsTree.insert('', 2, "网络层", text="网络层") arp_packet_tree_entry = self.protocolsTree.insert(ip_layer_tree_entry, 0, "ARP数据包", text="ARP数据包") ip_packet_tree_entry = self.protocolsTree.insert(ip_layer_tree_entry, 1, "IP数据包", text="IP数据包") icmp_packet_tree_entry = self.protocolsTree.insert(ip_layer_tree_entry, 2, "ICMP报文", text="ICMP报文") # 网络接口层协议 ether_layer_tree_entry = self.protocolsTree.insert('', 3, "网络接口层", text="网络接口层") mac_frame_tree_entry = self.protocolsTree.insert( ether_layer_tree_entry, 1, "以太网MAC协议", text="以太网MAC协议") self.protocolsTree.bind('<<TreeviewSelect>>', self.on_click_protocols_tree) style = Style(self) # get disabled entry colors disabled_bg = style.lookup("TEntry", "fieldbackground", ("disabled", )) style.map("Treeview", fieldbackground=[("disabled", disabled_bg)], foreground=[("disabled", "gray")], background=[("disabled", disabled_bg)]) self.protocolsTree.pack() return self.protocolsTree
def configure_main_treeview_style(self, style: ttk.Style, key: str, font: Tuple[str, int, str]) -> None: style.configure(key, font=font, rowheight=font[1] * 3, relief=tk.FLAT, borderwidth=0, highlightthickness=0, background=self._main_background, fieldbackground=self._main_background, foreground=self._main_foreground) style.map(key, foreground=[('selected', self._main_foreground_selected)], background=[('selected', self._main_background_selected)])
def __init__(self, master, env_name): self.ds = Dataset(source="", name="iam") self.RESULTS_PATH = "results/" self.master = master ##Init of the master view self.master.title("Handwritten flowchart with CNNs") self.master.configure(background="gray99") self.master.resizable(False, False) self.master.geometry("600x500") self.master.config(bg="#857074") # Predict self.selected_image = "" self.models_path = "model/training_results/" #training self.env_name = env_name #Header self.header = tk.Frame(self.master) self.header.config(width="1000", height="100", bg="#943340") self.header.pack(fill="y") self.header.pack_propagate(False) self.title = tk.Label(self.header, text="3b-flowchart", font=("Arial", 50), bg="#943340") self.title.pack(pady=20) style = Style() style.map('TButton', foreground=[('active', 'green')], background=[('active', 'black')]) #Buttons btn1 = tk.Button(self.master, height=4, font=("Arial", 15), width=25, text="Train shape model", command=self.train_window) btn1.pack(pady=10) btn2 = tk.Button(self.master, height=4, font=("Arial", 15), width=25, text="Recognize flowchart", command=self.recognize_flowchart_window) btn2.pack(pady=10) btn3 = tk.Button(self.master, height=4, font=("Arial", 15), width=25, text="Train text model", command=self.__train_text_model) btn3.pack(pady=10) self.master.mainloop()
def main(): root = Tk() root.resizable(0,0) s = Style() s.configure('My.TFrame', background='orange') s.configure('My.TButton', background='light gray') s.configure('My.TEntry', fieldbackground='light gray') s.configure('My.TRadiobutton', background='orange') s.map('My.TRadiobutton', background=[('active', '#FFC133')]) root.geometry("300x125") t431 = T431(root) root.mainloop()
def _alert_style(style: ttk.Style, name: str, background: str): style.configure( name, background=background, padding=0, relief=tk.RIDGE, borderwidth=1, font="TkDefaultFont", foreground="black", highlightbackground="white", ) style.map(name, background=[("!active", background), ("active", "white")])
def setup_style(style_object: ttk.Style): """ All the ttk style changes go in here. :param style_object: style object to configure and map. :return: """ style_object.theme_use("clam") style_object.configure("TFrame", background="#3a3a3a") style_object.configure("TNotebook", lightcolor="#242424", darkcolor="#242424", bordercolor="#242424", background="#3a3a3a", relief="flat") style_object.configure("TNotebook.Tab", background="#323232", bordercolor="#2d2d2d", relief="flat", foreground="white") style_object.map("TNotebook.Tab", background=[("selected", "#df4a16"), ("active", "#3c3c3c")]) style_object.configure("TLabelframe.Label", background="#3a3a3a", foreground="white") style_object.configure("TLabelframe", background="#3a3a3a", darkcolor="#242424", lightcolor="#242424", bordercolor="#242424") style_object.configure("TScrollbar", background="#868686", troughcolor="#323232", bordercolor="#323232") style_object.configure("TLabel", background="#3a3a3a", foreground="white") style_object.configure("TButton", background="#393939", foreground="white", bordercolor="#242424", darkcolor="#242424", lightcolor="#242424") style_object.map("TButton", background=[("pressed", "#202020"), ("active", "#3c3c3c")])
def style_for_ok_and_close_btn() -> None: """ Функция создания стилей для кнопок Ок и Отмена :return: """ style = Style() style.map( "OK.TButton", foreground=[('pressed', 'white'), ('active', 'green')], background=[('pressed', '#5CFF5D'), ('active', '#A5FF99'), ('!disabled', BUTTON_BACKGROUND)], ) style.map('Close.TButton', foreground=[('pressed', 'black'), ('active', '#B20007')], background=[('pressed', '#B20007'), ('active', '#FFA3B5')])
def __init__(self, master=None, **kw): Treeview.__init__(self, master, style='Checkbox.Treeview', **kw) # style (make a noticeable disabled style) style = Style(self) style.map("Checkbox.Treeview", fieldbackground=[("disabled", '#E6E6E6')], foreground=[("disabled", 'gray40')], background=[("disabled", '#E6E6E6')]) # checkboxes are implemented with pictures self.im_checked = PhotoImage(file=IM_CHECKED, master=self) self.im_unchecked = PhotoImage(file=IM_UNCHECKED, master=self) self.im_tristate = PhotoImage(file=IM_TRISTATE, master=self) self.tag_configure("unchecked", image=self.im_unchecked) self.tag_configure("tristate", image=self.im_tristate) self.tag_configure("checked", image=self.im_checked) # check / uncheck boxes on click self.bind("<Button-1>", self.box_click, True)
def __init__(self, parent, controller): tk.Frame.__init__(self, parent) label = tk.Label(self, text="Welcome to Zoo Monitor Data Mapper", font=LARGE_FONT, bg=BACKGROUND_COLOR) label.pack(pady=10, padx=10) style = Style() style.configure('TButton', font=BUTTON_FONT, borderwidth='4') style.map('TButton', foreground=[('active', '!disabled', 'green')], background=[('active', 'black')]) button = ttk.Button(self, text="Import Spreadsheet", style="TButton", command=lambda: controller.get_spreadsheet()) button.pack() button3 = ttk.Button( self, text="Graph Page", command=lambda: controller.show_frame(HeatMapPage)) button3.pack(pady=20) canvas = Canvas(self, width=800, height=507) #width and height of the logo.jpg image canvas.pack() img = ImageTk.PhotoImage(PIL.Image.open('resources/logo.jpg')) canvas.background = img # Keep a reference in case this code is put in a function. canvas.create_rectangle(0, 0, 600, 600, fill=BACKGROUND_COLOR, outline=BACKGROUND_COLOR) bg = canvas.create_image(0, 0, anchor=tk.NW, image=img) enclosure_image = Label(image="") enclosure_image.pack()
def _fixed_style_map(style: Style, style_name: str, option: str, highlight_colors: tuple[str, str] = (None, None)): # Fix for setting text color for Tkinter 8.6.9 # From: https://core.tcl.tk/tk/info/509cafafae default_map = [ elm for elm in style.map('Treeview', query_opt=option) if '!' not in elm[0] ] custom_map = [ elm for elm in style.map(style_name, query_opt=option) if '!' not in elm[0] ] if option == 'background': custom_map.append(('selected', highlight_colors[1] or 'SystemHighlight')) elif option == 'foreground': custom_map.append(('selected', highlight_colors[0] or 'SystemHighlightText')) return custom_map + default_map
class CreateStyle(): def __init__(self, parent): self.parent = parent self.style = Style() #self.style.theme_create("light", parent= "clam") self.style.theme_use("clam") #self.style.configure('TButton', foreground = 'white', background = 'blue') self.style.configure('TFrame', background=GREY) self.style.configure(BGWHITE, background=WHITE) self.style.configure(BGDARKGREY, background=DARKGREY) self.style.configure("TNotebook", background=GREY, borderwidth=0) self.style.map("TNotebook.Tab", background=[("selected", WHITE)], foreground=[("selected", BLACK)]) self.style.configure("TNotebook.Tab", background=DARKGREY, foreground=BLACK) self.style.configure("Tab", focuscolor=GREY) #self.parent.option_add('*Label.bg', 'red') self.parent.option_add('*TCombobox*Listbox.selectBackground', 'yellow') self.parent.option_add('*TCombobox*Listbox.selectForeground', 'black')
class Notification(Tk): def __init__(self, text=''): Tk.__init__(self) self.overrideredirect(True) self.withdraw() self.columnconfigure(0, weight=1) self.attributes('-type', 'notification') self.attributes('-alpha', 0.75) self.style = Style(self) self.style.theme_use('clam') self.bg = [ CONFIG.get('Reminders', 'window_bg'), CONFIG.get('Reminders', 'window_bg_alternate') ] self.fg = [ CONFIG.get('Reminders', 'window_fg'), CONFIG.get('Reminders', 'window_fg_alternate') ] self.active_bg = [active_color(*self.winfo_rgb(bg)) for bg in self.bg] self.active_bg2 = [ active_color(*self.winfo_rgb(bg)) for bg in self.active_bg ] self.style.configure('notif.TLabel', background=self.bg[0], foreground=self.fg[0]) self.style.configure('notif.TButton', background=self.active_bg[0], relief='flat', foreground=self.fg[0]) self.configure(bg=self.bg[0]) self.style.map('notif.TButton', background=[('active', self.active_bg2[0])]) Label(self, text=text, style='notif.TLabel').grid(row=0, column=0, padx=10, pady=10) Button(self, text='Ok', command=self.quit, style='notif.TButton').grid(row=1, column=0, padx=10, pady=(0, 10)) self.blink_alternate = False self.deiconify() self.update_idletasks() self.geometry('%ix%i+0+0' % (self.winfo_screenwidth(), self.winfo_height())) self.alarm_id = '' self.alarm_process = None self.blink_id = '' self.timeout_id = '' if CONFIG.getboolean('Reminders', 'blink'): self.blink_id = self.after(500, self.blink) if not CONFIG.getboolean("Reminders", "mute", fallback=False): self.alarm() timeout = CONFIG.getint('Reminders', 'timeout') * 60 * 1000 if timeout > 0: self.timeout_id = self.after(timeout, self.quit) def alarm(self): self.alarm_process = Popen([ CONFIG.get("General", "soundplayer"), CONFIG.get("Reminders", "alarm") ]) self.alarm_id = self.after(500, self.repeat_alarm) def repeat_alarm(self): if self.alarm_process.poll() is None: self.alarm_id = self.after(500, self.repeat_alarm) else: # ringing is finished self.alarm() def quit(self): try: self.after_cancel(self.alarm_id) except ValueError: pass try: self.after_cancel(self.blink_id) except ValueError: pass try: self.after_cancel(self.timeout_id) except ValueError: pass if self.alarm_process is not None: self.alarm_process.terminate() self.destroy() def blink(self): self.blink_alternate = not self.blink_alternate self.configure(bg=self.bg[self.blink_alternate]) self.style.configure('notif.TLabel', background=self.bg[self.blink_alternate], foreground=self.fg[self.blink_alternate]) self.style.configure('notif.TButton', background=self.active_bg[self.blink_alternate], relief='flat', foreground=self.fg[self.blink_alternate]) self.blink_id = self.after(500, self.blink)
class Sync(Tk): """FolderSync main window.""" def __init__(self): Tk.__init__(self, className='FolderSync') self.title("FolderSync") self.geometry("%ix%i" % (self.winfo_screenwidth(), self.winfo_screenheight())) self.protocol("WM_DELETE_WINDOW", self.quitter) self.icon = PhotoImage(master=self, file=IM_ICON) self.iconphoto(True, self.icon) self.rowconfigure(2, weight=1) self.columnconfigure(0, weight=1) # --- icons self.img_about = PhotoImage(master=self, file=IM_ABOUT) self.img_open = PhotoImage(master=self, file=IM_OPEN) self.img_plus = PhotoImage(master=self, file=IM_PLUS) self.img_moins = PhotoImage(master=self, file=IM_MOINS) self.img_sync = PhotoImage(master=self, file=IM_SYNC) self.img_prev = PhotoImage(master=self, file=IM_PREV) self.img_expand = PhotoImage(master=self, file=IM_EXPAND) self.img_collapse = PhotoImage(master=self, file=IM_COLLAPSE) self.original = "" self.sauvegarde = "" # list of files / folders to delete before starting the copy because # they are not of the same type on the original and the backup self.pb_chemins = [] self.err_copie = False self.err_supp = False # --- init log files l = [f for f in listdir(PATH) if match(r"foldersync[0-9]+.pid", f)] nbs = [] for f in l: with open(join(PATH, f)) as fich: old_pid = fich.read().strip() if exists("/proc/%s" % old_pid): nbs.append(int(search(r"[0-9]+", f).group())) else: remove(join(PATH, f)) if not nbs: i = 0 else: nbs.sort() i = 0 while i in nbs: i += 1 self.pidfile = PID_FILE % i open(self.pidfile, 'w').write(str(getpid())) self.log_copie = LOG_COPIE % i self.log_supp = LOG_SUPP % i self.logger_copie = setup_logger("copie", self.log_copie) self.logger_supp = setup_logger("supp", self.log_supp) date = datetime.now().strftime('%d/%m/%Y %H:%M') self.logger_copie.info("\n### %s ###\n" % date) self.logger_supp.info("\n### %s ###\n" % date) # --- filenames and extensions that will not be copied exclude_list = split(r'(?<!\\) ', CONFIG.get("Defaults", "exclude_copie")) self.exclude_names = [] self.exclude_ext = [] for elt in exclude_list: if elt: if elt[:2] == "*.": self.exclude_ext.append(elt[1:]) else: self.exclude_names.append(elt.replace("\ ", " ")) # --- paths that will not be deleted self.exclude_path_supp = [ ch.replace("\ ", " ") for ch in split( r'(?<!\\) ', CONFIG.get("Defaults", "exclude_supp")) if ch ] # while "" in self.exclude_path_supp: # self.exclude_path_supp.remove("") self.q_copie = Queue() self.q_supp = Queue() # True if a copy / deletion is running self.is_running_copie = False self.is_running_supp = False self.style = Style(self) self.style.theme_use("clam") self.style.configure("TProgressbar", troughcolor='lightgray', background='#387EF5', lightcolor="#5D95F5", darkcolor="#2758AB") self.style.map("TProgressbar", lightcolor=[("disabled", "white")], darkcolor=[("disabled", "gray")]) self.style.configure("folder.TButton", padding=0) # --- menu self.menu = Menu(self, tearoff=False) self.configure(menu=self.menu) # -------- recents self.menu_recent = Menu(self.menu, tearoff=False) if RECENT: for ch_o, ch_s in RECENT: self.menu_recent.add_command( label="%s -> %s" % (ch_o, ch_s), command=lambda o=ch_o, s=ch_s: self.open(o, s)) else: self.menu.entryconfigure(0, state="disabled") # -------- favorites self.menu_fav = Menu(self.menu, tearoff=False) self.menu_fav_del = Menu(self.menu_fav, tearoff=False) self.menu_fav.add_command(label=_("Add"), image=self.img_plus, compound="left", command=self.add_fav) self.menu_fav.add_cascade(label=_("Remove"), image=self.img_moins, compound="left", menu=self.menu_fav_del) for ch_o, ch_s in FAVORIS: label = "%s -> %s" % (ch_o, ch_s) self.menu_fav.add_command( label=label, command=lambda o=ch_o, s=ch_s: self.open(o, s)) self.menu_fav_del.add_command( label=label, command=lambda nom=label: self.del_fav(nom)) if not FAVORIS: self.menu_fav.entryconfigure(1, state="disabled") # -------- log files menu_log = Menu(self.menu, tearoff=False) menu_log.add_command(label=_("Copy"), command=self.open_log_copie) menu_log.add_command(label=_("Removal"), command=self.open_log_suppression) # -------- settings menu_params = Menu(self.menu, tearoff=False) self.copy_links = BooleanVar(self, value=CONFIG.getboolean( "Defaults", "copy_links")) self.show_size = BooleanVar(self, value=CONFIG.getboolean( "Defaults", "show_size")) menu_params.add_checkbutton(label=_("Copy links"), variable=self.copy_links, command=self.toggle_copy_links) menu_params.add_checkbutton(label=_("Show total size"), variable=self.show_size, command=self.toggle_show_size) self.langue = StringVar(self, CONFIG.get("Defaults", "language")) menu_lang = Menu(menu_params, tearoff=False) menu_lang.add_radiobutton(label="English", value="en", variable=self.langue, command=self.change_language) menu_lang.add_radiobutton(label="Français", value="fr", variable=self.langue, command=self.change_language) menu_params.add_cascade(label=_("Language"), menu=menu_lang) menu_params.add_command(label=_("Exclude from copy"), command=self.exclusion_copie) menu_params.add_command(label=_("Exclude from removal"), command=self.exclusion_supp) self.menu.add_cascade(label=_("Recents"), menu=self.menu_recent) self.menu.add_cascade(label=_("Favorites"), menu=self.menu_fav) self.menu.add_cascade(label=_("Log"), menu=menu_log) self.menu.add_cascade(label=_("Settings"), menu=menu_params) self.menu.add_command(image=self.img_prev, compound="center", command=self.list_files_to_sync) self.menu.add_command(image=self.img_sync, compound="center", state="disabled", command=self.synchronise) self.menu.add_command(image=self.img_about, compound="center", command=lambda: About(self)) # --- tooltips wrapper = TooltipMenuWrapper(self.menu) wrapper.add_tooltip(4, _('Preview')) wrapper.add_tooltip(5, _('Sync')) wrapper.add_tooltip(6, _('About')) # --- path selection frame_paths = Frame(self) frame_paths.grid(row=0, sticky="ew", pady=(10, 0)) frame_paths.columnconfigure(0, weight=1) frame_paths.columnconfigure(1, weight=1) f1 = Frame(frame_paths, height=26) f2 = Frame(frame_paths, height=26) f1.grid(row=0, column=0, sticky="ew") f2.grid(row=0, column=1, sticky="ew") f1.grid_propagate(False) f2.grid_propagate(False) f1.columnconfigure(1, weight=1) f2.columnconfigure(1, weight=1) # -------- path to original Label(f1, text=_("Original")).grid(row=0, column=0, padx=(10, 4)) f11 = Frame(f1) f11.grid(row=0, column=1, sticky="nsew", padx=(4, 0)) self.entry_orig = Entry(f11) self.entry_orig.place(x=1, y=0, bordermode='outside', relwidth=1) self.b_open_orig = Button(f1, image=self.img_open, style="folder.TButton", command=self.open_orig) self.b_open_orig.grid(row=0, column=2, padx=(0, 7)) # -------- path to backup Label(f2, text=_("Backup")).grid(row=0, column=0, padx=(8, 4)) f22 = Frame(f2) f22.grid(row=0, column=1, sticky="nsew", padx=(4, 0)) self.entry_sauve = Entry(f22) self.entry_sauve.place(x=1, y=0, bordermode='outside', relwidth=1) self.b_open_sauve = Button(f2, image=self.img_open, width=2, style="folder.TButton", command=self.open_sauve) self.b_open_sauve.grid(row=0, column=5, padx=(0, 10)) paned = PanedWindow(self, orient='horizontal') paned.grid(row=2, sticky="eswn") paned.rowconfigure(0, weight=1) paned.columnconfigure(1, weight=1) paned.columnconfigure(0, weight=1) # --- left side frame_left = Frame(paned) paned.add(frame_left, weight=1) frame_left.rowconfigure(3, weight=1) frame_left.columnconfigure(0, weight=1) # -------- files to copy f_left = Frame(frame_left) f_left.columnconfigure(2, weight=1) f_left.grid(row=2, columnspan=2, pady=(4, 2), padx=(10, 4), sticky="ew") Label(f_left, text=_("To copy")).grid(row=0, column=2) frame_copie = Frame(frame_left) frame_copie.rowconfigure(0, weight=1) frame_copie.columnconfigure(0, weight=1) frame_copie.grid(row=3, column=0, sticky="eswn", columnspan=2, pady=(2, 4), padx=(10, 4)) self.tree_copie = CheckboxTreeview(frame_copie, selectmode='none', show='tree') self.b_expand_copie = Button(f_left, image=self.img_expand, style="folder.TButton", command=self.tree_copie.expand_all) TooltipWrapper(self.b_expand_copie, text=_("Expand all")) self.b_expand_copie.grid(row=0, column=0) self.b_expand_copie.state(("disabled", )) self.b_collapse_copie = Button(f_left, image=self.img_collapse, style="folder.TButton", command=self.tree_copie.collapse_all) TooltipWrapper(self.b_collapse_copie, text=_("Collapse all")) self.b_collapse_copie.grid(row=0, column=1, padx=4) self.b_collapse_copie.state(("disabled", )) self.tree_copie.tag_configure("warning", foreground="red") self.tree_copie.tag_configure("link", font="tkDefaultFont 9 italic", foreground="blue") self.tree_copie.tag_bind("warning", "<Button-1>", self.show_warning) self.tree_copie.grid(row=0, column=0, sticky="eswn") self.scroll_y_copie = Scrollbar(frame_copie, orient="vertical", command=self.tree_copie.yview) self.scroll_y_copie.grid(row=0, column=1, sticky="ns") self.scroll_x_copie = Scrollbar(frame_copie, orient="horizontal", command=self.tree_copie.xview) self.scroll_x_copie.grid(row=1, column=0, sticky="ew") self.tree_copie.configure(yscrollcommand=self.scroll_y_copie.set, xscrollcommand=self.scroll_x_copie.set) self.pbar_copie = Progressbar(frame_left, orient="horizontal", mode="determinate") self.pbar_copie.grid(row=4, columnspan=2, sticky="ew", padx=(10, 4), pady=4) self.pbar_copie.state(("disabled", )) # --- right side frame_right = Frame(paned) paned.add(frame_right, weight=1) frame_right.rowconfigure(3, weight=1) frame_right.columnconfigure(0, weight=1) # -------- files to delete f_right = Frame(frame_right) f_right.columnconfigure(2, weight=1) f_right.grid(row=2, columnspan=2, pady=(4, 2), padx=(4, 10), sticky="ew") Label(f_right, text=_("To remove")).grid(row=0, column=2) frame_supp = Frame(frame_right) frame_supp.rowconfigure(0, weight=1) frame_supp.columnconfigure(0, weight=1) frame_supp.grid(row=3, columnspan=2, sticky="eswn", pady=(2, 4), padx=(4, 10)) self.tree_supp = CheckboxTreeview(frame_supp, selectmode='none', show='tree') self.b_expand_supp = Button(f_right, image=self.img_expand, style="folder.TButton", command=self.tree_supp.expand_all) TooltipWrapper(self.b_expand_supp, text=_("Expand all")) self.b_expand_supp.grid(row=0, column=0) self.b_expand_supp.state(("disabled", )) self.b_collapse_supp = Button(f_right, image=self.img_collapse, style="folder.TButton", command=self.tree_supp.collapse_all) TooltipWrapper(self.b_collapse_supp, text=_("Collapse all")) self.b_collapse_supp.grid(row=0, column=1, padx=4) self.b_collapse_supp.state(("disabled", )) self.tree_supp.grid(row=0, column=0, sticky="eswn") self.scroll_y_supp = Scrollbar(frame_supp, orient="vertical", command=self.tree_supp.yview) self.scroll_y_supp.grid(row=0, column=1, sticky="ns") self.scroll_x_supp = Scrollbar(frame_supp, orient="horizontal", command=self.tree_supp.xview) self.scroll_x_supp.grid(row=1, column=0, sticky="ew") self.tree_supp.configure(yscrollcommand=self.scroll_y_supp.set, xscrollcommand=self.scroll_x_supp.set) self.pbar_supp = Progressbar(frame_right, orient="horizontal", mode="determinate") self.pbar_supp.grid(row=4, columnspan=2, sticky="ew", padx=(4, 10), pady=4) self.pbar_supp.state(("disabled", )) # --- bindings self.entry_orig.bind("<Key-Return>", self.list_files_to_sync) self.entry_sauve.bind("<Key-Return>", self.list_files_to_sync) def exclusion_supp(self): excl = ExclusionsSupp(self) self.wait_window(excl) # paths that will not be deleted self.exclude_path_supp = [ ch.replace("\ ", " ") for ch in split( r'(?<!\\) ', CONFIG.get("Defaults", "exclude_supp")) if ch ] def exclusion_copie(self): excl = ExclusionsCopie(self) self.wait_window(excl) exclude_list = CONFIG.get("Defaults", "exclude_copie").split(" ") self.exclude_names = [] self.exclude_ext = [] for elt in exclude_list: if elt: if elt[:2] == "*.": self.exclude_ext.append(elt[2:]) else: self.exclude_names.append(elt) def toggle_copy_links(self): CONFIG.set("Defaults", "copy_links", str(self.copy_links.get())) def toggle_show_size(self): CONFIG.set("Defaults", "show_size", str(self.show_size.get())) def open_log_copie(self): open_file(self.log_copie) def open_log_suppression(self): open_file(self.log_supp) def quitter(self): rep = True if self.is_running_copie or self.is_running_supp: rep = askokcancel( _("Confirmation"), _("A synchronization is ongoing, do you really want to quit?"), parent=self) if rep: self.destroy() def del_fav(self, nom): self.menu_fav.delete(nom) self.menu_fav_del.delete(nom) FAVORIS.remove(tuple(nom.split(" -> "))) save_config() if not FAVORIS: self.menu_fav.entryconfigure(1, state="disabled") def add_fav(self): sauvegarde = self.entry_sauve.get() original = self.entry_orig.get() if original != sauvegarde and original and sauvegarde: if exists(original) and exists(sauvegarde): if not (original, sauvegarde) in FAVORIS: FAVORIS.append((original, sauvegarde)) save_config() label = "%s -> %s" % (original, sauvegarde) self.menu_fav.entryconfigure(1, state="normal") self.menu_fav.add_command(label=label, command=lambda o=original, s= sauvegarde: self.open(o, s)) self.menu_fav_del.add_command( label=label, command=lambda nom=label: self.del_fav(nom)) def open(self, ch_o, ch_s): self.entry_orig.delete(0, "end") self.entry_orig.insert(0, ch_o) self.entry_sauve.delete(0, "end") self.entry_sauve.insert(0, ch_s) self.list_files_to_sync() def open_sauve(self): sauvegarde = askdirectory(self.entry_sauve.get(), parent=self) if sauvegarde: self.entry_sauve.delete(0, "end") self.entry_sauve.insert(0, sauvegarde) def open_orig(self): original = askdirectory(self.entry_orig.get(), parent=self) if original: self.entry_orig.delete(0, "end") self.entry_orig.insert(0, original) def sync(self, original, sauvegarde): """ peuple tree_copie avec l'arborescence des fichiers d'original à copier vers sauvegarde et tree_supp avec celle des fichiers de sauvegarde à supprimer """ errors = [] copy_links = self.copy_links.get() excl_supp = [ path for path in self.exclude_path_supp if commonpath([path, sauvegarde]) == sauvegarde ] def get_name(elt): return elt.name.lower() def lower(char): return char.lower() def arbo(tree, parent, n): """ affiche l'arborescence complète de parent et renvoie la longueur maximale des items (pour gérer la scrollbar horizontale) """ m = 0 try: with scandir(parent) as content: l = sorted(content, key=get_name) for item in l: chemin = item.path nom = item.name if item.is_symlink(): if copy_links: tree.insert(parent, 'end', chemin, text=nom, tags=("whole", "link")) m = max(m, len(nom) * 9 + 20 * (n + 1)) elif ((nom not in self.exclude_names) and (splitext(nom)[-1] not in self.exclude_ext)): tree.insert(parent, 'end', chemin, text=nom, tags=("whole", )) m = max(m, len(nom) * 9 + 20 * (n + 1)) if item.is_dir(): m = max(m, arbo(tree, chemin, n + 1)) except NotADirectoryError: pass except Exception as e: errors.append(str(e)) return m def aux(orig, sauve, n, search_supp): m_copie = 0 m_supp = 0 try: lo = listdir(orig) ls = listdir(sauve) except Exception as e: errors.append(str(e)) lo = [] ls = [] lo.sort(key=lambda x: x.lower()) ls.sort(key=lambda x: x.lower()) supp = False copie = False if search_supp: for item in ls: chemin_s = join(sauve, item) if chemin_s not in excl_supp and item not in lo: supp = True self.tree_supp.insert(sauve, 'end', chemin_s, text=item, tags=("whole", )) m_supp = max(m_supp, int(len(item) * 9 + 20 * (n + 1)), arbo(self.tree_supp, chemin_s, n + 1)) for item in lo: chemin_o = join(orig, item) chemin_s = join(sauve, item) if ((item not in self.exclude_names) and (splitext(item)[-1] not in self.exclude_ext)): if item not in ls: # le dossier / fichier n'est pas dans la sauvegarde if islink(chemin_o): if copy_links: copie = True self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", "link")) m_copie = max( m_copie, (int(len(item) * 9 + 20 * (n + 1)))) else: copie = True self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", )) m_copie = max( m_copie, (int(len(item) * 9 + 20 * (n + 1))), arbo(self.tree_copie, chemin_o, n + 1)) elif islink(chemin_o) and exists(chemin_o): # checking the existence prevent from copying broken links if copy_links: if not islink(chemin_s): self.pb_chemins.append(chemin_o) tags = ("whole", "warning", "link") else: tags = ("whole", "link") self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=tags) m_copie = max(m_copie, int(len(item) * 9 + 20 * (n + 1))) copie = True elif isfile(chemin_o): # first check if chemin_s is also a file if isfile(chemin_s): if getmtime(chemin_o) // 60 > getmtime( chemin_s) // 60: # le fichier f a été modifié depuis la dernière sauvegarde copie = True self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", )) else: self.pb_chemins.append(chemin_o) self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", "warning")) elif isdir(chemin_o): # to avoid errors due to unrecognized item types (neither file nor folder nor link) if isdir(chemin_s): self.tree_copie.insert(orig, 'end', chemin_o, text=item) self.tree_supp.insert(sauve, 'end', chemin_s, text=item) c, s, mc, ms = aux( chemin_o, chemin_s, n + 1, search_supp and (chemin_s not in excl_supp)) supp = supp or s copie = copie or c if not c: # nothing to copy self.tree_copie.delete(chemin_o) else: m_copie = max( m_copie, mc, int(len(item) * 9 + 20 * (n + 1))) if not s: # nothing to delete self.tree_supp.delete(chemin_s) else: m_supp = max(m_supp, ms, int(len(item) * 9 + 20 * (n + 1))) else: copie = True self.pb_chemins.append(chemin_o) self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", "warning")) m_copie = max( m_copie, (int(len(item) * 9 + 20 * (n + 1))), arbo(self.tree_copie, chemin_o, n + 1)) return copie, supp, m_copie, m_supp self.tree_copie.insert("", 0, original, text=original, tags=("checked", ), open=True) self.tree_supp.insert("", 0, sauvegarde, text=sauvegarde, tags=("checked", ), open=True) c, s, mc, ms = aux(original, sauvegarde, 1, True) if not c: self.tree_copie.delete(original) self.tree_copie.column("#0", minwidth=0, width=0) else: mc = max(len(original) * 9 + 20, mc) self.tree_copie.column("#0", minwidth=mc, width=mc) if not s: self.tree_supp.delete(sauvegarde) self.tree_supp.column("#0", minwidth=0, width=0) else: ms = max(len(sauvegarde) * 9 + 20, mc) self.tree_supp.column("#0", minwidth=ms, width=ms) return errors def show_warning(self, event): if "disabled" not in self.b_open_orig.state(): x, y = event.x, event.y elem = event.widget.identify("element", x, y) if elem == "padding": orig = self.tree_copie.identify_row(y) sauve = orig.replace(self.original, self.sauvegarde) showwarning( _("Warning"), _("%(original)s and %(backup)s are not of the same kind (folder/file/link)" ) % { 'original': orig, 'backup': sauve }, master=self) def list_files_to_sync(self, event=None): """Display in a treeview the file to copy and the one to delete.""" self.pbar_copie.configure(value=0) self.pbar_supp.configure(value=0) self.sauvegarde = self.entry_sauve.get() self.original = self.entry_orig.get() if self.original != self.sauvegarde and self.original and self.sauvegarde: if exists(self.original) and exists(self.sauvegarde): o_s = (self.original, self.sauvegarde) if o_s in RECENT: RECENT.remove(o_s) self.menu_recent.delete("%s -> %s" % o_s) RECENT.insert(0, o_s) self.menu_recent.insert_command( 0, label="%s -> %s" % o_s, command=lambda o=self.original, s=self.sauvegarde: self. open(o, s)) if len(RECENT) == 10: del (RECENT[-1]) self.menu_recent.delete(9) save_config() self.menu.entryconfigure(0, state="normal") self.configure(cursor="watch") self.toggle_state_gui() self.update_idletasks() self.update() self.efface_tree() err = self.sync(self.original, self.sauvegarde) self.configure(cursor="") self.toggle_state_gui() c = self.tree_copie.get_children("") s = self.tree_supp.get_children("") if not (c or s): self.menu.entryconfigure(5, state="disabled") self.b_collapse_copie.state(("disabled", )) self.b_expand_copie.state(("disabled", )) self.b_collapse_supp.state(("disabled", )) self.b_expand_supp.state(("disabled", )) elif not c: self.b_collapse_copie.state(("disabled", )) self.b_expand_copie.state(("disabled", )) elif not s: self.b_collapse_supp.state(("disabled", )) self.b_expand_supp.state(("disabled", )) if err: showerror(_("Errors"), "\n".join(err), master=self) notification_send(_("Scan is finished.")) warnings = self.tree_copie.tag_has('warning') if warnings: showwarning( _("Warning"), _("Some elements to copy (in red) are not of the same kind on the original and the backup." ), master=self) else: showerror(_("Error"), _("Invalid path!"), master=self) def efface_tree(self): """Clear both trees.""" c = self.tree_copie.get_children("") for item in c: self.tree_copie.delete(item) s = self.tree_supp.get_children("") for item in s: self.tree_supp.delete(item) self.b_collapse_copie.state(("disabled", )) self.b_expand_copie.state(("disabled", )) self.b_collapse_supp.state(("disabled", )) self.b_expand_supp.state(("disabled", )) def toggle_state_gui(self): """Toggle the state (normal/disabled) of key elements of the GUI.""" if "disabled" in self.b_open_orig.state(): state = "!disabled" for i in range(7): self.menu.entryconfigure(i, state="normal") else: state = "disabled" for i in range(7): self.menu.entryconfigure(i, state="disabled") self.tree_copie.state((state, )) self.tree_supp.state((state, )) self.entry_orig.state((state, )) self.entry_sauve.state((state, )) self.b_expand_copie.state((state, )) self.b_collapse_copie.state((state, )) self.b_expand_supp.state((state, )) self.b_collapse_supp.state((state, )) self.b_open_orig.state((state, )) self.b_open_sauve.state((state, )) def update_pbar(self): """ Dislay the progress of the copy and deletion and put the GUI back in normal state once both processes are done. """ if not self.is_running_copie and not self.is_running_supp: notification_send(_("Sync is finished.")) self.toggle_state_gui() self.pbar_copie.configure(value=self.pbar_copie.cget("maximum")) self.pbar_supp.configure(value=self.pbar_supp.cget("maximum")) self.menu.entryconfigure(5, state="disabled") self.configure(cursor="") self.efface_tree() msg = "" if self.err_copie: msg += _( "There were errors during the copy, see %(file)s for more details.\n" ) % { 'file': self.log_copie } if self.err_supp: msg += _( "There were errors during the removal, see %(file)s for more details.\n" ) % { 'file': self.log_supp } if msg: showerror(_("Error"), msg, master=self) else: if not self.q_copie.empty(): self.pbar_copie.configure(value=self.q_copie.get()) if not self.q_supp.empty(): self.pbar_supp.configure(value=self.q_supp.get()) self.update() self.after(50, self.update_pbar) @staticmethod def get_list(tree): """Return the list of files/folders to copy/delete (depending on the tree).""" selected = [] def aux(item): tags = tree.item(item, "tags") if "checked" in tags and "whole" in tags: selected.append(item) elif "checked" in tags or "tristate" in tags: ch = tree.get_children(item) for c in ch: aux(c) ch = tree.get_children("") for c in ch: aux(c) return selected def synchronise(self): """ Display the list of files/folders that will be copied / deleted and launch the copy and deletion if the user validates the sync. """ # get files to delete and folder to delete if they are empty a_supp = self.get_list(self.tree_supp) # get files to copy a_copier = self.get_list(self.tree_copie) a_supp_avant_cp = [] for ch in self.pb_chemins: if ch in a_copier: a_supp_avant_cp.append( ch.replace(self.original, self.sauvegarde)) if a_supp or a_copier: Confirmation(self, a_copier, a_supp, a_supp_avant_cp, self.original, self.sauvegarde, self.show_size.get()) def copie_supp(self, a_copier, a_supp, a_supp_avant_cp): """Launch sync.""" self.toggle_state_gui() self.configure(cursor="watch") self.update() self.pbar_copie.state(("!disabled", )) self.pbar_supp.state(("!disabled", )) nbtot_copie = len(a_copier) + len(a_supp_avant_cp) self.pbar_copie.configure(maximum=nbtot_copie, value=0) nbtot_supp = len(a_supp) self.pbar_supp.configure(maximum=nbtot_supp, value=0) self.is_running_copie = True self.is_running_supp = True process_copie = Thread(target=self.copie, name="copie", daemon=True, args=(a_copier, a_supp_avant_cp)) process_supp = Thread(target=self.supp, daemon=True, name="suppression", args=(a_supp, )) process_copie.start() process_supp.start() self.pbar_copie.configure(value=0) self.pbar_supp.configure(value=0) self.update_pbar() def copie(self, a_copier, a_supp_avant_cp): """ Copie tous les fichiers/dossiers de a_copier de original vers sauvegarde en utilisant la commande système cp. Les erreurs rencontrées au cours du processus sont inscrites dans ~/.foldersync/copie.log """ self.err_copie = False orig = abspath(self.original) + "/" sauve = abspath(self.sauvegarde) + "/" chdir(orig) self.logger_copie.info( _("\n###### Copy: %(original)s -> %(backup)s\n") % { 'original': self.original, 'backup': self.sauvegarde }) n = len(a_supp_avant_cp) self.logger_copie.info(_("Removal before copy:")) for i, ch in zip(range(1, n + 1), a_supp_avant_cp): self.logger_copie.info(ch) p_copie = run(["rm", "-r", ch], stderr=PIPE) self.q_copie.put(i) err = p_copie.stderr.decode() if err: self.err_copie = True self.logger_copie.error(err.strip()) self.logger_copie.info(_("Copy:")) for i, ch in zip(range(n + 1, n + 1 + len(a_copier)), a_copier): ch_o = ch.replace(orig, "") self.logger_copie.info("%s -> %s" % (ch_o, sauve)) p_copie = run(["cp", "-ra", "--parents", ch_o, sauve], stderr=PIPE) self.q_copie.put(i) err = p_copie.stderr.decode() if err: self.err_copie = True self.logger_copie.error(err.strip()) self.is_running_copie = False def supp(self, a_supp): """ Supprime tous les fichiers/dossiers de a_supp de original vers sauvegarde en utilisant la commande système rm. Les erreurs rencontrées au cours du processus sont inscrites dans ~/.foldersync/suppression.log. """ self.err_supp = False self.logger_supp.info( _("\n###### Removal: %(original)s -> %(backup)s\n") % { 'original': self.original, 'backup': self.sauvegarde }) for i, ch in enumerate(a_supp): self.logger_supp.info(ch) p_supp = run(["rm", "-r", ch], stderr=PIPE) self.q_supp.put(i + 1) err = p_supp.stderr.decode() if err: self.logger_supp.error(err.strip()) self.err_supp = True self.is_running_supp = False def unlink(self): """Unlink pidfile.""" unlink(self.pidfile) def change_language(self): """Change app language.""" CONFIG.set("Defaults", "language", self.langue.get()) showinfo( _("Information"), _("The language setting will take effect after restarting the application" ))
class box(gui.Tk): def __init__(self): #op = operators() self.op = -1 self.b = '' self.a = '' self.first = '' self.second = '' self.action = '' super().__init__() self.title("Calculator") self.resizable(width=False, height=False) self.frame = ttk.Frame(self).grid() self.display = ttk.Entry(text='0', font=('Comic Sans MS', 25), foreground='#33334d', background='#e6e6e6') self.display.grid(row=0, columnspan=8, sticky=gui.W + gui.E) self.look_special = Style() self.look_operators = Style() self.look_numbers = Style() self.look_numbers.theme_use('alt') self.look_equal = Style() #styling buttons self.look_special.configure('s.TButton', relief='flat', font=('callbri', 13, 'bold'), foreground='red', ipading=0, borderwidth=1, background='#ffe6e6', focusthickness=3, focuscolor='none') self.look_operators.configure('op.TButton', relief='flat', font=('callbri', 13, 'bold'), foreground='blue', ipading=0, borderwidth=1, background='#ccffff', focusthickness=3, focuscolor='none') self.look_numbers.configure('num.TButton', relief='flat', font=('callbri', 13, 'bold'), bordercolor='black', ipading=0, foreground='black', background='#e6ffff', borderwidth=1, focusthickness=1, focuscolor='none') self.look_equal.configure('eq.TButton', relief='flat', font=('callbri', 13, 'bold'), foreground='#0000b3', ipading=0, borderwidth=1, background='#99d6ff', focusthickness=3, focuscolor='none') ##styling buttons on hover self.look_numbers.map('num.TButton', foreground=[('pressed', 'black'), ('active', 'black')], background=[('pressed', '!disabled', '#00ffff'), ('active', '#80ffff')]) self.look_operators.map('op.TButton', foreground=[('pressed', 'blue'), ('active', 'blue')], background=[('pressed', '!disabled', '#00cccc'), ('active', '#4dffff')]) self.look_special.map('s.TButton', foreground=[('pressed', 'red'), ('active', 'red')], background=[('pressed', '!disabled', '#ff8080'), ('active', '#ffb3b3')]) self.look_equal.map('eq.TButton', foreground=[('pressed', 'blue'), ('active', 'blue')], background=[('pressed', '!disabled', '#33adff'), ('active', '#66c2ff')]) self.buttons() def buttons(self): #printing numbers self.clc = ttk.Button(text="C", style='s.TButton', command=lambda: self.clearing()) self.clc.grid(row=1, column=0, ipady=20, ipadx=8) self.div = ttk.Button(text="/", style='op.TButton', command=lambda: self.operate('/')) self.div.grid(row=1, column=1, ipady=20, ipadx=8) self.mul = ttk.Button(text="X", style='op.TButton', command=lambda: self.operate('x')) self.mul.grid(row=1, column=2, ipady=20, ipadx=8) self.back = ttk.Button(text="<-", style='s.TButton', command=lambda: self.backspace()) self.back.grid(row=1, column=3, ipady=20, ipadx=8) self.seven = ttk.Button(text="7", style='num.TButton', command=lambda: self.getdata(7)) self.seven.grid(row=2, column=0, ipady=20, ipadx=8) self.eighth = ttk.Button(text="8", style='num.TButton', command=lambda: self.getdata(8)) self.eighth.grid(row=2, column=1, ipady=20, ipadx=8) self.nine = ttk.Button(text="9", style='num.TButton', command=lambda: self.getdata(9)) self.nine.grid(row=2, column=2, ipady=20, ipadx=8) self.sub = ttk.Button(text="-", style='op.TButton', command=lambda: self.operate('-')) self.sub.grid(row=2, column=3, ipady=20, ipadx=8) self.four = ttk.Button(text="4", style='num.TButton', command=lambda: self.getdata(4)) self.four.grid(row=3, column=0, ipady=20, ipadx=8) self.five = ttk.Button(text="5", style='num.TButton', command=lambda: self.getdata(5)) self.five.grid(row=3, column=1, ipady=20, ipadx=8) self.six = ttk.Button(text="6", style='num.TButton', command=lambda: self.getdata(6)) self.six.grid(row=3, column=2, ipady=20, ipadx=8) self.add = ttk.Button(text="+", style='op.TButton', command=lambda: self.operate('+')) self.add.grid(row=3, column=3, ipady=20, ipadx=8) self.one = ttk.Button(text="1", style='num.TButton', command=lambda: self.getdata(1)) self.one.grid(row=4, column=0, ipady=20, ipadx=8) self.two = ttk.Button(text="2", style='num.TButton', command=lambda: self.getdata(2)) self.two.grid(row=4, column=1, ipady=20, ipadx=8) self.three = ttk.Button(text="3", style='num.TButton', command=lambda: self.getdata(3)) self.three.grid(row=4, column=2, ipady=20, ipadx=8) self.pow = ttk.Button(text="^", style='op.TButton', command=lambda: self.operate('^')) self.pow.grid(row=4, column=3, ipady=20, ipadx=8) self.equal = ttk.Button(text="=", style='eq.TButton', command=lambda: self.getdata('=')) self.equal.grid(row=5, column=3, rowspan=2, ipady=50, ipadx=8) self.mod = ttk.Button(text="%", style='op.TButton', command=lambda: self.operate('%')) self.mod.grid(row=5, column=0, ipady=20, ipadx=8) self.zero = ttk.Button(text="0", style='num.TButton', command=lambda: self.getdata(0)) self.zero.grid(row=5, column=1, ipady=20, ipadx=8) self.deci = ttk.Button(text=".", style='num.TButton', command=lambda: self.getdata('.')) self.deci.grid(row=5, column=2, ipady=20, ipadx=8) self.sine = ttk.Button(text="sin", style='op.TButton', command=lambda: self.trigno('sin')) self.sine.grid(row=6, column=0, ipady=20, ipadx=8) self.cos = ttk.Button(text="cos", style='op.TButton', command=lambda: self.trigno('cos')) self.cos.grid(row=6, column=1, ipady=20, ipadx=8) self.tan = ttk.Button(text="tan", style='op.TButton', command=lambda: self.trigno('tan')) self.tan.grid(row=6, column=2, ipady=20, ipadx=8) def clearing(self): self.display.delete(0, gui.END) self.first = '' self.second = '' self.op = -1 self.x = '' def backspace(self): if self.op == -1: return if self.op == 0: self.first = str(self.first) self.first = self.first[:-1] self.display.delete(0, gui.END) check = type(self.first) if check == int: self.first = int(self.first) self.display.insert(0, self.first) def calc_trigno(self, x, point): x = float(x) if self.t_action == 'sin': self.ans = comp.sine(x) if self.t_action == 'tan': self.ans = comp.tangent(x) if self.t_action == 'cos': self.ans = comp.cosine(x) check = type(self.ans) if check == int: self.ans = int(self.ans) if point == -1: self.first = self.ans self.second = '' self.t_action = "" self.op = 3 if point == 0: self.second = self.ans self.t_action = '' self.op = 2 self.getdata('=') self.display.delete(0, gui.END) self.display.insert(0, self.ans) def calc(self, a, b, p): print(a) a = float(a) b = float(b) avi = ['+', '-', "/", 'x', '%', '^'] if p in avi: if p == '+': self.ans = comp.add(a, b) if p == '-': self.ans = comp.sub(a, b) if p == 'x': self.ans = comp.multi(a, b) if p == '/': self.ans = comp.div(a, b) if p == '%': self.ans = comp.mod(a, b) if p == '^': self.ans = comp.power(a, b) check = type(self.ans) if check == int: self.ans = int(self.ans) self.first = self.ans self.second = '' self.action = "" self.op = 3 self.display.delete(0, gui.END) self.display.insert(0, self.ans) def getdata(self, x): if self.op == 3 and self.action == '': self.first = '' self.display.delete(0, gui.END) self.display.insert(0, self.first) self.op = -1 if self.op == 10 and x != '=': try: self.first += str(x) check = type(self.first) if check == int: self.first = int(self.first) self.display.delete(0, gui.END) self.display.insert(0, str(self.t_action) + ' ' + str(self.first)) except ValueError: print('first error') return if self.op == 12 and x != '=': try: self.second += str(x) check = type(self.second) if check == int: self.second = int(self.second) self.display.delete(0, gui.END) self.display.insert( 0, str(self.first) + str(self.action) + str(self.t_action) + ' ' + str(self.second)) except ValueError: print('first error') return if x == "=": if self.op == -1 or self.op == 0 or self.op == 1: return if self.op == 2: self.calc(self.first, self.second, self.action) if self.op == 10: self.calc_trigno(self.first, -1) if self.op == 12: self.calc_trigno(self.second, 0) if (self.op == -1 or self.op == 0) and x != '=': try: self.first += str(x) check = type(self.first) if check == int: self.first = int(self.first) self.display.delete(0, gui.END) self.display.insert(0, self.first) print(self.first) if self.first != 0: self.op = 0 except ValueError: print('first error') return if (self.op == 1 or self.op == 2) and x != '=': try: self.second += str(x) check = type(self.second) if check == int: self.second = int(self.second) self.display.delete(0, gui.END) self.display.insert( 0, str(self.first) + self.action + str(self.second)) if self.second != 0: self.op = 2 except ValueError: print('second error') return def operate(self, y): if self.op == -1: if y == '-' or y == '+': self.sign = y self.action = '' self.op = 0 if self.op == 0: self.action = y self.op = 1 self.display.delete(0, gui.END) check = type(self.first) if check == int: self.first = int(self.first) self.display.insert(0, str(self.first) + y) if self.op == 2: self.getdata('=') self.action = y if self.op == 3: self.action = y self.op = 1 self.display.delete(0, gui.END) check = type(self.first) if check == int: self.first = int(self.first) self.display.insert(0, str(self.first) + y) def trigno(self, t): if self.op == -1: self.op = 10 self.t_action = t self.display.delete(0, gui.END) self.display.insert(0, self.t_action) if self.op == 1: self.op = 12 self.t_action = t self.display.delete(0, gui.END) self.display.insert(0, self.first + self.action + self.t_action) def run(self): self.mainloop()
class cGUI: def __init__(self): #accept a q for the Queue Object self.database = IC_Database.database(False) #initial IC statuses self.mS1 = cStatus.OFFLINE self.mS2 = cStatus.OFFLINE self.mS3 = cStatus.OFFLINE self.toShutdown = ['offline', 'offline', 'offline'] #Root frame self.mRoot = Tk() self.mNote = Notebook(self.mRoot) #notebook used to create tabs #Gif Frames self.frames =[PhotoImage(file="pi.gif", format="gif -index %i" %(i)) for i in range(80)] self.idx1 = 0 self.idx2 = 0 self.idx3 = 0 self.mRoot.title("VIEC Network System Status") #set title self.mRoot.attributes("-zoomed", True) #start in fullscreen #Placing Notebook and create tab frames self.mNote.grid(row=0, column=0) self.mStatusTab = Frame(self.mNote) self.mHelpTab = Frame(self.mNote) #add tabs to notebook self.mNote.add(self.mStatusTab, text="IC Statuses") self.mNote.add(self.mHelpTab, text="Help") self.mRoot.attributes("-alpha", 0) #set window as transparent self.mRoot.update() #displays window self.mOffset = self.mNote.winfo_reqheight() #size of the tabs self.height, self.width = self.getScreenSize() #get usable screen size self.mUsable = self.height - (2*self.mOffset) #size for status tab = screen size - tab size ############### STATUS TAB ##################################################################### #setting column and row sizes for Status tab self.mStatusTab.grid_rowconfigure(0, weight=1, minsize=(self.mUsable/2)) self.mStatusTab.grid_rowconfigure(1, weight=1, minsize=(self.mUsable/2)) self.mStatusTab.grid_columnconfigure(0, weight=1, minsize=(self.width)) #splitting status tab into two frames self.mTopFrame = Frame(self.mStatusTab, width=self.width, height=(self.mUsable/2)) self.mTopFrame.grid(row=0) self.mTopFrame.grid_rowconfigure(0, weight=1, minsize=(self.mUsable/2)) self.mTopFrame.grid_columnconfigure(0, weight=1, minsize=(self.width/2)) self.mTopFrame.grid_columnconfigure(1, weight=1, minsize=(self.width/2)) self.mBottomFrame = Frame(self.mStatusTab, width=self.width, height=(self.mUsable/2)) self.mBottomFrame.grid(row=1) self.mBottomFrame.grid_rowconfigure(0, weight=1, minsize=(self.mUsable/2)) self.mBottomFrame.grid_columnconfigure(0, weight=1, minsize=self.width) #IC Frames self.mIC1 = Frame(self.mTopFrame, width=(self.width/2), height=(self.mUsable/2)) self.mIC1.grid(row=0, column=0) self.mIC1.grid_columnconfigure(0, weight=1, minsize=(self.width/2)) self.mIC2 = Frame(self.mTopFrame, width=(self.width/2), height=(self.mUsable/2)) self.mIC2.grid(row=0, column=1) self.mIC2.grid_columnconfigure(0, weight=1, minsize=(self.width/2)) self.mIC3 = Frame(self.mBottomFrame, width=self.width, height=(self.mUsable)) self.mIC3.grid(row=0, column=0) self.mIC3.grid_columnconfigure(0, weight=1, minsize=self.width) #IC Styles self.s = Style() self.s.configure("offline.TButton", font=(None, 15), pady=3, foreground='black', state=DISABLED) self.s.map('offline.TButton',foreground=[('disabled', 'black')]) self.s.configure("runnning.TButton", font=(None, 15), pady=3, foreground='green', state=NORMAL) self.s.configure("caution.TButton", font=(None, 15), pady=3, foreground='yellow4', state=NORMAL) self.s.configure("failed.TButton", font=(None, 15), pady=3, foreground='red', state=NORMAL) #add IC1 widgets self.mIC1Label = Label(self.mIC1, text="Habitat Lighting System", font=(None, 15), pady=5) self.mIC1Label.grid(row=0, column=0) self.mIC1ImageLabel = Label(self.mIC1, image=self.frames[0], width=128, height=128) self.mIC1ImageLabel.grid(row=1) self.mIC1Status = Button(self.mIC1, text="Offline", style='offline.TButton', state=DISABLED, command=lambda app=1: self.shutdownIC(app)) self.mIC1Status.grid(row=2) #add IC2 widgets self.mIC2Label = Label(self.mIC2, text="Environment Monitoring System", font=(None, 15),pady=5) self.mIC2Label.grid(row=0, column=0) self.mIC2ImageLabel = Label(self.mIC2, image=self.frames[0], width=128, height=128) self.mIC2ImageLabel.grid(row=1) self.mIC2Status = Button(self.mIC2, text="Offline", style='offline.TButton', state=DISABLED, command=lambda app=2: self.shutdownIC(app)) self.mIC2Status.grid(row=2, column=0) #add IC3 widgets self.mIC3Label = Label(self.mIC3, text="Reaction Control System", font=(None, 15), pady=5) self.mIC3Label.grid(row=0, column=0) self.mIC3ImageLabel = Label(self.mIC3, image=self.frames[0], width=128, height=128) self.mIC3ImageLabel.grid(row=1) self.mIC3Status = Button(self.mIC3, text="Offline", style='offline.TButton', state=DISABLED, command=lambda app = 3: self.shutdownIC(app)) self.mIC3Status.grid(row=2) ############### HELP TAB ####################################################################### self.mHelpTab.grid_columnconfigure(0, weight=1, minsize=self.width) self.mHelpTab.grid_rowconfigure(0, weight=1, minsize=self.mUsable/8) self.mHelpTab.grid_rowconfigure(1, weight=1, minsize=3*self.mUsable/8) self.mHelpTab.grid_rowconfigure(2, weight=1, minsize=1*self.mUsable/8) self.help =PhotoImage(file="help.gif", format="gif") self.mHelpTitleLabel = Label(self.mHelpTab, text="How to Replace ICs", font=(None, 20), pady=5) self.mHelpTitleLabel.grid(row=0, column=0) self.mHelpImageLabel = Label(self.mHelpTab, image=self.help, width=300, height=225) self.mHelpImageLabel.grid(row=1) self.mHelpInsLabel = Label(self.mHelpTab, text="1. Remove the Ethernet, Power, and Universal Connector\ \n 2. Plug in new IC "\ , font=(None, 15), pady=5) self.mHelpInsLabel.grid(row=2, column=0) ############### START GUI ####################################################################### self.mRoot.after(25, self.updateGif) self.mRoot.after(1000, self.update) self.mRoot.protocol("WM_DELETE_WINDOW", self.onClosing) self.shutdown = False def onClosing(self): self.shutdown = True tkinter.messagebox.showinfo("System Shutdown", "Shutting down... Please wait.") def getScreenSize(self): height = self.mRoot.winfo_height() #get current height of screen width = self.mRoot.winfo_width() #get current width of screen self.mRoot.attributes("-alpha", 1) #set window as opaque return (height, width) def update(self): self.mS1 = self.setStatus(self.mS1, self.mIC1Status, (1,)) self.mS2 = self.setStatus(self.mS2, self.mIC2Status, (2,)) self.mS3 = self.setStatus(self.mS3, self.mIC3Status, (3,)) self.mRoot.after(1000, self.update) def updateGif(self): status1 = self.database.getStatus((1,)) if len(status1) != 0 and (status1[0][0] == 'RUNNING' or status1[0][0] == 'CAUTION'): self.idx1 = (self.idx1 + 1) % 80 self.mIC1ImageLabel.configure(image=self.frames[self.idx1]) status2 = self.database.getStatus((2,)) if len(status2) != 0 and (status2[0][0] == 'RUNNING' or status2[0][0] == 'CAUTION'): self.idx2 = (self.idx2 + 1) % 80 self.mIC2ImageLabel.configure(image=self.frames[self.idx2]) status3 = self.database.getStatus((3,)) if len(status3) != 0 and (status3[0][0] == 'RUNNING' or status3[0][0] == 'CAUTION'): self.idx3 = (self.idx3 + 1) % 80 self.mIC3ImageLabel.configure(image=self.frames[self.idx3]) self.mRoot.after(35, self.updateGif) def setStatus(self, oldS, label, app): #this is where the database will be read status = (self.database.getStatus(app)) if len(status) != 0: if status[0][0] == 'RUNNING': newS = cStatus.RUNNING elif status[0][0] == 'CAUTION': newS = cStatus.CAUTION elif status[0][0] == 'FAILED' : newS = cStatus.FAILED else: raise Exception else: newS = cStatus.OFFLINE self.toShutdown[app[0]-1] = 'offline' if oldS != newS: self.setStatusString(newS, label) return newS def setStatusString(self, s, label): if s == cStatus.OFFLINE: label.configure(text="Offline", state=DISABLED, style='offline.TButton') #fg="black", elif s == cStatus.RUNNING: label.configure(text="Running", state=NORMAL, style='runnning.TButton')#fg="green", elif s == cStatus.CAUTION: label.configure(text="Not Responding", state=NORMAL, style='caution.TButton')#, fg="yellow4") else: label.configure(text="Failed", state=NORMAL, style='failed.TButton')#, fg="red") def shutdownIC(self, app): #function to trigger a shutdown sequence for a particular IC self.toShutdown[app-1] = 'true'
class MainFrame(Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("InstaDjango") self.pack(fill=BOTH, expand=1) self.size_and_center_window() self.style = Style() self.style.theme_use("clam") self.style.configure("TFrame", background="#808080", foreground="white") self.style.configure("TButton", background="#808080", foreground="white") self.style.configure("high.TButton", background="#8FBC8B", foreground="white") self.style.configure("TLabel", background="#808080", foreground="white") self.style.map("TButton", background=[("pressed", "#404040"), ("active", "#A0A0A0")]) frame = Frame(self, relief=FLAT, borderwidth=1) frame.pack(fill=BOTH, expand=1) subframe_0 = Frame(frame, relief=FLAT, borderwidth=0) subframe_0.pack(fill=X) lbl_0 = Label(subframe_0, text="App's machine-readable name (used for naming folders locally and remotely):", style="TLabel") lbl_0.pack(fill=BOTH, padx=10, pady=10) entry_0 = Entry(subframe_0) entry_0.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_0, "") subframe_1 = Frame(frame, relief=FLAT, borderwidth=0) subframe_1.pack(fill=X) lbl_1 = Label( subframe_1, text="Where to create the app's folder locally:", style="TLabel") lbl_1.pack(fill=BOTH, padx=10, pady=10) entry_1 = Entry(subframe_1) def action_1(): cdir = filedialog.askdirectory(title="Please select a directory") if cdir: self.set_entry_text(entry_1, cdir) button_1 = Button(subframe_1, text="Choose", command=action_1, style="TButton") button_1.pack(side=RIGHT, padx=10, pady=0) entry_1.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_1, "") subframe_2 = Frame(frame, relief=FLAT, borderwidth=0) subframe_2.pack(fill=X) lbl_2 = Label(subframe_2, text="Remote host:", style="TLabel") lbl_2.pack(fill=BOTH, padx=10, pady=10) entry_2 = Entry(subframe_2) entry_2.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_2, "") subframe_3 = Frame(frame, relief=FLAT, borderwidth=0) subframe_3.pack(fill=X) lbl_3 = Label( subframe_3, text="Remote SSH port (empty will mean the default port):", style="TLabel") lbl_3.pack(fill=BOTH, padx=10, pady=10) entry_3 = Entry(subframe_3) entry_3.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_3, "") subframe_4 = Frame(frame, relief=FLAT, borderwidth=0) subframe_4.pack(fill=X) lbl_4 = Label(subframe_4, text="Remote user:"******"TLabel") lbl_4.pack(fill=BOTH, padx=10, pady=10) entry_4 = Entry(subframe_4) entry_4.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_4, "") subframe_5 = Frame(frame, relief=FLAT, borderwidth=0) subframe_5.pack(fill=X) lbl_5 = Label( subframe_5, text="Local path to the SSH private key:", style="TLabel") lbl_5.pack(fill=BOTH, padx=10, pady=10) entry_5 = Entry(subframe_5) def action_5(): cdir = filedialog.askopenfilename(title="Please select a private key") if cdir: self.set_entry_text(entry_5, cdir) button_5 = Button(subframe_5, text="Choose", command=action_5, style="TButton") button_5.pack(side=RIGHT, padx=10, pady=0) entry_5.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_5, "") subframe_6 = Frame(frame, relief=FLAT, borderwidth=0) subframe_6.pack(fill=X) lbl_6 = Label( subframe_6, text="Where to create the app's folder remotely (should not be owned by root):", style="TLabel") lbl_6.pack(fill=BOTH, padx=10, pady=10) entry_6 = Entry(subframe_6) entry_6.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_6, "/var/www") subframe_7 = Frame(frame, relief=FLAT, borderwidth=0) subframe_7.pack(fill=X) lbl_7 = Label(subframe_7, text="Sudo password:"******"TLabel") lbl_7.pack(fill=BOTH, padx=10, pady=10) entry_7 = Entry(subframe_7, show="*") entry_7.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_7, "") subframe_8 = Frame(frame, relief=FLAT, borderwidth=0) subframe_8.pack(fill=X) lbl_8 = Label(subframe_8, text="Database password:"******"TLabel") lbl_8.pack(fill=BOTH, padx=10, pady=10) entry_8 = Entry(subframe_8, show="*") entry_8.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_8, "") subframe_9 = Frame(frame, relief=FLAT, borderwidth=0) subframe_9.pack(fill=X) lbl_9 = Label(subframe_9, text="Domain:", style="TLabel") lbl_9.pack(fill=BOTH, padx=10, pady=10) entry_9 = Entry(subframe_9) entry_9.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_9, "dev.example.com") subframe_10 = Frame(frame, relief=FLAT, borderwidth=0) subframe_10.pack(fill=X) lbl_10 = Label(subframe_10, text="Django installation type (local, production, staging):", style="TLabel") lbl_10.pack(fill=BOTH, padx=10, pady=10) entry_10 = Entry(subframe_10) entry_10.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_10, "local") def go(): setup_django_project( proj=entry_0.get(), proj_local_parent_dir=entry_1.get(), host=entry_2.get(), port=entry_3.get(), user=entry_4.get(), ssh_key=entry_5.get(), proj_remote_parent_dir=entry_6.get(), sudo_pass=entry_7.get(), db_pass=entry_8.get(), domain=entry_9.get(), insta_type=entry_10.get()) self.quit() inst_button = Button(self, text="Go", command=go, style="high.TButton") inst_button.pack(side=RIGHT, padx=10, pady=10) quit_button = Button(self, text="Quit", command=self.quit, style="TButton") quit_button.pack(side=RIGHT, pady=10) def size_and_center_window(self): w = 640 h = 850 sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() x = (sw - w)/2 y = (sh - h)/2 self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y)) @staticmethod def set_entry_text(e, text): e.delete(0, END) e.insert(0, text)
class AbstractTkApp(threading.Thread): __metaclass__ = ABCMeta def __init__(self): super().__init__() self.logger = logging.getLogger(self.__class__.__name__) self.window = None self.window_title = f"{PROJECT_NAME}" self.window_background_text = "" self.style = None self.top_frame = None self.bottom_frame = None self.start() def run(self): try: self.window = Tk() # set style self.style = Style() self.style.configure('Bot.TButton', background=BACKGROUND_COLOR, foreground=BUTTON_TEXT_COLOR) self.style.map('Bot.TButton', background=[('active', ACTIVE_COLOR)], relief=[('pressed', '!disabled', 'sunken')]) self.style.configure('Bot.TFrame', background=BACKGROUND_COLOR) self.style.configure('Bot.TLabel', background=BACKGROUND_COLOR, foreground="white") self.style.configure('Bot.Horizontal.TProgressbar', foreground=PROGRESS_BAR_COLOR, background=PROGRESS_BAR_COLOR) # window settings self.window.title(self.window_title) self.window.protocol("WM_DELETE_WINDOW", self.close_callback) # self.window.configure(background=BACKGROUND_COLOR) try: self.window.iconbitmap('interfaces/web/static/favicon.ico') except Exception as e: self.logger.error("Failed to load tk window icon" + str(e)) self.window.geometry(f"{WINDOW_SIZE_WIDTH}x{WINDOW_SIZE_HEIGHT}") # background try: background_image = PhotoImage( file="interfaces/web/static/img/octobot.png") background_label = tkinter.Label( self.window, image=background_image, text=self.window_background_text, compound=CENTER, background=BACKGROUND_COLOR) background_label.place(x=0, y=0, relwidth=1, relheight=1) except Exception as e: self.logger.error("Failed to load tk window background" + str(e)) # frames self.top_frame = Frame(self.window, style='Bot.TFrame') self.bottom_frame = Frame(self.window, style='Bot.TFrame') self.top_frame.pack(side="top", fill="y", expand=False) self.bottom_frame.pack(side="bottom", fill="y", expand=False) self.create_components() self.start_app() except _tkinter.TclError as e: self.logger.exception(f"Failed to start tk_app : {e}") @staticmethod @abstractmethod def close_callback(): pass def create_components(self): pass def start_app(self): self.window.mainloop() def stop(self): self.window.quit()
class explorer(tk.Toplevel): def __init__(self, *args, **kwargs): tk.Toplevel.__init__(self, *args, **kwargs) self.geometry(f"{WIDTH}x{HEIGHT}") self.title("Explorer") """ Map to connect the string id's of the various nodes with layout: { {"entry" : DirEntry, "built" : False}, {"entry" : DirEntry, "built" : False}, ... } "built" indicates whether or not the node has been populated assuming it has children nodes. DirEntry is an object produced by the itterable os.scandir() It has several methods it similar to those in the module os.path such as is_file, is_dir, and stat, and the object caches these values for later calls, resulting in better performance. The root node is mapped to "" and uses an artifical DirEntry. The rest are mapped to their string id's provided at the time of the node's creation. """ self.node_map = {} self.style = Style(self) #Style treeview, not styling means #later calls to tag_configure() don't work self.style.map("Treeview", foreground=[("disabled", "white")], background=[("disabled", "black")]) #If a path was passed set the current dir to it #Otherwise set it to the user's home dir if "path" in args: self.current_dir = kwargs.pop("path") else: self.current_dir = os.path.expanduser("~") self.set_title(self.current_dir) self.file_icon = load_tk_image_from_bytes_array(file_image_bytes) self.folder_icon = load_tk_image_from_bytes_array(folder_image_bytes) self.outer_frame = LabelFrame(self) self.outer_frame.pack(fill="both", expand=1, padx=5, pady=5) #Top row, frame to add a path to enter a path and button to go to it self.path_frame = Frame(self.outer_frame) self.path_frame.pack(side="top", expand=0, fill="x") self.path_box = Entry(self.path_frame) self.path_box.pack(side="left", expand=1, fill="both", padx=5, pady=(1, 5)) self.submit_path_button = Button(self.path_frame, text="⏎", command=self.submit_path) self.submit_path_button.pack(side="right", expand=0, fill="both", padx=(0, 4), pady=(0, 4)) #Buttons have weird padding self.tree = ScrolledTree(self.outer_frame, columns=("size", "modified")) self.tree.pack(side="top", expand=1, fill="both", padx=5, pady=(0, 5)) self.tree.bind("<Double-1>", self.on_double_click) self.tree.bind("<<TreeviewOpen>>", self.on_open) self.tree.column("#0", width=150) self.tree.column("size", width=60, minwidth=60, stretch="no") self.tree.column("modified", width=150, minwidth=150, stretch="no") self.tree.heading("#0", text="...", anchor="w") self.tree.heading("size", text="Size", anchor="w") self.tree.heading("modified", text="Modified", anchor="w") self.populate(self.current_dir) def set_title(self, string): self.title(f"TK Explorer - {string}") def submit_path(self): self.populate(self.tree.selection()[0]) def on_open(self, event): #Get current node and attempt to build it #build_node will immediately return if already built self.build_node(self.tree.focus()) def populate(self, dir: os.path): self.current_dir = dir self.node_map = {} #Clear node map self.tree.delete(*self.tree.get_children()) self.set_title(self.current_dir) self.build_tree() self.outer_frame.configure( text=self.current_dir) #Set frame label text def build_tree(self): """Fills the tree with the contents of the path at self.current_dir""" #Create entry in the node map for the tree root self.node_map[""] = { "entry": DirEntry(self.current_dir), "built": False } self.build_node("") #Build tree root def build_node(self, node: id): """""" node_dict = self.node_map[node] if node_dict["built"]: return path = node_dict["entry"] self.tree.delete(*self.tree.get_children(node)) try: dir_items = os.scandir(path.path) except PermissionError: dir_items = [] files, folders_then_both = [], [] for entry in dir_items: #Sort files from folders files.append( entry) if entry.is_file() else folders_then_both.append(entry) folders_then_both.extend(files) #Sort folders-first for entry in folders_then_both: if entry.is_file(): size = _sizeof_fmt(os.path.getsize( entry.path)) #Get friendly file size modified = _get_human_mtime( entry.path) #Get human modified time else: size = "" modified = "" branch = self.tree.insert(node, "end", text=entry.name, values=(size, modified, "")) self.build_branch(branch, entry) #Flesh out the branch #Built status is set to false if it's a dir since it may have children self.node_map[branch] = {"entry": entry, "built": entry.is_file()} self.node_map[node]["built"] = True def build_branch(self, branch: id, entry: DirEntry): #Flesh out an empty branch #Adds an image to the branch based on its type (file or folder) #Also adds a + to the node if it has children if entry.is_dir(): try: self.tree.item(branch, image=self.folder_icon) if os.scandir(entry.path): #Insert a single empty node in the branch. #This is so the branch has a clickable +, #when the + is clicked build_node(branch) is called. #The empty node gets erased when build_node gets called. self.tree.insert(branch, "end", text=".", values=("", "", "")) except PermissionError: #make folder appear empty if no permission to access it print(entry.path) pass else: self.tree.item(branch, image=self.file_icon) def on_double_click(self, event): region = self.tree.identify("region", event.x, event.y) column = self.tree.identify_column(event.x) == "#0" if region == "heading" and column: # If clicking on the "..." on the top left self.populate(os.path.dirname(self.current_dir)) else: node_dict = self.node_map[self.tree.selection()[0]] if node_dict["entry"].is_dir(): self.populate(node_dict["entry"].path)
# ('!disabled', '!selected', ...) filtered out. # style.map() returns an empty list for missing options, so this # should be future-safe. return [ elm for elm in st1.map('Treeview', query_opt=option) if elm[:2] != ('!disabled', '!selected') ] root = Tk() st1 = Style() st1.theme_use('default') st1.map('Treeview', foreground=fixed_map('foreground'), background=fixed_map('background')) fact = font.Font(font="TkDefaultFont").metrics('linespace') st1.configure('font.Treeview', rowheight=fact, font=font.nametofont("TkDefaultFont")) # determine Heading font based on TkDefaultFont def_font = font.nametofont('TkDefaultFont') font_family = def_font.actual()['family'] font_size = def_font.actual()['size'] + 1 # st1.configure('font.Treeview.Heading', font='TkHeadingFont') st1.configure('font.Treeview.Heading', font=(font_family, font_size, 'bold'))
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 Sticky(Toplevel): """ Sticky note class """ def __init__(self, master, key, **kwargs): """ Create a new sticky note. master: main app key: key identifying this note in master.note_data kwargs: dictionnary of the other arguments (title, txt, category, color, tags, geometry, locked, checkboxes, images, rolled) """ Toplevel.__init__(self, master) # --- window properties self.id = key self.is_locked = not (kwargs.get("locked", False)) self.images = [] self.links = {} self.latex = {} self.nb_links = 0 self.title('mynotes%s' % key) self.attributes("-type", "splash") self.attributes("-alpha", CONFIG.getint("General", "opacity") / 100) self.focus_force() # window geometry self.update_idletasks() self.geometry(kwargs.get("geometry", '220x235')) self.save_geometry = kwargs.get("geometry", '220x235') self.update() self.rowconfigure(1, weight=1) self.minsize(10, 10) self.protocol("WM_DELETE_WINDOW", self.hide) # --- style self.style = Style(self) self.style.configure(self.id + ".TCheckbutton", selectbackground="red") self.style.map('TEntry', selectbackground=[('!focus', '#c3c3c3')]) selectbg = self.style.lookup('TEntry', 'selectbackground', ('focus', )) self.style.configure("sel.TCheckbutton", background=selectbg) self.style.map("sel.TCheckbutton", background=[("active", selectbg)]) # --- note elements # title font_title = "%s %s" % (CONFIG.get("Font", "title_family").replace( " ", "\ "), CONFIG.get("Font", "title_size")) style = CONFIG.get("Font", "title_style").split(",") if style: font_title += " " font_title += " ".join(style) self.title_var = StringVar(master=self, value=kwargs.get("title", _("Title"))) self.title_label = Label(self, textvariable=self.title_var, anchor="center", style=self.id + ".TLabel", font=font_title) self.title_entry = Entry(self, textvariable=self.title_var, exportselection=False, justify="center", font=font_title) # buttons/icons self.roll = Label(self, image="img_roll", style=self.id + ".TLabel") self.close = Label(self, image="img_close", style=self.id + ".TLabel") self.im_lock = PhotoImage(master=self, file=IM_LOCK) self.cadenas = Label(self, style=self.id + ".TLabel") # corner grip self.corner = Sizegrip(self, style=self.id + ".TSizegrip") # texte font_text = "%s %s" % (CONFIG.get("Font", "text_family").replace( " ", "\ "), CONFIG.get("Font", "text_size")) self.txt = Text(self, wrap='word', undo=True, selectforeground='white', inactiveselectbackground=selectbg, selectbackground=selectbg, tabs=(10, 'right', 21, 'left'), relief="flat", borderwidth=0, highlightthickness=0, font=font_text) # tags self.txt.tag_configure("bold", font="%s bold" % font_text) self.txt.tag_configure("italic", font="%s italic" % font_text) self.txt.tag_configure("bold-italic", font="%s bold italic" % font_text) self.txt.tag_configure("underline", underline=True, selectforeground="white") self.txt.tag_configure("overstrike", overstrike=True, selectforeground="white") self.txt.tag_configure("center", justify="center") self.txt.tag_configure("left", justify="left") self.txt.tag_configure("right", justify="right") self.txt.tag_configure("link", foreground="blue", underline=True, selectforeground="white") self.txt.tag_configure("list", lmargin1=0, lmargin2=21, tabs=(10, 'right', 21, 'left')) self.txt.tag_configure("todolist", lmargin1=0, lmargin2=21, tabs=(10, 'right', 21, 'left')) margin = 2 * Font(self, font=font_text).measure("m") self.txt.tag_configure("enum", lmargin1=0, lmargin2=margin + 5, tabs=(margin, 'right', margin + 5, 'left')) for coul in TEXT_COLORS.values(): self.txt.tag_configure(coul, foreground=coul, selectforeground="white") self.txt.tag_configure(coul + "-underline", foreground=coul, selectforeground="white", underline=True) self.txt.tag_configure(coul + "-overstrike", foreground=coul, overstrike=True, selectforeground="white") # --- menus # --- * menu on title self.menu = Menu(self, tearoff=False) # note color menu_note_color = Menu(self.menu, tearoff=False) colors = list(COLORS.keys()) colors.sort() for coul in colors: menu_note_color.add_command( label=coul, command=lambda key=coul: self.change_color(key)) # category self.category = StringVar( self, kwargs.get("category", CONFIG.get("General", "default_category"))) self.menu_categories = Menu(self.menu, tearoff=False) categories = CONFIG.options("Categories") categories.sort() for cat in categories: self.menu_categories.add_radiobutton(label=cat.capitalize(), value=cat, variable=self.category, command=self.change_category) # position: normal, always above, always below self.position = StringVar( self, kwargs.get("position", CONFIG.get("General", "position"))) menu_position = Menu(self.menu, tearoff=False) menu_position.add_radiobutton(label=_("Always above"), value="above", variable=self.position, command=self.set_position_above) menu_position.add_radiobutton(label=_("Always below"), value="below", variable=self.position, command=self.set_position_below) menu_position.add_radiobutton(label=_("Normal"), value="normal", variable=self.position, command=self.set_position_normal) # mode: note, list, todo list menu_mode = Menu(self.menu, tearoff=False) self.mode = StringVar(self, kwargs.get("mode", "note")) menu_mode.add_radiobutton(label=_("Note"), value="note", variable=self.mode, command=self.set_mode_note) menu_mode.add_radiobutton(label=_("List"), value="list", variable=self.mode, command=self.set_mode_list) menu_mode.add_radiobutton(label=_("ToDo List"), value="todolist", variable=self.mode, command=self.set_mode_todolist) menu_mode.add_radiobutton(label=_("Enumeration"), value="enum", variable=self.mode, command=self.set_mode_enum) self.menu.add_command(label=_("Delete"), command=self.delete) self.menu.add_cascade(label=_("Category"), menu=self.menu_categories) self.menu.add_cascade(label=_("Color"), menu=menu_note_color) self.menu.add_command(label=_("Lock"), command=self.lock) self.menu.add_cascade(label=_("Position"), menu=menu_position) self.menu.add_cascade(label=_("Mode"), menu=menu_mode) # --- * menu on main text self.menu_txt = Menu(self.txt, tearoff=False) # style menu_style = Menu(self.menu_txt, tearoff=False) menu_style.add_command(label=_("Bold"), command=lambda: self.toggle_text_style("bold")) menu_style.add_command( label=_("Italic"), command=lambda: self.toggle_text_style("italic")) menu_style.add_command(label=_("Underline"), command=self.toggle_underline) menu_style.add_command(label=_("Overstrike"), command=self.toggle_overstrike) # text alignment menu_align = Menu(self.menu_txt, tearoff=False) menu_align.add_command(label=_("Left"), command=lambda: self.set_align("left")) menu_align.add_command(label=_("Right"), command=lambda: self.set_align("right")) menu_align.add_command(label=_("Center"), command=lambda: self.set_align("center")) # text color menu_colors = Menu(self.menu_txt, tearoff=False) colors = list(TEXT_COLORS.keys()) colors.sort() for coul in colors: menu_colors.add_command(label=coul, command=lambda key=coul: self. change_sel_color(TEXT_COLORS[key])) # insert menu_insert = Menu(self.menu_txt, tearoff=False) menu_insert.add_command(label=_("Symbols"), command=self.add_symbols) menu_insert.add_command(label=_("Checkbox"), command=self.add_checkbox) menu_insert.add_command(label=_("Image"), command=self.add_image) menu_insert.add_command(label=_("Date"), command=self.add_date) menu_insert.add_command(label=_("Link"), command=self.add_link) if LATEX: menu_insert.add_command(label="LaTex", command=self.add_latex) self.menu_txt.add_cascade(label=_("Style"), menu=menu_style) self.menu_txt.add_cascade(label=_("Alignment"), menu=menu_align) self.menu_txt.add_cascade(label=_("Color"), menu=menu_colors) self.menu_txt.add_cascade(label=_("Insert"), menu=menu_insert) # --- restore note content/appearence self.color = kwargs.get("color", CONFIG.get("Categories", self.category.get())) self.txt.insert('1.0', kwargs.get("txt", "")) self.txt.edit_reset() # clear undo stack # restore inserted objects (images and checkboxes) # we need to restore objects with increasing index to avoid placment errors indexes = list(kwargs.get("inserted_objects", {}).keys()) indexes.sort(key=sorting) for index in indexes: kind, val = kwargs["inserted_objects"][index] if kind == "checkbox": ch = Checkbutton(self.txt, takefocus=False, style=self.id + ".TCheckbutton") if val: ch.state(("selected", )) self.txt.window_create(index, window=ch) elif kind == "image": if os.path.exists(val): self.images.append(PhotoImage(master=self.txt, file=val)) self.txt.image_create(index, image=self.images[-1], name=val) # restore tags for tag, indices in kwargs.get("tags", {}).items(): if indices: self.txt.tag_add(tag, *indices) for link in kwargs.get("links", {}).values(): self.nb_links += 1 self.links[self.nb_links] = link self.txt.tag_bind("link#%i" % self.nb_links, "<Button-1>", lambda e, l=link: open_url(l)) for img, latex in kwargs.get("latex", {}).items(): self.latex[img] = latex if LATEX: self.txt.tag_bind(img, '<Double-Button-1>', lambda e, im=img: self.add_latex(im)) mode = self.mode.get() if mode != "note": self.txt.tag_add(mode, "1.0", "end") self.txt.focus_set() self.lock() if kwargs.get("rolled", False): self.rollnote() if self.position.get() == "above": self.set_position_above() elif self.position.get() == "below": self.set_position_below() # --- placement # titlebar if CONFIG.get("General", "buttons_position") == "right": # right = lock icon - title - roll - close self.columnconfigure(1, weight=1) self.roll.grid(row=0, column=2, sticky="e") self.close.grid(row=0, column=3, sticky="e", padx=(0, 2)) self.cadenas.grid(row=0, column=0, sticky="w") self.title_label.grid(row=0, column=1, sticky="ew", pady=(1, 0)) else: # left = close - roll - title - lock icon self.columnconfigure(2, weight=1) self.roll.grid(row=0, column=1, sticky="w") self.close.grid(row=0, column=0, sticky="w", padx=(2, 0)) self.cadenas.grid(row=0, column=3, sticky="e") self.title_label.grid(row=0, column=2, sticky="ew", pady=(1, 0)) # body self.txt.grid(row=1, columnspan=4, column=0, sticky="ewsn", pady=(1, 4), padx=4) self.corner.lift(self.txt) self.corner.place(relx=1.0, rely=1.0, anchor="se") # --- bindings self.bind("<FocusOut>", self.save_note) self.bind('<Configure>', self.bouge) self.bind('<Button-1>', self.change_focus, True) self.close.bind("<Button-1>", self.hide) self.close.bind("<Enter>", self.enter_close) self.close.bind("<Leave>", self.leave_close) self.roll.bind("<Button-1>", self.rollnote) self.roll.bind("<Enter>", self.enter_roll) self.roll.bind("<Leave >", self.leave_roll) self.title_label.bind("<Double-Button-1>", self.edit_title) self.title_label.bind("<ButtonPress-1>", self.start_move) self.title_label.bind("<ButtonRelease-1>", self.stop_move) self.title_label.bind("<B1-Motion>", self.move) self.title_label.bind('<Button-3>', self.show_menu) self.title_entry.bind("<Return>", lambda e: self.title_entry.place_forget()) self.title_entry.bind("<FocusOut>", lambda e: self.title_entry.place_forget()) self.title_entry.bind("<Escape>", lambda e: self.title_entry.place_forget()) self.txt.tag_bind("link", "<Enter>", lambda event: self.txt.configure(cursor="hand1")) self.txt.tag_bind("link", "<Leave>", lambda event: self.txt.configure(cursor="")) self.txt.bind("<FocusOut>", self.save_note) self.txt.bind('<Button-3>', self.show_menu_txt) # add binding to the existing class binding so that the selected text # is erased on pasting self.txt.bind("<Control-v>", self.paste) self.corner.bind('<ButtonRelease-1>', self.resize) # --- keyboard shortcuts self.txt.bind('<Control-b>', lambda e: self.toggle_text_style('bold')) self.txt.bind('<Control-i>', lambda e: self.toggle_text_style('italic')) self.txt.bind('<Control-u>', lambda e: self.toggle_underline()) self.txt.bind('<Control-r>', lambda e: self.set_align('right')) self.txt.bind('<Control-l>', lambda e: self.set_align('left')) def __setattr__(self, name, value): object.__setattr__(self, name, value) if name == "color": self.style.configure(self.id + ".TSizegrip", background=self.color) self.style.configure(self.id + ".TLabel", background=self.color) self.style.configure("close" + self.id + ".TLabel", background=self.color) self.style.configure("roll" + self.id + ".TLabel", background=self.color) self.style.map(self.id + ".TLabel", background=[("active", self.color)]) self.style.configure(self.id + ".TCheckbutton", background=self.color) self.style.map(self.id + ".TCheckbutton", background=[("active", self.color), ("disabled", self.color)]) self.style.map("close" + self.id + ".TLabel", background=[("active", self.color)]) self.style.map("roll" + self.id + ".TLabel", background=[("active", self.color)]) self.configure(bg=self.color) self.txt.configure(bg=self.color) def paste(self, event): """ delete selected text before pasting """ if self.txt.tag_ranges("sel"): self.txt.delete("sel.first", "sel.last") def delete(self, confirmation=True): """ Delete this note """ if confirmation: rep = askokcancel(_("Confirmation"), _("Delete the note?")) else: rep = True if rep: del (self.master.note_data[self.id]) del (self.master.notes[self.id]) self.master.save() self.destroy() def lock(self): """ Put note in read-only mode to avoid unwanted text insertion """ if self.is_locked: selectbg = self.style.lookup('TEntry', 'selectbackground', ('focus', )) self.txt.configure(state="normal", selectforeground='white', selectbackground=selectbg, inactiveselectbackground=selectbg) self.style.configure("sel.TCheckbutton", background=selectbg) self.style.map("sel.TCheckbutton", background=[("active", selectbg)]) self.is_locked = False for checkbox in self.txt.window_names(): ch = self.txt.children[checkbox.split(".")[-1]] ch.configure(state="normal") self.cadenas.configure(image="") self.menu.entryconfigure(3, label=_("Lock")) self.title_label.bind("<Double-Button-1>", self.edit_title) self.txt.bind('<Button-3>', self.show_menu_txt) else: self.txt.configure(state="disabled", selectforeground='black', inactiveselectbackground='#c3c3c3', selectbackground='#c3c3c3') self.style.configure("sel.TCheckbutton", background='#c3c3c3') self.style.map("sel.TCheckbutton", background=[("active", '#c3c3c3')]) self.cadenas.configure(image=self.im_lock) for checkbox in self.txt.window_names(): ch = self.txt.children[checkbox.split(".")[-1]] ch.configure(state="disabled") self.is_locked = True self.menu.entryconfigure(3, label=_("Unlock")) self.title_label.unbind("<Double-Button-1>") self.txt.unbind('<Button-3>') self.save_note() def save_info(self): """ Return the dictionnary containing all the note data """ data = {} data["txt"] = self.txt.get("1.0", "end")[:-1] data["tags"] = {} for tag in self.txt.tag_names(): if tag not in ["sel", "todolist", "list", "enum"]: data["tags"][tag] = [ index.string for index in self.txt.tag_ranges(tag) ] data["title"] = self.title_var.get() data["geometry"] = self.save_geometry data["category"] = self.category.get() data["color"] = self.color data["locked"] = self.is_locked data["mode"] = self.mode.get() data["inserted_objects"] = {} data["rolled"] = not self.txt.winfo_ismapped() data["position"] = self.position.get() data["links"] = {} for i, link in self.links.items(): if self.txt.tag_ranges("link#%i" % i): data["links"][i] = link data["latex"] = {} for img, latex in self.latex.items(): if self.txt.tag_ranges(img): data["latex"][img] = latex for image in self.txt.image_names(): data["inserted_objects"][self.txt.index(image)] = ( "image", image.split('#')[0]) for checkbox in self.txt.window_names(): ch = self.txt.children[checkbox.split(".")[-1]] data["inserted_objects"][self.txt.index(checkbox)] = ( "checkbox", "selected" in ch.state()) return data def change_color(self, key): self.color = COLORS[key] self.save_note() def change_category(self, category=None): if category: self.category.set(category) self.color = CONFIG.get("Categories", self.category.get()) self.save_note() def set_position_above(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 1, '_NET_WM_STATE_ABOVE') e.setWmState(w, 0, '_NET_WM_STATE_BELOW') e.display.flush() self.save_note() def set_position_below(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 0, '_NET_WM_STATE_ABOVE') e.setWmState(w, 1, '_NET_WM_STATE_BELOW') e.display.flush() self.save_note() def set_position_normal(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 0, '_NET_WM_STATE_BELOW') e.setWmState(w, 0, '_NET_WM_STATE_ABOVE') e.display.flush() self.save_note() def set_mode_note(self): self.txt.tag_remove("list", "1.0", "end") self.txt.tag_remove("todolist", "1.0", "end") self.txt.tag_remove("enum", "1.0", "end") self.save_note() def set_mode_list(self): end = int(self.txt.index("end").split(".")[0]) lines = self.txt.get("1.0", "end").splitlines() for i, l in zip(range(1, end), lines): # remove checkboxes try: ch = self.txt.window_cget("%i.0" % i, "window") self.txt.children[ch.split('.')[-1]].destroy() self.txt.delete("%i.0" % i) except TclError: # there is no checkbox # remove enumeration res = re.match('^\t[0-9]+\.\t', l) if res: self.txt.delete("%i.0" % i, "%i.%i" % (i, res.end())) if self.txt.get("%i.0" % i, "%i.3" % i) != "\t•\t": self.txt.insert("%i.0" % i, "\t•\t") self.txt.tag_add("list", "1.0", "end") self.txt.tag_remove("todolist", "1.0", "end") self.txt.tag_remove("enum", "1.0", "end") self.save_note() def set_mode_enum(self): self.txt.configure(autoseparators=False) self.txt.edit_separator() end = int(self.txt.index("end").split(".")[0]) lines = self.txt.get("1.0", "end").splitlines() for i, l in zip(range(1, end), lines): # remove checkboxes try: ch = self.txt.window_cget("%i.0" % i, "window") self.txt.children[ch.split('.')[-1]].destroy() self.txt.delete("%i.0" % i) except TclError: # there is no checkbox # remove bullets if self.txt.get("%i.0" % i, "%i.3" % i) == "\t•\t": self.txt.delete("%i.0" % i, "%i.3" % i) if not re.match('^\t[0-9]+\.', l): self.txt.insert("%i.0" % i, "\t0.\t") self.txt.tag_add("enum", "1.0", "end") self.txt.tag_remove("todolist", "1.0", "end") self.txt.tag_remove("list", "1.0", "end") self.update_enum() self.txt.configure(autoseparators=True) self.txt.edit_separator() self.save_note() def set_mode_todolist(self): end = int(self.txt.index("end").split(".")[0]) lines = self.txt.get("1.0", "end").splitlines() for i, l in zip(range(1, end), lines): res = re.match('^\t[0-9]+\.\t', l) if res: self.txt.delete("%i.0" % i, "%i.%i" % (i, res.end())) elif self.txt.get("%i.0" % i, "%i.3" % i) == "\t•\t": self.txt.delete("%i.0" % i, "%i.3" % i) try: ch = self.txt.window_cget("%i.0" % i, "window") except TclError: ch = Checkbutton(self.txt, takefocus=False, style=self.id + ".TCheckbutton") self.txt.window_create("%i.0" % i, window=ch) self.txt.tag_remove("enum", "1.0", "end") self.txt.tag_remove("list", "1.0", "end") self.txt.tag_add("todolist", "1.0", "end") self.save_note() # --- bindings def enter_roll(self, event): """ mouse is over the roll icon """ self.roll.configure(image="img_rollactive") def leave_roll(self, event): """ mouse leaves the roll icon """ self.roll.configure(image="img_roll") def enter_close(self, event): """ mouse is over the close icon """ self.close.configure(image="img_closeactive") def leave_close(self, event): """ mouse leaves the close icon """ self.close.configure(image="img_close") def change_focus(self, event): if not self.is_locked: event.widget.focus_force() def show_menu(self, event): self.menu.tk_popup(event.x_root, event.y_root) def show_menu_txt(self, event): self.menu_txt.tk_popup(event.x_root, event.y_root) def resize(self, event): self.save_geometry = self.geometry() def bouge(self, event): geo = self.geometry().split("+")[1:] self.save_geometry = self.save_geometry.split("+")[0] \ + "+%s+%s" % tuple(geo) def edit_title(self, event): self.title_entry.place(x=self.title_label.winfo_x() + 5, y=self.title_label.winfo_y(), anchor="nw", width=self.title_label.winfo_width() - 10) def start_move(self, event): self.x = event.x self.y = event.y self.configure(cursor='fleur') def stop_move(self, event): self.x = None self.y = None self.configure(cursor='') def move(self, event): if self.x is not None and self.y is not None: deltax = event.x - self.x deltay = event.y - self.y x = self.winfo_x() + deltax y = self.winfo_y() + deltay self.geometry("+%s+%s" % (x, y)) def save_note(self, event=None): data = self.save_info() data["visible"] = True self.master.note_data[self.id] = data self.master.save() def rollnote(self, event=None): if self.txt.winfo_ismapped(): self.txt.grid_forget() self.corner.place_forget() self.geometry("%sx22" % self.winfo_width()) else: self.txt.grid(row=1, columnspan=4, column=0, sticky="ewsn", pady=(1, 4), padx=4) self.corner.place(relx=1.0, rely=1.0, anchor="se") self.geometry(self.save_geometry) self.save_note() def hide(self, event=None): """ Hide note (can be displayed again via app menu) """ cat = self.category.get() self.master.add_note_to_menu(self.id, self.title_var.get().strip(), cat) data = self.save_info() data["visible"] = False self.master.note_data[self.id] = data del (self.master.notes[self.id]) self.master.save() self.destroy() # --- Settings update def update_title_font(self): font = "%s %s" % (CONFIG.get("Font", "title_family").replace( " ", "\ "), CONFIG.get("Font", "title_size")) style = CONFIG.get("Font", "title_style").split(",") if style: font += " " font += " ".join(style) self.title_label.configure(font=font) def update_text_font(self): font = "%s %s" % (CONFIG.get("Font", "text_family").replace( " ", "\ "), CONFIG.get("Font", "text_size")) self.txt.configure(font=font) self.txt.tag_configure("bold", font="%s bold" % font) self.txt.tag_configure("italic", font="%s italic" % font) self.txt.tag_configure("bold-italic", font="%s bold italic" % font) margin = 2 * Font(self, font=font).measure("m") self.txt.tag_configure("enum", lmargin1=0, lmargin2=margin + 5, tabs=(margin, 'right', margin + 5, 'left')) def update_menu_cat(self, categories): """ Update the category submenu """ self.menu_categories.delete(0, "end") for cat in categories: self.menu_categories.add_radiobutton(label=cat.capitalize(), value=cat, variable=self.category, command=self.change_category) def update_titlebar(self): if CONFIG.get("General", "buttons_position") == "right": # right = lock icon - title - roll - close self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=0) self.roll.grid_configure(row=0, column=2, sticky="e") self.close.grid_configure(row=0, column=3, sticky="e", padx=(0, 2)) self.cadenas.grid_configure(row=0, column=0, sticky="w") self.title_label.grid_configure(row=0, column=1, sticky="ew", pady=(1, 0)) else: # left = close - roll - title - lock icon self.columnconfigure(2, weight=1) self.columnconfigure(1, weight=0) self.roll.grid_configure(row=0, column=1, sticky="w") self.close.grid_configure(row=0, column=0, sticky="w", padx=(2, 0)) self.cadenas.grid_configure(row=0, column=3, sticky="e") self.title_label.grid_configure(row=0, column=2, sticky="ew", pady=(1, 0)) # --- Text edition def add_link(self): def ok(eveny=None): lien = link.get() txt = text.get() if lien: if not txt: txt = lien self.nb_links += 1 if self.txt.tag_ranges("sel"): index = self.txt.index("sel.first") self.txt.delete('sel.first', 'sel.last') else: index = "current" tags = self.txt.tag_names(index) + ("link", "link#%i" % self.nb_links) self.txt.insert("current", txt, tags) if not lien[:4] == "http": lien = "http://" + lien self.links[self.nb_links] = lien self.txt.tag_bind("link#%i" % self.nb_links, "<Button-1>", lambda e: open_url(lien)) top.destroy() top = Toplevel(self) top.transient(self) top.update_idletasks() top.geometry("+%i+%i" % top.winfo_pointerxy()) top.grab_set() top.resizable(True, False) top.title(_("Link")) top.columnconfigure(1, weight=1) text = Entry(top) link = Entry(top) if self.txt.tag_ranges('sel'): txt = self.txt.get('sel.first', 'sel.last') else: txt = '' text.insert(0, txt) text.icursor("end") Label(top, text=_("Text")).grid(row=0, column=0, sticky="e", padx=4, pady=4) Label(top, text=_("Link")).grid(row=1, column=0, sticky="e", padx=4, pady=4) text.grid(row=0, column=1, sticky="ew", padx=4, pady=4) link.grid(row=1, column=1, sticky="ew", padx=4, pady=4) Button(top, text="Ok", command=ok).grid(row=2, columnspan=2, padx=4, pady=4) text.focus_set() text.bind("<Return>", ok) link.bind("<Return>", ok) def add_checkbox(self): ch = Checkbutton(self.txt, takefocus=False, style=self.id + ".TCheckbutton") self.txt.window_create("current", window=ch) def add_date(self): self.txt.insert("current", strftime("%x")) def add_latex(self, img_name=None): def ok(event): latex = r'%s' % text.get() if latex: if img_name is None: l = [ int(os.path.splitext(f)[0]) for f in os.listdir(PATH_LATEX) ] l.sort() if l: i = l[-1] + 1 else: i = 0 img = "%i.png" % i self.txt.tag_bind(img, '<Double-Button-1>', lambda e: self.add_latex(img)) self.latex[img] = latex else: img = img_name im = os.path.join(PATH_LATEX, img) try: math_to_image(latex, im, fontsize=CONFIG.getint("Font", "text_size") - 2) self.images.append(PhotoImage(file=im, master=self)) if self.txt.tag_ranges("sel"): index = self.txt.index("sel.first") self.txt.delete('sel.first', 'sel.last') else: index = self.txt.index("current") self.txt.image_create(index, image=self.images[-1], name=im) self.txt.tag_add(img, index) top.destroy() except Exception as e: showerror(_("Error"), str(e)) top = Toplevel(self) top.transient(self) top.update_idletasks() top.geometry("+%i+%i" % top.winfo_pointerxy()) top.grab_set() top.resizable(True, False) top.title("LaTex") text = Entry(top, justify='center') if img_name is not None: text.insert(0, self.latex[img_name]) else: if self.txt.tag_ranges('sel'): text.insert(0, self.txt.get('sel.first', 'sel.last')) else: text.insert(0, '$$') text.icursor(1) text.pack(fill='x', expand=True) text.bind('<Return>', ok) text.focus_set() def add_image(self): fichier = askopenfilename(defaultextension=".png", filetypes=[("PNG", "*.png")], initialdir="", initialfile="", title=_('Select PNG image')) if os.path.exists(fichier): self.images.append(PhotoImage(master=self.txt, file=fichier)) self.txt.image_create("current", image=self.images[-1], name=fichier) elif fichier: showerror("Erreur", "L'image %s n'existe pas" % fichier) def add_symbols(self): symbols = pick_symbol( self, CONFIG.get("Font", "text_family").replace(" ", "\ "), CONFIG.get("General", "symbols")) self.txt.insert("current", symbols) def toggle_text_style(self, style): '''Toggle the style of the selected text''' if self.txt.tag_ranges("sel"): current_tags = self.txt.tag_names("sel.first") if style in current_tags: # first char is in style so 'unstyle' the range self.txt.tag_remove(style, "sel.first", "sel.last") elif style == "bold" and "bold-italic" in current_tags: self.txt.tag_remove("bold-italic", "sel.first", "sel.last") self.txt.tag_add("italic", "sel.first", "sel.last") elif style == "italic" and "bold-italic" in current_tags: self.txt.tag_remove("bold-italic", "sel.first", "sel.last") self.txt.tag_add("bold", "sel.first", "sel.last") elif style == "bold" and "italic" in current_tags: self.txt.tag_remove("italic", "sel.first", "sel.last") self.txt.tag_add("bold-italic", "sel.first", "sel.last") elif style == "italic" and "bold" in current_tags: self.txt.tag_remove("bold", "sel.first", "sel.last") self.txt.tag_add("bold-italic", "sel.first", "sel.last") else: # first char is normal, so apply style to the whole selection self.txt.tag_add(style, "sel.first", "sel.last") def toggle_underline(self): if self.txt.tag_ranges("sel"): current_tags = self.txt.tag_names("sel.first") if "underline" in current_tags: # first char is in style so 'unstyle' the range self.txt.tag_remove("underline", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): self.txt.tag_remove(coul + "-underline", "sel.first", "sel.last") else: self.txt.tag_add("underline", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): r = text_ranges(self.txt, coul, "sel.first", "sel.last") if r: for deb, fin in zip(r[::2], r[1::2]): self.txt.tag_add(coul + "-underline", "sel.first", "sel.last") def toggle_overstrike(self): if self.txt.tag_ranges("sel"): current_tags = self.txt.tag_names("sel.first") if "overstrike" in current_tags: # first char is in style so 'unstyle' the range self.txt.tag_remove("overstrike", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): self.txt.tag_remove(coul + "-overstrike", "sel.first", "sel.last") else: self.txt.tag_add("overstrike", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): r = text_ranges(self.txt, coul, "sel.first", "sel.last") if r: for deb, fin in zip(r[::2], r[1::2]): self.txt.tag_add(coul + "-overstrike", "sel.first", "sel.last") def change_sel_color(self, color): """ change the color of the selection """ if self.txt.tag_ranges("sel"): for coul in TEXT_COLORS.values(): self.txt.tag_remove(coul, "sel.first", "sel.last") self.txt.tag_remove(coul + "-overstrike", "sel.first", "sel.last") self.txt.tag_remove(coul + "-underline", "sel.first", "sel.last") if not color == "black": self.txt.tag_add(color, "sel.first", "sel.last") underline = text_ranges(self.txt, "underline", "sel.first", "sel.last") overstrike = text_ranges(self.txt, "overstrike", "sel.first", "sel.last") for deb, fin in zip(underline[::2], underline[1::2]): self.txt.tag_add(color + "-underline", deb, fin) for deb, fin in zip(overstrike[::2], overstrike[1::2]): self.txt.tag_add(color + "-overstrike", deb, fin) def set_align(self, alignment): """ Align the text according to alignment (left, right, center) """ if self.txt.tag_ranges("sel"): line = self.txt.index("sel.first").split(".")[0] line2 = self.txt.index("sel.last").split(".")[0] deb, fin = line + ".0", line2 + ".end" if not "\t" in self.txt.get(deb, fin): # tabulations don't support right/center alignment # remove old alignment tag self.txt.tag_remove("left", deb, fin) self.txt.tag_remove("right", deb, fin) self.txt.tag_remove("center", deb, fin) # set new alignment tag self.txt.tag_add(alignment, deb, fin) def update_enum(self): """ update enumeration numbers """ lines = self.txt.get("1.0", "end").splitlines() indexes = [] for i, l in enumerate(lines): res = re.match('^\t[0-9]+\.\t', l) res2 = re.match('^\t[0-9]+\.', l) if res: indexes.append((i, res.end())) elif res2: indexes.append((i, res2.end())) for j, (i, end) in enumerate(indexes): self.txt.delete("%i.0" % (i + 1), "%i.%i" % (i + 1, end)) self.txt.insert("%i.0" % (i + 1), "\t%i.\t" % (j + 1)) self.txt.tag_add("enum", "1.0", "end")
def __init__(self, master): """Create Config dialog.""" Toplevel.__init__(self, master, class_='MyNotes') self.title(_("Preferences")) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.quit) self.changes = {}, {}, False, False self.minsize(width=430, height=450) # --- style style = Style(self) style.theme_use("clam") style.configure("TScale", sliderlength=20) style.map("TCombobox", fieldbackground=[('readonly', 'white')], selectbackground=[('readonly', 'white')], selectforeground=[('readonly', 'black')]) style.configure("prev.TLabel", background="white") style.map("prev.TLabel", background=[("active", "white")]) color = CONFIG.get("Categories", CONFIG.get("General", "default_category")) style.configure("titlebar.TFrame", background=color) style.configure("titlebar.TLabel", background=color) style.configure("text.TFrame", background="white") # --- body self.notebook = Notebook(self) okcancel_frame = Frame(self) okcancel_frame.columnconfigure(0, weight=1) okcancel_frame.columnconfigure(1, weight=1) okcancel_frame.pack(fill="x", side='bottom') self.notebook.pack(expand=True, fill="both") # --- * General settings self._init_general() # --- * Font settings self._init_font() # --- * Categories self.category_settings = CategoryManager(self.notebook, master) self.notebook.add(self.category_settings, text=_("Categories"), sticky="ewsn", padding=4) # --- * Symbols size = CONFIG.get("Font", "text_size") family = CONFIG.get("Font", "text_family") symbols_settings = Frame(self.notebook, padding=4) self.notebook.add(symbols_settings, text=_("Symbols"), sticky="ewsn", padding=4) txt_frame = Frame(symbols_settings, relief="sunken", borderwidth=1, style="text.TFrame") txt_frame.rowconfigure(0, weight=1) txt_frame.columnconfigure(0, weight=1) self.symbols = Text(txt_frame, width=1, height=1, highlightthickness=0, spacing2=5, spacing1=5, relief="flat", padx=4, pady=4, font="%s %s" % (family.replace(" ", "\ "), size)) scroll_y = AutoScrollbar(txt_frame, orient='vertical', command=self.symbols.yview) self.symbols.configure(yscrollcommand=scroll_y.set) self.symbols.insert("1.0", CONFIG.get("General", "symbols")) Label(symbols_settings, text=_("Available symbols")).pack(padx=4, pady=4) txt_frame.pack(fill="both", expand=True, padx=4, pady=4) self.symbols.grid(sticky='ewns') scroll_y.grid(row=0, column=1, sticky='ns') Button(symbols_settings, text=_('Reset'), command=self.reset_symbols).pack(padx=4, pady=4) # --- * AutoCorrect self.autocorrect_settings = AutoCorrectConfig(self.notebook, master) self.notebook.add(self.autocorrect_settings, text=_("AutoCorrect"), sticky="ewsn", padding=4) # --- Ok/Cancel buttons Button(okcancel_frame, text="Ok", command=self.ok).grid(row=1, column=0, padx=4, pady=10, sticky="e") Button(okcancel_frame, text=_("Cancel"), command=self.destroy).grid(row=1, column=1, padx=4, pady=10, sticky="w")
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)
""" from tkinter import Tk, Frame, StringVar, font, Label from tkinter.ttk import Notebook, Button, Style import sys sys.path.insert(1, '../treeview/') from tree_function import Tree root = Tk() st1 = Style() st1.theme_use('default') st1.configure( 'green.TNotebook.Tab', background='light green', foreground='blue') st1.map('green.TNotebook.Tab', background=[ ('disabled', '#d9d9d9'), ('selected', '#bceebc')]) test_size = font.Font(family="Times", size=12, weight="bold").measure('Test') mult = int(test_size / 30) def tab_changed(event): """notebook handler changes width and height after a tab is selected Parameters ---------- event : str bind event """ event.widget.update_idletasks() tc1 = event.widget.nametowidget(event.widget.select()) event.widget.configure(
class MainFrame(Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.parent.title("InstaDjango") self.pack(fill=BOTH, expand=1) self.size_and_center_window() self.style = Style() self.style.theme_use("clam") self.style.configure("TFrame", background="#808080", foreground="white") self.style.configure("TButton", background="#808080", foreground="white") self.style.configure("high.TButton", background="#8FBC8B", foreground="white") self.style.configure("TLabel", background="#808080", foreground="white") self.style.map("TButton", background=[("pressed", "#404040"), ("active", "#A0A0A0")]) frame = Frame(self, relief=FLAT, borderwidth=1) frame.pack(fill=BOTH, expand=1) subframe_0 = Frame(frame, relief=FLAT, borderwidth=0) subframe_0.pack(fill=X) lbl_0 = Label( subframe_0, text= "App's machine-readable name (used for naming folders locally and remotely):", style="TLabel") lbl_0.pack(fill=BOTH, padx=10, pady=10) entry_0 = Entry(subframe_0) entry_0.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_0, "") subframe_1 = Frame(frame, relief=FLAT, borderwidth=0) subframe_1.pack(fill=X) lbl_1 = Label(subframe_1, text="Where to create the app's folder locally:", style="TLabel") lbl_1.pack(fill=BOTH, padx=10, pady=10) entry_1 = Entry(subframe_1) def action_1(): cdir = filedialog.askdirectory(title="Please select a directory") if cdir: self.set_entry_text(entry_1, cdir) button_1 = Button(subframe_1, text="Choose", command=action_1, style="TButton") button_1.pack(side=RIGHT, padx=10, pady=0) entry_1.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_1, "") subframe_2 = Frame(frame, relief=FLAT, borderwidth=0) subframe_2.pack(fill=X) lbl_2 = Label(subframe_2, text="Remote host:", style="TLabel") lbl_2.pack(fill=BOTH, padx=10, pady=10) entry_2 = Entry(subframe_2) entry_2.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_2, "") subframe_3 = Frame(frame, relief=FLAT, borderwidth=0) subframe_3.pack(fill=X) lbl_3 = Label( subframe_3, text="Remote SSH port (empty will mean the default port):", style="TLabel") lbl_3.pack(fill=BOTH, padx=10, pady=10) entry_3 = Entry(subframe_3) entry_3.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_3, "") subframe_4 = Frame(frame, relief=FLAT, borderwidth=0) subframe_4.pack(fill=X) lbl_4 = Label(subframe_4, text="Remote user:"******"TLabel") lbl_4.pack(fill=BOTH, padx=10, pady=10) entry_4 = Entry(subframe_4) entry_4.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_4, "") subframe_5 = Frame(frame, relief=FLAT, borderwidth=0) subframe_5.pack(fill=X) lbl_5 = Label(subframe_5, text="Local path to the SSH private key:", style="TLabel") lbl_5.pack(fill=BOTH, padx=10, pady=10) entry_5 = Entry(subframe_5) def action_5(): cdir = filedialog.askopenfilename( title="Please select a private key") if cdir: self.set_entry_text(entry_5, cdir) button_5 = Button(subframe_5, text="Choose", command=action_5, style="TButton") button_5.pack(side=RIGHT, padx=10, pady=0) entry_5.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_5, "") subframe_6 = Frame(frame, relief=FLAT, borderwidth=0) subframe_6.pack(fill=X) lbl_6 = Label( subframe_6, text= "Where to create the app's folder remotely (should not be owned by root):", style="TLabel") lbl_6.pack(fill=BOTH, padx=10, pady=10) entry_6 = Entry(subframe_6) entry_6.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_6, "/var/www") subframe_7 = Frame(frame, relief=FLAT, borderwidth=0) subframe_7.pack(fill=X) lbl_7 = Label(subframe_7, text="Sudo password:"******"TLabel") lbl_7.pack(fill=BOTH, padx=10, pady=10) entry_7 = Entry(subframe_7, show="*") entry_7.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_7, "") subframe_8 = Frame(frame, relief=FLAT, borderwidth=0) subframe_8.pack(fill=X) lbl_8 = Label(subframe_8, text="Database password:"******"TLabel") lbl_8.pack(fill=BOTH, padx=10, pady=10) entry_8 = Entry(subframe_8, show="*") entry_8.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_8, "") subframe_9 = Frame(frame, relief=FLAT, borderwidth=0) subframe_9.pack(fill=X) lbl_9 = Label(subframe_9, text="Domain:", style="TLabel") lbl_9.pack(fill=BOTH, padx=10, pady=10) entry_9 = Entry(subframe_9) entry_9.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_9, "dev.example.com") subframe_10 = Frame(frame, relief=FLAT, borderwidth=0) subframe_10.pack(fill=X) lbl_10 = Label( subframe_10, text="Django installation type (local, production, staging):", style="TLabel") lbl_10.pack(fill=BOTH, padx=10, pady=10) entry_10 = Entry(subframe_10) entry_10.pack(fill=X, padx=10, ipady=5) self.set_entry_text(entry_10, "local") def go(): setup_django_project(proj=entry_0.get(), proj_local_parent_dir=entry_1.get(), host=entry_2.get(), port=entry_3.get(), user=entry_4.get(), ssh_key=entry_5.get(), proj_remote_parent_dir=entry_6.get(), sudo_pass=entry_7.get(), db_pass=entry_8.get(), domain=entry_9.get(), insta_type=entry_10.get()) self.quit() inst_button = Button(self, text="Go", command=go, style="high.TButton") inst_button.pack(side=RIGHT, padx=10, pady=10) quit_button = Button(self, text="Quit", command=self.quit, style="TButton") quit_button.pack(side=RIGHT, pady=10) def size_and_center_window(self): w = 640 h = 850 sw = self.parent.winfo_screenwidth() sh = self.parent.winfo_screenheight() x = (sw - w) / 2 y = (sh - h) / 2 self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y)) @staticmethod def set_entry_text(e, text): e.delete(0, END) e.insert(0, text)
def __init__(self, master): Toplevel.__init__(self, master, class_="CheckMails") self.title(_("Preferences")) style = Style(self) style.map("TCombobox", fieldbackground=[('readonly', 'white')], selectbackground=[('readonly', 'white')], selectforeground=[('readonly', 'black')], foreground=[('readonly', 'black')]) # validation of the entries : only numbers are allowed self._validate_entry_nb = self.register(self.validate_entry_nb) # --- Times Label(self, text=_("Time between two checks")).grid(row=0, column=0, padx=(10, 4), pady=(10, 4), sticky="e") Label(self, justify="right", text=_("Maximum time allowed for login or check\n\ (then the connection is reset)")).grid(row=1, column=0, padx=(10, 4), pady=4, sticky="e") self.time_entry = Entry(self, width=5, justify="center", validate="key", validatecommand=(self._validate_entry_nb, "%P")) self.time_entry.grid(row=0, column=1, padx=(4, 0), pady=(10, 4)) self.time_entry.insert(0, "%g" % (CONFIG.getint("General", "time") / 60000)) self.timeout_entry = Entry(self, width=5, justify="center", validate="key", validatecommand=(self._validate_entry_nb, "%P")) self.timeout_entry.grid(row=1, column=1, padx=(4, 0), pady=4) self.timeout_entry.insert(0, "%g" % (CONFIG.getint("General", "timeout") / 60000)) Label(self, text="min").grid(row=0, column=2, padx=(0, 10), pady=(10, 4)) Label(self, text="min").grid(row=1, column=2, padx=(0, 10), pady=4) frame = Frame(self) frame.grid(row=2, columnspan=3, padx=6, pady=(0, 6)) # --- Language Label(frame, text=_("Language")).grid(row=0, column=0, padx=8, pady=4, sticky="e") lang = {"fr": "Français", "en": "English"} self.lang = StringVar(self, lang[CONFIG.get("General", "language")]) menu_lang = Menu(frame, tearoff=False) Menubutton(frame, menu=menu_lang, width=9, textvariable=self.lang).grid(row=0, column=1, padx=8, pady=4, sticky="w") menu_lang.add_radiobutton(label="English", value="English", variable=self.lang, command=self.translate) menu_lang.add_radiobutton(label="Français", value="Français", variable=self.lang, command=self.translate) # --- gui toolkit Label(frame, text=_("GUI Toolkit for the system tray icon")).grid(row=1, column=0, padx=8, pady=4, sticky="e") self.gui = StringVar(self, CONFIG.get("General", "trayicon").capitalize()) menu_gui = Menu(frame, tearoff=False) Menubutton(frame, menu=menu_gui, width=9, textvariable=self.gui).grid(row=1, column=1, padx=8, pady=4, sticky="w") for toolkit, b in TOOLKITS.items(): if b: menu_gui.add_radiobutton(label=toolkit.capitalize(), value=toolkit.capitalize(), variable=self.gui, command=self.change_gui) # --- Font self.preview_path = tempfile.mktemp(".png", "checkmails_preview") w = max([len(f) for f in TTF_FONTS]) self.fonts = sorted(TTF_FONTS) self.font = Combobox(frame, values=self.fonts, width=(w * 2) // 3, exportselection=False, state="readonly") current_font = CONFIG.get("General", "font") if current_font in self.fonts: i = self.fonts.index(current_font) else: i = 0 self.font.current(i) self.img_prev = PhotoImage(master=self, file=IMAGE) Label(frame, text=_("Font")).grid(row=2, column=0, padx=8, pady=4, sticky="e") self.font.grid(row=2, column=1, padx=8, pady=4, sticky="w") self.prev = Label(frame, image=self.img_prev) self.prev.grid(row=2, column=2, padx=8, pady=4) self.update_preview() self.font.bind('<<ComboboxSelected>>', self.update_preview) self.font.bind_class("ComboboxListbox", '<KeyPress>', self.key_nav) # --- Ok/Cancel frame_button = Frame(self) frame_button.grid(row=3, columnspan=3, padx=6, pady=(0, 6)) Button(frame_button, text="Ok", command=self.ok).grid(row=2, column=0, padx=8, pady=4) Button(frame_button, text=_("Cancel"), command=self.destroy).grid(row=2, column=1, padx=4, pady=4)
hashtags = f.readlines() ## GUI Tkinter _bgcolor = '#d9d9d9' # X11 color: 'gray85' _fgcolor = '#000000' # X11 color: 'black' _compcolor = '#d9d9d9' # X11 color: 'gray85' _ana1color = '#d9d9d9' # X11 color: 'gray85' _ana2color = '#d9d9d9' # X11 color: 'gray85' styl = Style() styl.theme_use('clam') styl.configure('.', background=_bgcolor) styl.configure('.', foreground=_fgcolor) styl.configure('.', sliderthickness='20') styl.configure('.', font="TkDefaultFont") styl.map('.', background=[('selected', _compcolor), ('active', _ana2color)]) Frame1 = Frame(root) Frame1.place(relx=0.02, rely=0.02, relheight=0.27, relwidth=0.46) Frame1.configure(relief=GROOVE) Frame1.configure(borderwidth="2") Frame1.configure(relief=GROOVE) Frame1.configure(width=285) Checkbutton1 = Checkbutton(Frame1) Checkbutton1.place(relx=0.07, rely=0.43, relheight=0.22, relwidth=0.34) Checkbutton1.configure(text='''Profile photo''') Checkbutton1.configure(variable=check1) Checkbutton3 = Checkbutton(Frame1) Checkbutton3.place(relx=0.07, rely=0.7, relheight=0.22, relwidth=0.35)
def _criar_estilo(self): ''' Define o estilo dos widgets. ''' cor_1 = '#C7E0DD' cor_2 = '#76B0AC' cor_3 = '#6C8BA7' cor_4 = '#CBB6B4' cor_5 = '#E5D4D0' cor_6 = '#EAE8E6' estilo = Style() # frame estilo.configure('TFrame', background=cor_4) # botao estilo.configure('TButton', background=cor_3, foreground=cor_6, font=('Georgia', 14, 'normal'), relief='flat') estilo.map('TButton', background=[('active', cor_2)], foreground=[('active', cor_6)]) # label estilo.configure('TLabel', background=cor_4, font=('Gergia', 14, 'normal')) # entry estilo.configure('TEntry', fieldbackground=cor_6) #notebook estilo.configure('TNotebook.Tab', background=cor_3, foreground=cor_6, font=('Arial', 14, 'bold'), relief='raised', borderwidth=5) estilo.map('TNotebook.Tab', background=[('active', cor_2)], foreground=[('active', cor_6)]) # option menu estilo.configure('TMenubutton', background=cor_6, font=('Georgia', 14, 'normal'), relief='flat') estilo.map('TMenubutton', background=[('active', cor_2)]) # scales estilo.configure('TScale', background=cor_3) estilo.map('TScale', background=[('active', cor_2)]) # spinboxs estilo.configure('TSpinbox', arrowsize=20, relief='flat', background=cor_3, fieldbackground=cor_6) estilo.map('TSpinbox', background=[('active', cor_2)])
def __init__(self, file=None): Tk.__init__(self, className="Sudoku-Tk") self.title("Sudoku-Tk") self.resizable(0, 0) self.protocol("WM_DELETE_WINDOW", self.quitter) cst.set_icon(self) self.columnconfigure(3, weight=1) # --- style bg = '#dddddd' activebg = '#efefef' pressedbg = '#c1c1c1' lightcolor = '#ededed' darkcolor = '#cfcdc8' bordercolor = '#888888' focusbordercolor = '#5E5E5E' disabledfg = '#999999' disabledbg = bg button_style_config = {'bordercolor': bordercolor, 'background': bg, 'lightcolor': lightcolor, 'darkcolor': darkcolor} button_style_map = {'background': [('active', activebg), ('disabled', disabledbg), ('pressed', pressedbg)], 'lightcolor': [('pressed', darkcolor)], 'darkcolor': [('pressed', lightcolor)], 'bordercolor': [('focus', focusbordercolor)], 'foreground': [('disabled', disabledfg)]} style = Style(self) style.theme_use(cst.STYLE) style.configure('TFrame', background=bg) style.configure('TLabel', background=bg) style.configure('TScrollbar', gripcount=0, troughcolor=pressedbg, **button_style_config) style.map('TScrollbar', **button_style_map) style.configure('TButton', **button_style_config) style.map('TButton', **button_style_map) style.configure('TCheckutton', **button_style_config) style.map('TCheckutton', **button_style_map) self.option_add('*Toplevel.background', bg) self.option_add('*Menu.background', bg) self.option_add('*Menu.activeBackground', activebg) self.option_add('*Menu.activeForeground', "black") self.configure(bg=bg) style.configure("bg.TFrame", background="grey") style.configure("case.TFrame", background="white") style.configure("case.TLabel", background="white", foreground="black") style.configure("case_init.TFrame", background="lightgrey") style.configure("case_init.TLabel", background="lightgrey", foreground="black") style.configure("erreur.TFrame", background="white") style.configure("erreur.TLabel", background="white", foreground="red") style.configure("solution.TFrame", background="white") style.configure("solution.TLabel", background="white", foreground="blue") style.configure("pause.TLabel", foreground="grey", background='white') # --- images self.im_erreur = open_image(cst.ERREUR) self.im_pause = open_image(cst.PAUSE) self.im_restart = open_image(cst.RESTART) self.im_play = open_image(cst.PLAY) self.im_info = open_image(cst.INFO) self.im_undo = open_image(cst.UNDO) self.im_redo = open_image(cst.REDO) self.im_question = open_image(cst.QUESTION) # --- timer self.chrono = [0, 0] self.tps = Label(self, text=" %02i:%02i" % tuple(self.chrono), font="Arial 16") self.debut = False # la partie a-t-elle commencée ? self.chrono_on = False # le chrono est-il en marche ? # --- buttons self.b_pause = Button(self, state="disabled", image=self.im_pause, command=self.play_pause) self.b_restart = Button(self, state="disabled", image=self.im_restart, command=self.recommence) self.b_undo = Button(self, image=self.im_undo, command=self.undo) self.b_redo = Button(self, image=self.im_redo, command=self.redo) # --- tooltips self.tooltip_wrapper = TooltipWrapper(self) self.tooltip_wrapper.add_tooltip(self.b_pause, _("Pause game")) self.tooltip_wrapper.add_tooltip(self.b_restart, _("Restart game")) self.tooltip_wrapper.add_tooltip(self.b_undo, _("Undo")) self.tooltip_wrapper.add_tooltip(self.b_redo, _("Redo")) # --- numbers frame_nb = Frame(self, style='bg.TFrame', width=36) self.progression = [] for i in range(1, 10): self.progression.append(Progression(frame_nb, i)) self.progression[-1].pack(padx=1, pady=1) # --- level indication frame = Frame(self) frame.grid(row=0, columnspan=5, padx=(30, 10), pady=10) Label(frame, text=_("Level") + ' - ', font="Arial 16").pack(side='left') self.label_level = Label(frame, font="Arial 16", text=_("Unknown")) self.label_level.pack(side='left') self.level = "unknown" # puzzle level # --- frame contenant la grille de sudoku self.frame_puzzle = Frame(self, style="bg.TFrame") self.frame_pause = Frame(self, style="case.TFrame") self.frame_pause.grid_propagate(False) self.frame_pause.columnconfigure(0, weight=1) self.frame_pause.rowconfigure(0, weight=1) Label(self.frame_pause, text='PAUSE', style='pause.TLabel', font='Arial 30 bold').grid() # --- placement frame_nb.grid(row=1, column=6, sticky='en', pady=0, padx=(0, 30)) self.frame_puzzle.grid(row=1, columnspan=5, padx=(30, 15)) self.tps.grid(row=2, column=0, sticky="e", padx=(30, 10), pady=30) self.b_pause.grid(row=2, column=1, sticky="w", padx=2, pady=30) self.b_restart.grid(row=2, column=2, sticky="w", padx=2, pady=30) self.b_undo.grid(row=2, column=3, sticky="e", pady=30, padx=2) self.b_redo.grid(row=2, column=4, sticky="w", pady=30, padx=(2, 10)) # --- menu menu = Menu(self, tearoff=0) menu_nouveau = Menu(menu, tearoff=0) menu_levels = Menu(menu_nouveau, tearoff=0) menu_levels.add_command(label=_("Easy"), command=self.new_easy) menu_levels.add_command(label=_("Medium"), command=self.new_medium) menu_levels.add_command(label=_("Difficult"), command=self.new_difficult) menu_nouveau.add_cascade(label=_("Level"), menu=menu_levels) menu_nouveau.add_command(label=_("Generate a puzzle"), command=self.genere_grille, accelerator="Ctrl+G") menu_nouveau.add_command(label=_("Empty grid"), command=self.grille_vide, accelerator="Ctrl+N") menu_ouvrir = Menu(menu, tearoff=0) menu_ouvrir.add_command(label=_("Game"), command=self.import_partie, accelerator="Ctrl+O") menu_ouvrir.add_command(label=_("Puzzle"), command=self.import_grille, accelerator="Ctrl+Shift+O") menu_game = Menu(menu, tearoff=0) menu_game.add_command(label=_("Restart"), command=self.recommence) menu_game.add_command(label=_("Solve"), command=self.resolution) menu_game.add_command(label=_("Save"), command=self.sauvegarde, accelerator="Ctrl+S") menu_game.add_command(label=_("Export"), command=self.export_impression, accelerator="Ctrl+E") menu_game.add_command(label=_("Evaluate level"), command=self.evaluate_level) menu_language = Menu(menu, tearoff=0) self.langue = StringVar(self) self.langue.set(cst.LANGUE[:2]) menu_language.add_radiobutton(label="Français", variable=self.langue, value="fr", command=self.translate) menu_language.add_radiobutton(label="English", variable=self.langue, value="en", command=self.translate) menu_help = Menu(menu, tearoff=0) menu_help.add_command(label=_("Help"), command=self.aide, accelerator='F1') menu_help.add_command(label=_("About"), command=self.about) menu.add_cascade(label=_("New"), menu=menu_nouveau) menu.add_cascade(label=_("Open"), menu=menu_ouvrir) menu.add_cascade(label=_("Game"), menu=menu_game) menu.add_cascade(label=_("Language"), menu=menu_language) menu.add_command(label=_("Statistics"), command=self.show_stat) menu.add_cascade(label=_("Help"), menu=menu_help) self.configure(menu=menu) # --- clavier popup self.clavier = None # --- cases self.nb_cases_remplies = 0 self.blocs = np.zeros((9, 9), dtype=object) for i in range(9): for j in range(9): self.blocs[i, j] = Case(self.frame_puzzle, i, j, self.update_nbs, width=50, height=50) px, py = 1, 1 if i % 3 == 2 and i != 8: py = (1, 3) if j % 3 == 2 and j != 8: px = (1, 3) self.blocs[i, j].grid(row=i, column=j, padx=px, pady=py) self.blocs[i, j].grid_propagate(0) # --- undo/redo stacks self._undo_stack = [] self._redo_stack = [] # --- raccourcis clavier et actions de la souris self.bind("<Button>", self.edit_case) self.bind("<Control-z>", lambda e: self.undo()) self.bind("<Control-y>", lambda e: self.redo()) self.bind("<Control-s>", lambda e: self.sauvegarde()) self.bind("<Control-e>", lambda e: self.export_impression()) self.bind("<Control-o>", lambda e: self.import_partie()) self.bind("<Control-Shift-O>", lambda e: self.import_grille()) self.bind("<Control-n>", lambda e: self.grille_vide()) self.bind("<Control-g>", lambda e: self.genere_grille()) self.bind("<FocusOut>", self.focus_out) self.bind("<F1>", self.aide) # --- open game if file: try: self.load_sudoku(file) except FileNotFoundError: one_button_box(self, _("Error"), _("The file %(file)r does not exist.") % file, image=self.im_erreur) except (KeyError, EOFError, UnpicklingError): try: self.load_grille(file) except Exception: one_button_box(self, _("Error"), _("This file is not a valid sudoku file."), image=self.im_erreur) elif exists(cst.PATH_SAVE): self.load_sudoku(cst.PATH_SAVE) remove(cst.PATH_SAVE)