class _EditorFrame(tk.Frame): """ A widget for creating, editing, and saving Settings objects for the pyTRSplat module. (Not for direct use. SettingsEditor object embeds / controls this object.) """ MW_PADX = 4 MW_PADY = 1 FIRST_WRITE_CHKBTN_ROW = 5 SM_ENTRYBOX_WIDTH = 3 MID_ENTRYBOX_WIDTH = 6 ENTRYBOX_PADX = 4 INNER_LBL_PADX = 4 DIM_ROW = 1 GRID_MARG_FIRST_ROW = 2 LINE_CONFIG_FIRST_ROW = 30 # For pulling typeface keys by value TYPEFACES_BY_FP = {} for k, v in Settings.TYPEFACES.items(): TYPEFACES_BY_FP[v] = k DEFAULT_FONT_KEY = 'Sans-Serif' def __init__(self, master=None, load_settings=None): tk.Frame.__init__(self, master=master) self.master = master if load_settings is None: load_settings = Settings(preset=None) ls = load_settings # TODO: Toggle displaying px or inches # TODO: Configure ppi (when displaying inches) ################################# # DIMENSIONS / MARGINS ################################# dim_frame = tk.Frame(self) dim_frame.grid(row=self.DIM_ROW, column=1, sticky='w') self.page_width = self.IntVarSetter(dim_frame, var_name='RAW_width', display_name='Page Width', start_val=ls.dim[0]) self.page_width.grid(row=0, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') self.page_height = self.IntVarSetter(dim_frame, var_name='RAW_width', display_name='Page Height', start_val=ls.dim[1]) self.page_height.grid(row=0, column=2, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') # Main margins next_avail_row = self.GRID_MARG_FIRST_ROW self.y_top_marg = self.IntVarSetter(self, var_name='y_top_marg', display_name='Upper Margin (Grid)', start_val=ls.y_top_marg) self.y_top_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.y_bottom_marg = self.IntVarSetter( self, var_name='y_bottom_marg', start_val=ls.y_bottom_marg, display_name='Bottom Margin (Entire Page)') self.y_bottom_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.qq_side = self.QQSideSetter( self, var_name='qq_side', display_name='Side length of each QQ square', start_val=ls.qq_side) self.qq_side.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') # TODO: Display left/right margins that are left after this setting # TODO: Optional set-by-LR-margin. next_avail_row += 1 cb_text = ('Size of area to clear at center of each ' 'section for writing section number') self.centerbox_wh = self.IntVarSetter(self, var_name='centerbox_wh', display_name=cb_text, start_val=ls.centerbox_wh) self.centerbox_wh.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 ################################# # CONFIGURE LINES / FILL ################################# self.qq_fill_RGBA = self.QQColorSetter(self, RGBA=ls.qq_fill_RGBA) self.qq_fill_RGBA.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 next_avail_row = self.LINE_CONFIG_FIRST_ROW self.sec_line = self.LineSetter(self, var_name='sec_line', display_name='Section Line', stroke=ls.sec_line_stroke, RGBA=ls.sec_line_RGBA) self.sec_line.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.ql_line = self.LineSetter(self, var_name='ql', display_name='Half-Dividing Line', stroke=ls.ql_stroke, RGBA=ls.ql_RGBA) self.ql_line.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.qql_line = self.LineSetter(self, var_name='qql', display_name='Quarter-Dividing Line', stroke=ls.qql_stroke, RGBA=ls.qql_RGBA) self.qql_line.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 ################################# # WHAT TO WRITE / FONTS / TEXT CONFIGURE ################################# self.write_header = tk.BooleanVar(self, value=ls.write_header, name='write_header') self.write_header_chkbtn = Checkbutton( self, text='Write Header in Top Margin', onvalue=True, offvalue=False, variable=self.write_header) self.write_header_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.headerfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.header_font = self.FontSetter(self, font_size=ls.headerfont_size, display_name='Header Font', var_name='headerfont', typeface=tf, RGBA=ls.headerfont_RGBA) self.header_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.y_header_marg = self.IntVarSetter( self, var_name='y_header_marg', start_val=ls.y_header_marg, display_name= 'How far above grid to write header (within top margin)') self.y_header_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.write_section_numbers = tk.BooleanVar( self, value=ls.write_section_numbers, name='write_section_numbers') self.write_section_numbers_chkbtn = Checkbutton( self, text='Write Section Numbers', onvalue=True, offvalue=False, variable=self.write_section_numbers) self.write_section_numbers_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.secfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.section_numbers_font = self.FontSetter( self, font_size=ls.secfont_size, display_name='Section Number Font', var_name='secfont', typeface=tf, RGBA=ls.secfont_RGBA) self.section_numbers_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.write_lot_numbers = tk.BooleanVar(self, value=ls.write_lot_numbers, name='write_lot_numbers') self.write_lot_numbers_chkbtn = Checkbutton( self, text='Write lot numbers within the appropriate QQ(s)', onvalue=True, offvalue=False, variable=self.write_lot_numbers) self.write_lot_numbers_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.lotfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.lot_font = self.FontSetter(self, font_size=ls.lotfont_size, display_name='Lot Number Font', var_name='lotfont', typeface=tf, RGBA=ls.lotfont_RGBA) self.lot_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.lot_num_offset_px = self.IntVarSetter( self, var_name='lot_num_offset_px', start_val=ls.lot_num_offset_px, display_name= 'Lot number distance from top-left corner of QQ (in px)') self.lot_num_offset_px.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.write_tracts = tk.BooleanVar(self, value=ls.write_tracts, name='write_tracts') self.write_tracts_chkbtn = Checkbutton( self, text='Write all tracts at the bottom', onvalue=True, offvalue=False, variable=self.write_tracts) self.write_tracts_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.tractfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.tract_font = self.FontSetter(self, font_size=ls.tractfont_size, display_name='Tract Font', var_name='tractfont', typeface=tf, RGBA=ls.tractfont_RGBA) self.tract_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 # A customized RGBASetter for warningfont_RGBA, since we don't # need to set typeface or size: wfont_txt = 'Font color for writing errors/warnings' self.warning_font_RGBA = _EditorFrame.RGBASetter( self, display_name=wfont_txt, show_opacity=False, var_name='warningfont_RGBA', RGBA=ls.warningfont_RGBA) self.warning_font_RGBA.rgba_frame.grid(row=0, column=1) lbl = tk.Label(self.warning_font_RGBA, text=wfont_txt) lbl.grid(row=0, column=0) self.warning_font_RGBA.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 ################################# # TractTextBox margins and other tract-writing configurables ################################# self.y_px_before_tracts = self.IntVarSetter( self, var_name='y_px_before_tracts', start_val=ls.y_px_before_tracts, display_name= 'Distance between bottom of the grid and the first written tract') self.y_px_before_tracts.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.x_text_left_marg = self.IntVarSetter( self, var_name='x_text_left_marg', start_val=ls.x_text_left_marg, display_name='Left Margin (for tract text below grid)') self.x_text_left_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.x_text_right_marg = self.IntVarSetter( self, var_name='x_text_right_marg', start_val=ls.x_text_right_marg, display_name='Right Margin (for tract text below grid)') self.x_text_right_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.y_px_between_tracts = self.IntVarSetter( self, var_name='y_px_between_tracts', start_val=ls.y_px_between_tracts, display_name='Space between lines of text') self.y_px_between_tracts.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.paragraph_indent = self.IntVarSetter( self, var_name='paragraph_indent', start_val=ls.paragraph_indent, display_name='Paragraph indent (in spaces, not pixels or inches)') self.paragraph_indent.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.new_line_indent = self.IntVarSetter( self, var_name='new_line_indent', start_val=ls.new_line_indent, display_name='Linebreak indent (in spaces, not pixels or inches)') self.new_line_indent.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.justify_tract_text = tk.BooleanVar(self, value=ls.justify_tract_text, name='justify_tract_text') self.justify_tract_text_chkbtn = Checkbutton( self, text='Justify tract text', onvalue=True, offvalue=False, variable=self.justify_tract_text) self.justify_tract_text_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 # Set the bool variables, according to the attributes in `ls` # (i.e. enact the settings in the `load_settings` object). # Note: This is not optimal design, but it seems to solve a # weird bug. Back when these values were set at the time that # the variables/checkbuttons themselves were created, the # _EditorFrame would fail to actually set them (to either True # or False), maybe 5% of the time. When clicking "Load Preset" # button repeatedly, with nothing different, would sometimes get # different results, and I could not reliably recreate the bug. # This is ineligant, but seems(?) to fix it... for var_name in [ 'write_header', 'write_section_numbers', 'write_lot_numbers', 'write_tracts', 'justify_tract_text' ]: getattr(self, var_name).set(getattr(ls, var_name)) def compile_settings(self): """ Compile all of the configured parameters into a Settings object, and return that object. IMPORTANT: Returns `False` if any fields contained invalid values. """ #TODO: Error-check any impossible parameters (margins too big, etc.) settings = [] w = self.page_width.compile() h = self.page_height.compile() dim = f"dim={w},{h}" settings.append(dim) settings.append(self.qq_side.compile()) settings.append(self.y_bottom_marg.compile()) settings.append(self.header_font.compile()) settings.append(self.y_header_marg.compile()) settings.append(self.tract_font.compile()) settings.append(self.section_numbers_font.compile()) settings.append(self.lot_font.compile()) warning_RGBA = self.warning_font_RGBA.compile_RGBA() if warning_RGBA is False: settings.append(warning_RGBA) else: settings.append(f"warningfont_RGBA={warning_RGBA}") settings.append(self.compile_checkbuttons()) settings.append(self.y_top_marg.compile()) settings.append(self.lot_num_offset_px.compile()) settings.append(self.y_px_before_tracts.compile()) settings.append(self.sec_line.compile()) settings.append(self.ql_line.compile()) settings.append(self.qql_line.compile()) settings.append(self.qq_fill_RGBA.compile()) settings.append(self.centerbox_wh.compile()) settings.append(self.x_text_left_marg.compile()) settings.append(self.x_text_right_marg.compile()) settings.append(self.y_px_between_tracts.compile()) settings.append(self.paragraph_indent.compile()) settings.append(self.new_line_indent.compile()) settings.append(self.qq_fill_RGBA.compile()) # Check for any errors: for setting in settings: if setting is False: return False settings_text = '\n'.join(settings) set_obj = Settings() set_obj._parse_text_to_settings(settings_text) return set_obj def warning(self, title, message): """ Show a warning, then reset focus on the window. """ tk.messagebox.showwarning(title, message) self.focus() def compile_checkbuttons(self) -> str: """ Compile parameters that are configured in Checkbuttons within the main window. Return as string. """ txt = '' # For each of these var_names, check the state of the checkbutton # and set the val accordingly. # # Note: This is not optimal design, but it seems to solve a # weird bug. Checking the BooleanVar values with .get() seemed # to set the state of the checkboxes to 'alternate' maybe 5% of # the time, and I couldn't recreate it reliably to debug it. # This is ineligant, but seems(?) to fix it... for var_name in [ 'write_header', 'write_section_numbers', 'write_lot_numbers', 'write_tracts', 'justify_tract_text' ]: chkbtn = getattr(self, var_name + '_chkbtn') val = False if 'selected' in chkbtn.state(): val = True chkbtn.state(['selected']) else: chkbtn.state(['!selected']) chkbtn.state(['!alternate']) txt = f"{txt}{var_name}={val}\n" return txt class RGBASetter(tk.Frame): """ The skeleton of a class that uses RGBAWidget. Not used directly, but allows child classes to inherit `.compile_RGBA()` method. IMPORTANT: Creates `self.rgba_frame` but does NOT place it on the grid; must call `rgba_frame.grid(...)` for every subclass! """ def __init__(self, master=None, display_name='', var_name='', RGBA=(0, 0, 0, 255), show_opacity=True): """ :param display_name: The public display name of the variable (for warning message purposes). :param var_name: The name of the variable (corresponding to the attribute name of a Settings object). :param RGBA: The starting RGBA values. :param show_opacity: Whether to give the option to set opacity. """ tk.Frame.__init__(self, master=master) self.master = master self.display_name = display_name self.var_name = var_name self.show_opacity = show_opacity # RGBA self.R, self.G, self.B, self.A = None, None, None, None self.rgba_frame = self.RGBAWidget(self, RGBA=RGBA) self.rgba_frame.grid(row=0, column=0) def compile_RGBA(self) -> str: """ Compile the entered RGBA values into a string, formatted '(0,0,0,0)'. If invalid values have been entered, will instead show a popup error message and return `False`. """ try: r = int(self.R.get()) g = int(self.G.get()) b = int(self.B.get()) a = int(self.A.get()) for i in [r, g, b, a]: if i < 0 or i > 255: raise ValueError except ValueError: opacity_txt = '' if self.show_opacity: opacity_txt = ' and Opacity' self.master.warning( 'Invalid RGBA', "Error: Enter numerical values (0 to 255) for " f"RGB{opacity_txt} for <{self.display_name}>.") return False return f"{r},{g},{b},{a}" def rgb_to_hex(self) -> str: """ Convert the current RGB values to a hex string. """ try: r = int(self.R.get()) g = int(self.G.get()) b = int(self.B.get()) rgb_as_hex = '#' for i in [r, g, b]: if i < 0 or i > 255: raise ValueError h = hex(i).split('x')[-1] h = h.rjust(2, '0') rgb_as_hex = rgb_as_hex + h return rgb_as_hex except: return False class RGBAWidget(tk.Frame): """ A frame for setting RGBA values. (Note: `.R`, `.G`, `.B`, and `A.` are set for `master`, not for `self`.) """ DISPLAY_COLOR_PREVIEW = True def __init__(self, master=None, RGBA=(0, 0, 0, 255)): tk.Frame.__init__(self, master) self.master = master lbl = tk.Label(self, text='RGB color values (0-255):') lbl.grid(row=0, column=0, sticky='w', padx=_EditorFrame.INNER_LBL_PADX) self.show_opacity = master.show_opacity self.master.R = tk.Entry(self, width=_EditorFrame.SM_ENTRYBOX_WIDTH) self.master.R.grid(row=0, column=1, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.master.R.insert(tk.END, str(RGBA[0])) self.master.G = tk.Entry(self, width=_EditorFrame.SM_ENTRYBOX_WIDTH) self.master.G.grid(row=0, column=2, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.master.G.insert(tk.END, str(RGBA[1])) self.master.B = tk.Entry(self, width=_EditorFrame.SM_ENTRYBOX_WIDTH) self.master.B.grid(row=0, column=3, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.master.B.insert(tk.END, str(RGBA[2])) if self.DISPLAY_COLOR_PREVIEW: preview_btn = tk.Button(self, text='Preview:', command=self.update_preview) preview_btn.grid(row=0, column=4, padx=1) self.preview_label = tk.Label(self, bg=master.rgb_to_hex(), width=2) self.preview_label.grid(row=0, column=5, sticky='w') lbl = tk.Label(self, text='Opacity (0-255):') self.master.A = tk.Entry(self, width=_EditorFrame.SM_ENTRYBOX_WIDTH) self.master.A.insert(tk.END, str(RGBA[3])) if self.show_opacity: lbl.grid(row=0, column=6, sticky='w', padx=_EditorFrame.INNER_LBL_PADX) self.master.A.grid(row=0, column=7, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) def update_preview(self): rgb_as_hex = self.master.rgb_to_hex() if rgb_as_hex is False: return self.preview_label.config(bg=rgb_as_hex) class IntVarSetter(tk.Frame): """ A frame for setting a single-integer type variable. """ def __init__(self, master=None, var_name='', display_name='', start_val=0): tk.Frame.__init__(self, master=master) self.editor = master self.var_name = var_name self.display_name = display_name self.v = tk.Entry(master=self, width=_EditorFrame.MID_ENTRYBOX_WIDTH) self.v.grid(row=0, column=0, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.v.insert(tk.END, str(start_val)) lbl = tk.Label(self, text=display_name) lbl.grid(row=0, column=1, sticky='w', padx=_EditorFrame.INNER_LBL_PADX) def compile(self): try: if self.var_name.startswith('RAW'): return int(self.v.get()) return f"{self.var_name}={int(self.v.get())}\n" except: self.master.warning( 'Invalid Number', "Error: Enter a numerical value for " f"<{self.display_name}>") return False class QQSideSetter(IntVarSetter): """ A frame for setting qq_side variable, while also showing the resulting margins. """ def __init__(self, master=None, var_name='', display_name='', start_val=0): _EditorFrame.IntVarSetter.__init__(self, master, var_name, display_name, start_val) marg_per_qq_btn = tk.Button( self, text="Calculate Left/Right Page Margins:", padx=3, command=self.marg_per_qq) marg_per_qq_btn.grid(row=0, column=3, sticky='e') self.lr_marg = tk.Entry(self, width=_EditorFrame.MID_ENTRYBOX_WIDTH) self.marg_per_qq() self.lr_marg.grid(row=0, column=4, sticky='w') qq_per_margin_btn = tk.Button( self, text="Calculate QQ side length per specified L/R margins", padx=3, command=self.qq_per_margin) qq_per_margin_btn.grid(row=0, column=5, sticky='e') def qq_per_margin(self): """Calculate the qq_side, per lr_marg.""" try: w = int(self.master.page_width.v.get()) lr_marg = int(self.lr_marg.get()) except ValueError: return False qq_side = (w - (lr_marg * 2)) // 24 if qq_side <= 0: return False self.v.delete(0, 'end') self.v.insert(tk.END, qq_side) def marg_per_qq(self): """Calculate the lr_marg, per qq_side and width.""" try: w = int(self.master.page_width.v.get()) qq_side = int(self.v.get()) except ValueError: return False lr_marg = (w - (qq_side * 4 * 6)) // 2 if lr_marg <= 0: return False self.lr_marg.delete(0, 'end') self.lr_marg.insert(tk.END, lr_marg) class QQColorSetter(RGBASetter): """ A frame for setting QQ fill color. """ def __init__(self, master=None, display_name='QQ Fill', var_name='qq_fill_RGBA', RGBA=Settings.RGBA_BLUE_OVERLAY): _EditorFrame.RGBASetter.__init__(self, master, display_name, var_name, RGBA, show_opacity=True) lbl = tk.Label(self, text=display_name, anchor='e') lbl.grid(row=0, column=0) # This frame is created by the parent class. Only needs to be # placed on grid here. self.rgba_frame.grid(row=0, column=1, sticky='w') def compile(self) -> str: """ Compile the RGBA into the appropriate string. :return: A string with the appropriate text. """ # get RGBA rgba = self.compile_RGBA() if rgba is False: return False return f"{self.var_name}={rgba}\n" class FontSetter(RGBASetter): """ A frame for setting font size, color, and typeface. """ AVAIL_FONTS = list(Settings.TYPEFACES.keys()) def __init__(self, master=None, font_size=12, display_name='', var_name='', typeface='Sans-Serif', RGBA=(0, 0, 0, 255)): _EditorFrame.RGBASetter.__init__(self, master, display_name, var_name, RGBA, show_opacity=False) # Font size lbl = tk.Label(self, text='Font size:', anchor='e') lbl.grid(row=0, column=0) self.font_size = tk.Entry(self, width=_EditorFrame.SM_ENTRYBOX_WIDTH) self.font_size.grid(row=0, column=1, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.font_size.insert(tk.END, font_size) # Typeface lbl = tk.Label(self, text="'Liberation' Font:", anchor='e') lbl.grid(row=0, column=2) self.typeface = Combobox(self, width=18) self.typeface.grid(row=0, column=3, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.typeface['values'] = self.AVAIL_FONTS try: typeface_index = self.AVAIL_FONTS.index(typeface) except: typeface_index = 0 self.typeface.current(typeface_index) # RGBA # This frame is created by the parent class. Only needs to be # placed on grid here. # TODO: Bugfix: why isn't rgba_frame showing up in grid? self.rgba_frame.grid(row=0, column=4, sticky='w') def compile(self) -> str: """ Compile the size, typeface, and RGBA into the appropriate string. :return: A string with the appropriate text. """ # Get font size try: font_size = int(self.font_size.get()) if font_size < 1: raise ValueError except (ValueError, TypeError): self.master.warning( 'Invalid Stroke', "Error: Enter a positive numerical value for 'size' for " f"<{self.display_name}>") return False txt = f"{self.var_name}_size={font_size}\n" # Get typeface typeface_fp = Settings.TYPEFACES.get(self.typeface.get()) if typeface_fp is False: self.master.warning( 'Invalid Font', "Error: Choose one of the available fonts for " f"<{self.display_name}>") return False txt = (f"{txt}{self.var_name}_typeface=" f"{Settings.TYPEFACES[self.typeface.get()]}\n") # get RGBA rgba = self.compile_RGBA() if rgba is False: return False return f"{txt}{self.var_name}_RGBA={rgba}\n" class LineSetter(RGBASetter): """ A frame for setting a line (Section, Half, Quarter). Possible `var_name` options: 'sec_line', 'ql', 'qql' """ MAIN_LBL_WID = 18 def __init__(self, master=None, var_name='', display_name='', stroke=1, RGBA=(0, 0, 0, 255)): _EditorFrame.RGBASetter.__init__(self, master, display_name, var_name, RGBA, show_opacity=False) self.master = master lbl = tk.Label(self, text=display_name + ':', width=self.MAIN_LBL_WID, anchor='w') lbl.grid(row=0, column=0, sticky='w', padx=_EditorFrame.INNER_LBL_PADX) # Stroke lbl = tk.Label(self, text='stroke (px):') lbl.grid(row=0, column=1, sticky='w', padx=_EditorFrame.INNER_LBL_PADX) self.stroke = tk.Entry(self, width=_EditorFrame.SM_ENTRYBOX_WIDTH) self.stroke.grid(row=0, column=2, sticky='w', padx=_EditorFrame.ENTRYBOX_PADX) self.stroke.insert(tk.END, str(stroke)) # RGBA # This frame is created by the parent class. Only needs to be # placed on grid here. self.rgba_frame.grid(row=0, column=3) def compile(self): """ Compile stroke and RGBA into the appropriate string. Returns `False` if either contained invalid values. """ try: strk = int(self.stroke.get()) if strk < 1: raise ValueError except (ValueError, TypeError): self.master.warning( 'Invalid Stroke', "Error: Enter a positive numerical value for 'stroke' for " f"<{self.display_name}>") return False txt = f"{self.var_name}_stroke={strk}\n" rgba = self.compile_RGBA() if rgba is False: return False return f"{txt}{self.var_name}_RGBA={rgba}\n"
def create_other_buttons(self): btn = Checkbutton(self.make_frame()[0], variable=self.recvar, text="是否包含子目录") btn.pack(side="top", fill="both")
def add_check_button(self): self.v1 = IntVar() self.v2 = IntVar() self.v3 = IntVar() self.v4 = IntVar() self.v5 = IntVar() self.v6 = IntVar() self.v7 = IntVar() self.v1.set("T") self.Check_total = Checkbutton(self.win, text="全部车次", variable=self.v1, onvalue='T') self.Check_total.place(x=168, y=7, width=80, height=30) self.Check_total = Checkbutton(self.win, text="G-高铁", variable=self.v2, onvalue='T') self.Check_total.place(x=258, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="D-动车", variable=self.v3, onvalue='T') self.Check_total.place(x=348, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="Z-直达", variable=self.v4, onvalue='T') self.Check_total.place(x=418, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="T-特快", variable=self.v5, onvalue='T') self.Check_total.place(x=488, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="K-快速", variable=self.v6, onvalue='T') self.Check_total.place(x=568, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="其他", variable=self.v7, onvalue='T') self.Check_total.place(x=648, y=7, width=60, height=30)
def create_other_buttons(self): "Add check button to recurse down subdirectories." btn = Checkbutton( self.make_frame()[0], variable=self.recvar, text="Recurse down subdirectories") btn.pack(side="top", fill="both")
class HighlightCode(): """ Created by yogesh singh and please follow my instagram page @dynamiccoding for more projects Plese install pygments and pyperclip . . make sure to follow me on github as well . and give feedback and suggestions also ......... """ def __init__(self,root): self.root = root self.check_line_on = BooleanVar() self.code_text = ScrolledText(self.root,bd=4,relief=GROOVE) self.code_text.place(x=0,y=0,height=300,width=300) self.output_code = ScrolledText(self.root,bd=4,relief=GROOVE) self.output_code.place(x=300,y=0,height=300,width=300) self.control_frame = Frame(self.root,bd=2,relief=GROOVE) self.control_frame.place(x=25,y=310,height=130,width=550) # ................ controls in control frames ................... self.languages = ['python','C','C++','java','php','C#'] self.borders = ['dotted','dashed','solid','double','groove','ridge','inset','none','hidden'] #self.border_width = ['2px','4px','6px','8px','10px','medium','thick'] self.border_clrs = ['red','black','gray','white','green','yellow','pink','cyan','sky blue'] self.styles = ['default', 'emacs', 'friendly', 'colorful', 'autumn', 'murphy', 'monokai', 'perldoc', 'pastie', 'borland', 'trac', 'native', 'fruity', 'bw', 'vim', 'vs', 'tango', 'rrt', 'xcode', 'igor', 'paraiso-light', 'paraiso-dark', 'lovelace', 'algol', 'algol_nu', 'arduino', 'rainbow_dash', 'abap', 'solarized-dark', 'solarized-light', 'sas', 'stata', 'stata-light', 'stata-dark', 'inkpot'] self.style_combo = Combobox(self.control_frame,width=20,values=self.styles,justify=CENTER) self.style_combo.set('Select Style') self.style_combo.place(x=10,y=5) self.border_combo = Combobox(self.control_frame,width=20,values=self.borders,justify=CENTER) self.border_combo.set('Select Border') self.border_combo.place(x=10,y=45) self.border_color_combo = Combobox(self.control_frame,width=20,values=self.border_clrs,justify=CENTER) self.border_color_combo.set('Border Color') self.border_color_combo.place(x=10,y=85) self.language_combo = Combobox(self.control_frame,width=15,values=self.languages,justify=CENTER) self.language_combo.set('python') self.language_combo.place(x=180,y=40) self.Line_no_check = Checkbutton(self.control_frame,text='Enable Line No.',onvalue=True,offvalue=False, variable=self.check_line_on) self.Line_no_check.place(x=180,y=9) highlight_btn = ttk.Button(self.control_frame,text='Highlight',command=self.highlight_code) highlight_btn.place(x=300,y=10) copy_edit_code = ttk.Button(self.control_frame,text='Copy Code',command=self.copy_code) copy_edit_code.place(x=300,y=50) clear_input_text = ttk.Button(self.control_frame,text='Clear Input Box', width=20,command=lambda:self.code_text.delete(0.0,END)) clear_input_text.place(x=400,y=10) clear_output_text = ttk.Button(self.control_frame,text='Clear Output Box', width=20,command=lambda:self.output_code.delete(0.0,END)) clear_output_text.place(x=400,y=50) # ............... Functions ..................... def highlight_code(self): self.output_code.delete(0.0,END) lexer = self.language_combo.get() linenos = self.check_line_on.get() defstyles = 'overflow:auto;width:auto;' divstyles = self.get_default_style() style = self.style_combo.get() if style == 'Select Style': style ='default' code = self.code_text.get(0.0,END) formatter = HtmlFormatter(style=style, linenos=False, noclasses=True, cssclass='', cssstyles=defstyles + divstyles, prestyles='margin: 0') html = highlight(code, get_lexer_by_name(lexer, stripall=True), formatter) if linenos: html = self.insert_line_numbers(html) html = "<!-- Syntax Highlighter by Dynamic Coding Code Highlighter -->" + html self.output_code.insert(0.0,html) def get_default_style(self): if self.border_color_combo.get() != 'Border Color' or self.border_combo.get() != 'Select Border': if self.border_color_combo.get() == 'Border Color': self.border_color_combo.set('solid') if self.border_combo.get() == 'Select Border': self.border_combo.set('gray') return 'border:'+str(self.border_combo.get())+' '+str(self.border_color_combo.get())+';border-width:.1em .1em .1em .8em;padding:.2em .6em;' else: return 'border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;' def insert_line_numbers(self,html): match = re.search('(<pre[^>]*>)(.*)(</pre>)', html, re.DOTALL) if not match: return html pre_open = match.group(1) pre = match.group(2) pre_close = match.group(3) html = html.replace(pre_close, '</pre></td></tr></table>') numbers = range(1, pre.count('\n') + 1) format = '%' + str(len(str(numbers[-1]))) + 'i' lines = '\n'.join(format % i for i in numbers) html = html.replace(pre_open, '<table><tr><td>' + pre_open + lines + '</pre></td><td>' + pre_open) return html def copy_code(self): pc.copy(self.output_code.get(0.0,END)) messagebox.showinfo("Highlighter says"," Code is copied to Clipboard")
def __init__(self, master, **kwargs): Checkbutton.__init__(self, master, **kwargs) self.configure(style="TButton", command=self._stateChanged)
def __init__(self, parent, txt: dict = dict(), path_browser=None, path_var: str = ""): """Instanciating the output workbook.""" self.p = parent self.txt = txt Frame.__init__(self) # -- VARIABLES ------------------------------------------------------- self.target_path = StringVar() # formats / type: vectors self.li_vectors_formats = ( ".shp", ".tab", ".kml", ".gml", ".geojson", ) # vectors handled self.li_shp = [] # list for shapefiles path self.li_tab = [] # list for MapInfo tables path self.li_kml = [] # list for KML path self.li_gml = [] # list for GML path self.li_geoj = [] # list for GeoJSON paths self.li_gxt = [] # list for GXT paths self.li_vectors = [] # list for all vectors # formats / type: rasters self.li_raster = [] # list for rasters paths self.li_raster_formats = (".ecw", ".tif", ".jp2") # raster handled # formats / type: file databases self.li_fdb = [] # list for all files databases self.li_egdb = [] # list for Esri File Geodatabases self.li_spadb = [] # list for Spatialite Geodatabases # formats / type: CAO/DAO self.li_cdao = [] # list for all CAO/DAO files self.li_dxf = [] # list for AutoCAD DXF paths self.li_dwg = [] # list for AutoCAD DWG paths self.li_dgn = [] # list for MicroStation DGN paths # formats / type: maps documents self.li_mapdocs = [] # list for all map & documents self.li_qgs = [] # list for QGS path # -- Source path ----------------------------------------------------- self.FrPath = Labelframe(self, name="files", text=txt.get("gui_fr1", "Path")) # target folder self.lb_target = Label(self.FrPath, text=txt.get("gui_path")) self.ent_target = Entry(master=self.FrPath, width=35, textvariable=self.target_path) self.btn_browse = Button( self.FrPath, text="\U0001F3AF " + txt.get("gui_choix", "Browse"), command=lambda: self.get_target_path(r"."), takefocus=True, ) self.btn_browse.focus_force() # widgets placement self.lb_target.grid(row=1, column=1, columnspan=1, sticky="NSWE", padx=2, pady=2) self.ent_target.grid(row=1, column=2, columnspan=1, sticky="NSWE", padx=2, pady=2) self.btn_browse.grid(row=1, column=3, sticky="NSE", padx=2, pady=2) # -- Format filters -------------------------------------------------- self.FrFilters = Labelframe(self, name="filters", text=txt.get("gui_fr3", "Filters")) # formats options self.opt_shp = IntVar(self.FrFilters) # able/disable shapefiles self.opt_tab = IntVar(self.FrFilters) # able/disable MapInfo tables self.opt_kml = IntVar(self.FrFilters) # able/disable KML self.opt_gml = IntVar(self.FrFilters) # able/disable GML self.opt_geoj = IntVar(self.FrFilters) # able/disable GeoJSON self.opt_gxt = IntVar(self.FrFilters) # able/disable GXT self.opt_egdb = IntVar(self.FrFilters) # able/disable Esri FileGDB self.opt_spadb = IntVar(self.FrFilters) # able/disable Spatalite DB self.opt_rast = IntVar(self.FrFilters) # able/disable rasters self.opt_cdao = IntVar(self.FrFilters) # able/disable CAO/DAO files self.opt_qgs = IntVar(self.FrFilters) # able/disable Geospatial QGS # format choosen: check buttons caz_shp = Checkbutton(self.FrFilters, text=".shp", variable=self.opt_shp) caz_tab = Checkbutton(self.FrFilters, text=".tab", variable=self.opt_tab) caz_kml = Checkbutton(self.FrFilters, text=".kml", variable=self.opt_kml) caz_gml = Checkbutton(self.FrFilters, text=".gml", variable=self.opt_gml) caz_geoj = Checkbutton(self.FrFilters, text=".geojson", variable=self.opt_geoj) caz_gxt = Checkbutton(self.FrFilters, text=".gxt", variable=self.opt_gxt) caz_egdb = Checkbutton(self.FrFilters, text="Esri FileGDB", variable=self.opt_egdb) caz_spadb = Checkbutton(self.FrFilters, text="Spatialite", variable=self.opt_spadb) caz_rast = Checkbutton( self.FrFilters, text="rasters ({0})".format(", ".join(self.li_raster_formats)), variable=self.opt_rast, ) caz_cdao = Checkbutton(self.FrFilters, text="CAO/DAO", variable=self.opt_cdao) # widgets placement caz_shp.grid(row=1, column=0, sticky="NSWE", padx=2, pady=2) caz_tab.grid(row=1, column=1, sticky="NSWE", padx=2, pady=2) caz_kml.grid(row=1, column=2, sticky="NSWE", padx=2, pady=2) caz_gml.grid(row=1, column=3, sticky="NSWE", padx=2, pady=2) caz_geoj.grid(row=1, column=4, sticky="NSWE", padx=2, pady=2) caz_gxt.grid(row=1, column=5, sticky="NSWE", padx=2, pady=2) caz_rast.grid(row=2, column=0, columnspan=2, sticky="NSWE", padx=2, pady=2) caz_egdb.grid(row=2, column=2, columnspan=2, sticky="NSWE", padx=2, pady=2) caz_cdao.grid(row=2, column=4, columnspan=1, sticky="NSWE", padx=2, pady=2) caz_spadb.grid(row=2, column=5, columnspan=2, sticky="NSWE", padx=2, pady=2) # frames placement self.FrPath.grid(row=3, column=1, padx=2, pady=2, sticky="NSWE") self.FrFilters.grid(row=4, column=1, padx=2, pady=2, sticky="NSWE")
lbl3 = Label(window, text="Макс. итерации", font=("Arial", 14)) lbl3.grid(column=1, row=1, sticky='W') txt3 = Entry(window, width=15) txt3.configure(background='LightSteelBlue4') txt3.insert(0, '500') txt3.grid(column=1, row=1) lbl4 = Label(window, text="Начальная точка", font=("Arial", 14)) lbl4.grid(column=1, row=2, sticky='W') txt4 = Entry(window, width=15) txt4.configure(background='LightSteelBlue4') txt4.insert(0, '0 0 0 0 0 0') txt4.grid(column=1, row=2) chk4_state = IntVar() chk4_state.set(1) chk4 = Checkbutton(window, text="Задать автоматически", var=chk4_state) chk4.grid(column=1, row=2, sticky='E') scroll_txt = scrolledtext.ScrolledText(window, width=100, height=27, pady=5, padx=5) scroll_txt.configure(background='LightSteelBlue4') scroll_txt.grid(column=0, row=3) fig = Figure() ax = fig.add_subplot(111) ax.set_xlabel("X axis") ax.set_ylabel("Y axis") ax.grid()
#class checkbox: # def _init_(self, name, state): # self.name = name # self.state = BooleanVar() # self.state.set(False) # задайте проверку состояния чекбокса #def set_state(state): # name = BooleanVar() #name.set(False) window = Tk() window.title("Выберите параметры анализа текста") window.geometry('400x400') chk_state1 = BooleanVar() chk_state1.set(False) # задайте проверку состояния чекбокса chk1 = Checkbutton(window, text='Выравнивание абзаца', var=chk_state1) chk1.grid(column=0, row=0) chk_state2 = BooleanVar() chk_state2.set(False) chk2 = Checkbutton(window, text='Отступ перед абзацем(см)', var=chk_state2) chk2.grid(column=0, row=1) chk_state3 = BooleanVar() chk_state3.set(False) chk3 = Checkbutton(window, text='Отступ после абзаца(см)', var=chk_state3) chk3.grid(column=0, row=2) chk_state4 = BooleanVar() chk_state4.set(False) chk4 = Checkbutton(window, text='Отступ слева(см)', var=chk_state4) chk4.grid(column=0, row=3) chk_state5 = BooleanVar() chk_state5.set(False)
def new_frame(self, schema, frame, data, sch): max_cols = 0 max_rows = 0 is_grid = False for key, value in schema.items(): type_ = value.pop("type", "") if type_ == "frame" or type_ == "group": is_grid = True children = value.pop("children", {}) pos = value.pop("pos", {}) new_frame = Frame(master=frame, borderwidth=1, relief="raised") new_frame.grid(sticky="nsew", **pos) max_cols = max(max_cols, pos.get("column", 0) + pos.get("columnspan", 1)) max_rows = max(max_rows, pos.get("row", 0) + pos.get("rowspan", 1)) Label(master=new_frame, text=value.pop("label", key), font=("Helvetica", 11, "bold")).pack(fill="x", pady=4) if type_ == "group": new_frame = Frame(master=new_frame) new_frame.pack(fill="both", expand=True) sch[key] = {"__frame__": new_frame} data[key] = {} self.new_frame(children, new_frame, data[key], sch[key]) continue default = value.pop("default", None) data[key] = None if type_ == "str": self.insert_label(frame, value, key) sch[key] = Entry(master=frame, validate="all", validatecommand=(self.register( lambda v, d=data, k=key: \ self.validate_entry(v, d, k)), "%P" ) ) if value.get("password", False): sch[key].config(show="*") sch[key].pack(fill="x", padx=10) if isinstance(default, str): sch[key].insert(0, default) data[key] = default elif type_ == "int": self.insert_label(frame, value, key) kind = value.pop("kind", "regular") sch[key] = Entry(master=frame, validate="all", validatecommand=(self.register( lambda v, d=data, k=key: \ self.validate_entry(v, d, k, int)), "%P" ) ) sch[key].pack(fill="x", padx=10) if isinstance(default, int): sch[key].insert(0, str(default)) data[key] = default elif type_ == "float": self.insert_label(frame, value, key) sch[key] = Entry(master=frame, validate="all", validatecommand=(self.register( lambda v, d=data, k=key: \ self.validate_entry(v, d, k, float)), "%P" ) ) sch[key].pack(fill="x", padx=10) if isinstance(default, float): sch[key].insert(0, str(default)) data[key] = default elif type_ == "bool": data[key] = False frm = Frame(master=frame) frm.pack(fill="x", padx=10) Label(master=frm, text=value.pop("label", key), font=("Helvetica", 9, "bold")).pack(side="left") sch[key] = Checkbutton( master=frm, text="", command=lambda d=data, k=key: self.change_bool(d, k)) sch[key].pack(side="left") Label(master=frm, text="").pack(fill="x", side="left", expand=True) if isinstance(default, bool): data[key] = default if default: sch[key] # .select() elif type_ == "choice": self.insert_label(frame, value, key) values = value.pop("values", []) sch[key] = Combobox(master=frame, values=values) sch[key].pack(fill="x", padx=10) sch[key].bind("<<ComboboxSelected>>", lambda e, s=sch[key], d=data, k=key: \ self.change_choice(s,d,k) ) sch[key].current() if isinstance(default, str): sch[key].current(values.index(default)) data[key] = default elif type_ == "file" or type_ == "folder": self.insert_label(frame, value, key) frm = Frame(master=frame) frm.pack(fill="x", padx=10) sch[key] = Label(master=frm, relief="sunken", borderwidth=1, anchor="w") sch[key].pack(fill="both", side="left", expand=True) Button( master=frm, text="...", command=lambda s=sch[key], d=data, k=key, t=type_: \ self.select_folder(s, d, k, t), # padx=0, # pady=0 ).pack(side=LEFT) if isinstance(default, str): sch[key]["text"] = default data[key] = default elif type_ == "button": sch[key] = Button(master=frame, text=value.pop("text", key)) sch[key].pack(fill="x", padx=10) del data[key] if is_grid: frame.columnconfigure(list(range(max_cols)), weight=1) frame.rowconfigure(list(range(max_rows)), weight=1) else: try: Label(master=frame, text=" ").pack() except: pass
def build(self): self.rbs = [] self.rbs1 = [] self.lF0 = lF0 = LabelFrame(self.fr, text='Widget and Themes') lF0.grid(row=0, column=0, sticky='nw') self.fr1 = fr1 = Frame(lF0) fr1.grid(row=0, column=0, sticky='nw') # create check box to select reverse selection order self.lF12 = lF12 = LabelFrame(fr1, text='Select Widget before Theme') lF12.grid(row=0, column=0, sticky='nw') self.ord = ord = IntVar() ord.set(0) cbut3 = Checkbutton(lF12, text='Reverse selection order', variable=ord, command=self.selord) cbut3.grid(row=0, column=0, padx=5, pady=5) cbut3.state(['!selected']) # create a Combobox to choose widgets widget_sel = [ 'Button', 'Checkbutton', 'Combobox', 'Entry', 'Frame', 'Label', 'LabelFrame', 'Menubutton', 'Notebook', 'PanedWindow', 'Progressbar', 'Radiobutton', 'Scale', 'Scrollbar', 'Separator', 'Sizegrip', 'Treeview' ] ord = self.ord self.lf6 = LabelFrame(self.fr1, text='Select Widget', style="RoundedFrame", padding=(10, 1, 10, 10)) self.lf6.grid(row=1, column=0, sticky='nw') self.lf6.state([("focus" if self.ord.get() == 0 else "!focus")]) self.widget_value = StringVar() self.cb = Combobox( self.lf6, values=widget_sel, textvariable=self.widget_value, state=('disabled' if self.ord.get() == 1 else 'active')) self.cb.grid(row=0, column=0, padx=5, pady=5, sticky='nw') self.cb.bind('<<ComboboxSelected>>', self.enabled) # create a Radio Buttons to choose orientation fr2 = Frame(self.lF0) fr2.grid(row=0, column=1, sticky='nw') self.lF5 = lF5 = LabelFrame( fr2, style="RoundedFrame", padding=(10, 1, 10, 10), text='Orientation of \nProgressbar \nScale \nScrollbar') lF5.grid(row=0, column=0, padx=5, pady=5, sticky='nw') self.orient = StringVar() orientT = ['Horizontal', 'Vertical'] for ix, val in enumerate(orientT): rb = Radiobutton(lF5, text=val, value=val, command=self.orient_command, variable=self.orient, state='disabled') rb.grid(row=ix, column=0, sticky='w') self.rbs.append(rb) # create Radio Buttons to choose themes themes = { "alt": "alt - standard", "clam": "clam - standard", "classic": "classic - standard", "default": "default - standard" } self.lF1 = LabelFrame(self.fr1, text='Select Theme', style="RoundedFrame", padding=(10, 1, 10, 10)) self.lF1.grid(row=2, column=0, sticky='n') self.theme_value = StringVar() for ix, val in enumerate(themes): rb1 = Radiobutton(self.lF1, text=themes[val], value=val, state='disabled', variable=self.theme_value, command=self.theme_command) rb1.grid(row=ix, column=0, padx=10, sticky='nw') self.rbs1.append(rb1)
class MSControls(Frame): #TODO: select parameters for small Multiples when len(cluster_params)>6 def __init__(self, parent,plot, params, k=1): super(MSControls, self).__init__(parent)#,text="Scatterplot-Options") self.params=params self.plot=plot #type:SimpleScatter self.k=k self.clusel=Label(self) apply_changes=self.plot.apply_settings #background self.wbvar = StringVar(value="0") self.whibla = Checkbutton(self, text='Black Background', command=apply_changes, variable=self.wbvar) self.whibla.grid(column=0, row=4, sticky=(W, N), columnspan=2) #Dot settings frm = Frame(self) frm.grid(column=0, row=5, sticky=(W, N, E), columnspan=2) frm.columnconfigure(2,weight=1) Label(frm,text="alpha:").grid(column=0, row=0, sticky=(N, E)) Label(frm,text="dotsize:").grid(column=3, row=0, sticky=(N, E)) self.alpha=StringVar(self,value="0.2") self.s=StringVar(self,value="4") Spinbox(frm,from_=0.05, to=1, increment=0.05, command=apply_changes, textvariable=self.alpha,width=4)\ .grid(column=1, row=0, sticky=(W, E)) Spinbox(frm,from_=0.5, to=20, increment=0.5 , command=apply_changes, textvariable=self.s,width=4)\ .grid(column=4, row=0, sticky=(W, E)) Button(frm,text="Apply", command=apply_changes)\ .grid(column=0, row=1, sticky=(N, E,W), columnspan=5) def set_new_cols(self, newcols): self.params=newcols def set_new_cluster(self, k): if self.k == k or (self.k<=1 and k<=1): return self.clusel.destroy() self.clusel=ClusterSelect(self,self.plot,k) self.clusel.grid(column=0, row=6, sticky=(N, E,W), columnspan=2) def do_white_on_black(self): return self.wbvar.get() is not "0" def get_alpha(self): return float(self.alpha.get()) def get_s(self): return float(self.s.get()) def get_cols(self): pass
def set_config(): sys_para = sys.argv file_path = os.path.split(sys_para[0])[0] gui = False if platform.uname()[0] == 'Windows': # Win默认打开 gui = True if platform.uname()[0] == 'Linux': # Linux 默认关闭 gui = False if '--gui' in sys.argv: # 指定 gui 模式 gui = True if '--nogui' in sys.argv: # 带 nogui 就覆盖前面Win打开要求 gui = False config_file = os.path.join(file_path, 's3_download_config.ini') # If no config file, read the default config if not os.path.exists(config_file): config_file += '.default' print("No customized config, use the default config") cfg = ConfigParser() print(f'Reading config file: {config_file}') try: global SrcBucket, S3Prefix, SrcFileIndex, SrcProfileName, DesDir, MaxRetry, MaxThread, MaxParallelFile, LoggingLevel cfg.read(config_file, encoding='utf-8-sig') SrcBucket = cfg.get('Basic', 'SrcBucket') S3Prefix = cfg.get('Basic', 'S3Prefix') SrcFileIndex = cfg.get('Basic', 'SrcFileIndex') SrcProfileName = cfg.get('Basic', 'SrcProfileName') DesDir = cfg.get('Basic', 'DesDir') Megabytes = 1024 * 1024 ChunkSize = cfg.getint('Advanced', 'ChunkSize') * Megabytes MaxRetry = cfg.getint('Advanced', 'MaxRetry') MaxThread = cfg.getint('Advanced', 'MaxThread') MaxParallelFile = cfg.getint('Advanced', 'MaxParallelFile') LoggingLevel = cfg.get('Advanced', 'LoggingLevel') except Exception as e: print("ERR loading s3_download_config.ini", str(e)) input('PRESS ENTER TO QUIT') sys.exit(0) if gui: # For GUI from tkinter import Tk, filedialog, END, StringVar, BooleanVar, messagebox from tkinter.ttk import Combobox, Label, Button, Entry, Spinbox, Checkbutton # get profile name list in ./aws/credentials pro_conf = RawConfigParser() pro_path = os.path.join(os.path.expanduser("~"), ".aws") cre_path = os.path.join(pro_path, "credentials") if os.path.exists(cre_path): pro_conf.read(cre_path) profile_list = pro_conf.sections() else: print( f"There is no aws_access_key in {cre_path}, please input for S3 Bucket: " ) os.mkdir(pro_path) aws_access_key_id = input('aws_access_key_id: ') aws_secret_access_key = input('aws_secret_access_key: ') region = input('region: ') pro_conf.add_section('default') pro_conf['default']['aws_access_key_id'] = aws_access_key_id pro_conf['default'][ 'aws_secret_access_key'] = aws_secret_access_key pro_conf['default']['region'] = region profile_list = ['default'] with open(cre_path, 'w') as f: print(f"Saving credentials to {cre_path}") pro_conf.write(f) # Click Select Folder def browse_folder(): local_dir = filedialog.askdirectory( initialdir=os.path.dirname(__file__)) url_txt.delete(0, END) url_txt.insert(0, local_dir) file_txt.delete(0, END) file_txt.insert(0, "*") # Finsih browse folder # Click List Buckets def ListBuckets(*args): SrcProfileName = SrcProfileName_txt.get() client = Session(profile_name=SrcProfileName).client('s3') bucket_list = [] try: response = client.list_buckets() if 'Buckets' in response: bucket_list = [b['Name'] for b in response['Buckets']] except Exception as e: messagebox.showerror( 'Error', f'Failt to List buckets. \n' f'Please verify your aws_access_key of profile: [{SrcProfileName}]\n' f'{str(e)}') bucket_list = ['CAN_NOT_GET_BUCKET_LIST'] SrcBucket_txt['values'] = bucket_list SrcBucket_txt.current(0) # Finish ListBuckets # Click List Prefix def ListPrefix(*args): SrcProfileName = SrcProfileName_txt.get() client = Session(profile_name=SrcProfileName).client('s3') prefix_list = [] this_bucket = SrcBucket_txt.get() max_get = 100 try: response = client.list_objects_v2( Bucket=this_bucket, Delimiter='/' ) # Only get the max 1000 prefix for simply list if 'CommonPrefixes' in response: prefix_list = [ c['Prefix'] for c in response['CommonPrefixes'] ] if not prefix_list: messagebox.showinfo( 'Message', f'There is no "/" Prefix in: {this_bucket}') if response['IsTruncated']: messagebox.showinfo( 'Message', f'More than {max_get} Prefix, cannot fully list here.') except Exception as e: messagebox.showinfo( 'Error', f'Cannot get prefix list from bucket: {this_bucket}, {str(e)}' ) S3Prefix_txt['values'] = prefix_list S3Prefix_txt.current(0) # Finish list prefix def browse_file(*args): SrcProfileName = SrcProfileName_txt.get() S3Prefix = S3Prefix_txt.get() client = Session(profile_name=SrcProfileName).client('s3') file_list = [] this_bucket = SrcBucket_txt.get() max_get = 100 try: response = client.list_objects_v2( Bucket=this_bucket, Prefix=str(PurePosixPath(S3Prefix)) + '/', Delimiter='/' ) # Only get the max 1000 files for simply list # For delete prefix in des_prefix if S3Prefix == '' or S3Prefix == '/': # 目的bucket没有设置 Prefix dp_len = 0 else: # 目的bucket的 "prefix/"长度 dp_len = len(str(PurePosixPath(S3Prefix))) + 1 if 'Contents' in response: file_list = [ c['Key'][dp_len:] for c in response['Contents'] ] # 去掉Prefix if not file_list: messagebox.showinfo( 'Message', f'There is no files in s3://{this_bucket}/{S3Prefix}') if response['IsTruncated']: messagebox.showinfo( 'Message', f'More than {max_get} files, cannot fully list here.') except Exception as e: messagebox.showinfo( 'Error', f'Cannot get file list from bucket s3://{this_bucket}/{S3Prefix}, {str(e)}' ) file_txt['values'] = file_list file_txt.current(0) # Finish list files # Click START button def close(): window.withdraw() ok = messagebox.askokcancel( 'Start downloading job', f'DOWNLOAD FROM s3://{SrcBucket_txt.get()}/{S3Prefix_txt.get()}\n' f'TO LOCAL {url_txt.get()}\n' f'Click OK to START') if not ok: window.deiconify() return window.quit() return # Finish close() # Start GUI window = Tk() window.title( "LONGBOW - AMAZON S3 DOWNLOAD TOOL WITH BREAK-POINT RESUMING") window.geometry('705x350') window.configure(background='#ECECEC') window.protocol("WM_DELETE_WINDOW", sys.exit) Label(window, text="S3 Bucket").grid(column=0, row=1, sticky='w', padx=2, pady=2) SrcBucket_txt = Combobox(window, width=48) SrcBucket_txt.grid(column=1, row=1, sticky='w', padx=2, pady=2) SrcBucket_txt['values'] = SrcBucket SrcBucket_txt.current(0) Button(window, text="List Buckets", width=10, command=ListBuckets) \ .grid(column=2, row=1, sticky='w', padx=2, pady=2) Label(window, text="S3 Prefix").grid(column=0, row=2, sticky='w', padx=2, pady=2) S3Prefix_txt = Combobox(window, width=48) S3Prefix_txt.grid(column=1, row=2, sticky='w', padx=2, pady=2) S3Prefix_txt['values'] = S3Prefix if S3Prefix != '': S3Prefix_txt.current(0) Button(window, text="List Prefix", width=10, command=ListPrefix) \ .grid(column=2, row=2, sticky='w', padx=2, pady=2) Label(window, text="Filename or *").grid(column=0, row=3, sticky='w', padx=2, pady=2) file_txt = Combobox(window, width=48) file_txt.grid(column=1, row=3, sticky='w', padx=2, pady=2) file_txt['values'] = SrcFileIndex if SrcFileIndex != '': file_txt.current(0) Button(window, text="Select File", width=10, command=browse_file) \ .grid(column=2, row=3, sticky='w', padx=2, pady=2) Label(window, text="AWS Profile").grid(column=0, row=4, sticky='w', padx=2, pady=2) SrcProfileName_txt = Combobox(window, width=15, state="readonly") SrcProfileName_txt['values'] = tuple(profile_list) SrcProfileName_txt.grid(column=1, row=4, sticky='w', padx=2, pady=2) if SrcProfileName in profile_list: position = profile_list.index(SrcProfileName) SrcProfileName_txt.current(position) else: SrcProfileName_txt.current(0) SrcProfileName = SrcProfileName_txt.get() SrcProfileName_txt.bind("<<ComboboxSelected>>", ListBuckets) Label(window, text="Folder").grid(column=0, row=5, sticky='w', padx=2, pady=2) url_txt = Entry(window, width=50) url_txt.grid(column=1, row=5, sticky='w', padx=2, pady=2) url_btn = Button(window, text="Select Folder", width=10, command=browse_folder) url_btn.grid(column=2, row=5, sticky='w', padx=2, pady=2) url_txt.insert(0, DesDir) Label(window, text="MaxThread/File").grid(column=0, row=6, sticky='w', padx=2, pady=2) if MaxThread < 1 or MaxThread > 100: MaxThread = 5 var_t = StringVar() var_t.set(str(MaxThread)) MaxThread_txt = Spinbox(window, from_=1, to=100, width=15, textvariable=var_t) MaxThread_txt.grid(column=1, row=6, sticky='w', padx=2, pady=2) Label(window, text="MaxParallelFile").grid(column=0, row=7, sticky='w', padx=2, pady=2) if MaxParallelFile < 1 or MaxParallelFile > 100: MaxParallelFile = 5 var_f = StringVar() var_f.set(str(MaxParallelFile)) MaxParallelFile_txt = Spinbox(window, from_=1, to=100, width=15, textvariable=var_f) MaxParallelFile_txt.grid(column=1, row=7, sticky='w', padx=2, pady=2) save_config = BooleanVar() save_config.set(True) save_config_txt = Checkbutton(window, text="Save to s3_download_config.ini", var=save_config) save_config_txt.grid(column=1, row=9, padx=2, pady=2) Button(window, text="Start Download", width=15, command=close).grid(column=1, row=10, padx=5, pady=5) window.mainloop() DesDir = url_txt.get() SrcFileIndex = file_txt.get() SrcBucket = SrcBucket_txt.get() S3Prefix = S3Prefix_txt.get() SrcProfileName = SrcProfileName_txt.get() MaxThread = int(MaxThread_txt.get()) MaxParallelFile = int(MaxParallelFile_txt.get()) if save_config: cfg['Basic']['SrcBucket'] = SrcBucket cfg['Basic']['S3Prefix'] = S3Prefix cfg['Basic']['SrcFileIndex'] = SrcFileIndex cfg['Basic']['SrcProfileName'] = SrcProfileName cfg['Basic']['DesDir'] = DesDir cfg['Advanced']['MaxThread'] = str(MaxThread) cfg['Advanced']['MaxParallelFile'] = str(MaxParallelFile) config_file = os.path.join(file_path, 's3_download_config.ini') with codecs.open(config_file, 'w', 'utf-8') as f: cfg.write(f) print(f"Save config to {config_file}") # GUI window finish if S3Prefix == '/': S3Prefix = '' # Finish set_config() return ChunkSize
def __init__(self, master=None, load_settings=None): tk.Frame.__init__(self, master=master) self.master = master if load_settings is None: load_settings = Settings(preset=None) ls = load_settings # TODO: Toggle displaying px or inches # TODO: Configure ppi (when displaying inches) ################################# # DIMENSIONS / MARGINS ################################# dim_frame = tk.Frame(self) dim_frame.grid(row=self.DIM_ROW, column=1, sticky='w') self.page_width = self.IntVarSetter(dim_frame, var_name='RAW_width', display_name='Page Width', start_val=ls.dim[0]) self.page_width.grid(row=0, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') self.page_height = self.IntVarSetter(dim_frame, var_name='RAW_width', display_name='Page Height', start_val=ls.dim[1]) self.page_height.grid(row=0, column=2, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') # Main margins next_avail_row = self.GRID_MARG_FIRST_ROW self.y_top_marg = self.IntVarSetter(self, var_name='y_top_marg', display_name='Upper Margin (Grid)', start_val=ls.y_top_marg) self.y_top_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.y_bottom_marg = self.IntVarSetter( self, var_name='y_bottom_marg', start_val=ls.y_bottom_marg, display_name='Bottom Margin (Entire Page)') self.y_bottom_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.qq_side = self.QQSideSetter( self, var_name='qq_side', display_name='Side length of each QQ square', start_val=ls.qq_side) self.qq_side.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') # TODO: Display left/right margins that are left after this setting # TODO: Optional set-by-LR-margin. next_avail_row += 1 cb_text = ('Size of area to clear at center of each ' 'section for writing section number') self.centerbox_wh = self.IntVarSetter(self, var_name='centerbox_wh', display_name=cb_text, start_val=ls.centerbox_wh) self.centerbox_wh.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 ################################# # CONFIGURE LINES / FILL ################################# self.qq_fill_RGBA = self.QQColorSetter(self, RGBA=ls.qq_fill_RGBA) self.qq_fill_RGBA.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 next_avail_row = self.LINE_CONFIG_FIRST_ROW self.sec_line = self.LineSetter(self, var_name='sec_line', display_name='Section Line', stroke=ls.sec_line_stroke, RGBA=ls.sec_line_RGBA) self.sec_line.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.ql_line = self.LineSetter(self, var_name='ql', display_name='Half-Dividing Line', stroke=ls.ql_stroke, RGBA=ls.ql_RGBA) self.ql_line.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.qql_line = self.LineSetter(self, var_name='qql', display_name='Quarter-Dividing Line', stroke=ls.qql_stroke, RGBA=ls.qql_RGBA) self.qql_line.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 ################################# # WHAT TO WRITE / FONTS / TEXT CONFIGURE ################################# self.write_header = tk.BooleanVar(self, value=ls.write_header, name='write_header') self.write_header_chkbtn = Checkbutton( self, text='Write Header in Top Margin', onvalue=True, offvalue=False, variable=self.write_header) self.write_header_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.headerfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.header_font = self.FontSetter(self, font_size=ls.headerfont_size, display_name='Header Font', var_name='headerfont', typeface=tf, RGBA=ls.headerfont_RGBA) self.header_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.y_header_marg = self.IntVarSetter( self, var_name='y_header_marg', start_val=ls.y_header_marg, display_name= 'How far above grid to write header (within top margin)') self.y_header_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.write_section_numbers = tk.BooleanVar( self, value=ls.write_section_numbers, name='write_section_numbers') self.write_section_numbers_chkbtn = Checkbutton( self, text='Write Section Numbers', onvalue=True, offvalue=False, variable=self.write_section_numbers) self.write_section_numbers_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.secfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.section_numbers_font = self.FontSetter( self, font_size=ls.secfont_size, display_name='Section Number Font', var_name='secfont', typeface=tf, RGBA=ls.secfont_RGBA) self.section_numbers_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.write_lot_numbers = tk.BooleanVar(self, value=ls.write_lot_numbers, name='write_lot_numbers') self.write_lot_numbers_chkbtn = Checkbutton( self, text='Write lot numbers within the appropriate QQ(s)', onvalue=True, offvalue=False, variable=self.write_lot_numbers) self.write_lot_numbers_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.lotfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.lot_font = self.FontSetter(self, font_size=ls.lotfont_size, display_name='Lot Number Font', var_name='lotfont', typeface=tf, RGBA=ls.lotfont_RGBA) self.lot_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 self.lot_num_offset_px = self.IntVarSetter( self, var_name='lot_num_offset_px', start_val=ls.lot_num_offset_px, display_name= 'Lot number distance from top-left corner of QQ (in px)') self.lot_num_offset_px.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.write_tracts = tk.BooleanVar(self, value=ls.write_tracts, name='write_tracts') self.write_tracts_chkbtn = Checkbutton( self, text='Write all tracts at the bottom', onvalue=True, offvalue=False, variable=self.write_tracts) self.write_tracts_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 tf = _EditorFrame.TYPEFACES_BY_FP.get(ls.tractfont_typeface, _EditorFrame.DEFAULT_FONT_KEY) self.tract_font = self.FontSetter(self, font_size=ls.tractfont_size, display_name='Tract Font', var_name='tractfont', typeface=tf, RGBA=ls.tractfont_RGBA) self.tract_font.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 # A customized RGBASetter for warningfont_RGBA, since we don't # need to set typeface or size: wfont_txt = 'Font color for writing errors/warnings' self.warning_font_RGBA = _EditorFrame.RGBASetter( self, display_name=wfont_txt, show_opacity=False, var_name='warningfont_RGBA', RGBA=ls.warningfont_RGBA) self.warning_font_RGBA.rgba_frame.grid(row=0, column=1) lbl = tk.Label(self.warning_font_RGBA, text=wfont_txt) lbl.grid(row=0, column=0) self.warning_font_RGBA.grid(row=next_avail_row, column=1, sticky='w') next_avail_row += 1 ################################# # TractTextBox margins and other tract-writing configurables ################################# self.y_px_before_tracts = self.IntVarSetter( self, var_name='y_px_before_tracts', start_val=ls.y_px_before_tracts, display_name= 'Distance between bottom of the grid and the first written tract') self.y_px_before_tracts.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.x_text_left_marg = self.IntVarSetter( self, var_name='x_text_left_marg', start_val=ls.x_text_left_marg, display_name='Left Margin (for tract text below grid)') self.x_text_left_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.x_text_right_marg = self.IntVarSetter( self, var_name='x_text_right_marg', start_val=ls.x_text_right_marg, display_name='Right Margin (for tract text below grid)') self.x_text_right_marg.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.y_px_between_tracts = self.IntVarSetter( self, var_name='y_px_between_tracts', start_val=ls.y_px_between_tracts, display_name='Space between lines of text') self.y_px_between_tracts.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.paragraph_indent = self.IntVarSetter( self, var_name='paragraph_indent', start_val=ls.paragraph_indent, display_name='Paragraph indent (in spaces, not pixels or inches)') self.paragraph_indent.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.new_line_indent = self.IntVarSetter( self, var_name='new_line_indent', start_val=ls.new_line_indent, display_name='Linebreak indent (in spaces, not pixels or inches)') self.new_line_indent.grid(row=next_avail_row, column=1, padx=self.MW_PADX, pady=self.MW_PADY, sticky='w') next_avail_row += 1 self.justify_tract_text = tk.BooleanVar(self, value=ls.justify_tract_text, name='justify_tract_text') self.justify_tract_text_chkbtn = Checkbutton( self, text='Justify tract text', onvalue=True, offvalue=False, variable=self.justify_tract_text) self.justify_tract_text_chkbtn.grid(row=next_avail_row, column=1, sticky='w', padx=self.MW_PADX, pady=self.MW_PADY) next_avail_row += 1 # Set the bool variables, according to the attributes in `ls` # (i.e. enact the settings in the `load_settings` object). # Note: This is not optimal design, but it seems to solve a # weird bug. Back when these values were set at the time that # the variables/checkbuttons themselves were created, the # _EditorFrame would fail to actually set them (to either True # or False), maybe 5% of the time. When clicking "Load Preset" # button repeatedly, with nothing different, would sometimes get # different results, and I could not reliably recreate the bug. # This is ineligant, but seems(?) to fix it... for var_name in [ 'write_header', 'write_section_numbers', 'write_lot_numbers', 'write_tracts', 'justify_tract_text' ]: getattr(self, var_name).set(getattr(ls, var_name))
class MainWindow: def __init__(self) -> None: self.Root = Tk() self.App = Frame(self.Root, padding=(5, 2)) self.UpdatesFrame = LabelFrame(self.App, text=L.UpdatesFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.upd_enabled = BooleanVar() # Флаг обновлений self.upd_unit = StringVar() # Единица измерения времени self.time_units = { Minutes: L.Minutes, Hours: L.Hours, Days: L.Days, Weeks: L.Weeks, Months: L.Months } self.size_units = { Bytes: L.Bytes, KBytes: L.KBytes, MBytes: L.MBytes, GBytes: L.GBytes, TBytes: L.TBytes } # Список единиц измерения времени self.maxfsize = StringVar() # Максимальный размер файла self.size_unit = StringVar() # Единица измерения информации self.units_amount1 = StringVar() # Количество единиц self.quar = BooleanVar() # False - удалять, True - карантин self.quar_path = StringVar() # Расположение карантина self.rpt_enabled = BooleanVar() # Флаг отправки отчета self.email = StringVar() # Адрес отправки self.passwd = StringVar() # Пароль исходящего ящика self.rpt_unit = StringVar() # Единица измерения времени self.units_amount2 = StringVar() # Количество единиц self.Upd_Label1 = Label(self.UpdatesFrame, text=L.Upd_Label1) self.Upd_Checkbutton1 = Checkbutton(self.UpdatesFrame, variable=self.upd_enabled) self.Upd_Label2 = Label(self.UpdatesFrame, text=L.Upd_Label2) self.Upd_Spinbox1 = Spinbox(self.UpdatesFrame, textvariable=self.units_amount1, from_=1, to=999999999, width=4) self.Upd_OptionMenu1 = OptionMenu(self.UpdatesFrame, self.upd_unit, *self.time_units.values()) self.Upd_Button1 = Button( self.UpdatesFrame, text=L.Upd_Button1, command=lambda: EntryOptionsWindow('AV_SOURCES', self.Root)) self.ScanFrame = LabelFrame(self.App, text=L.ScanFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.Scn_Label1 = Label(self.ScanFrame, text=L.Scn_Label1) self.Scn_Spinbox1 = Spinbox(self.ScanFrame, textvariable=self.maxfsize, from_=0, to=999999999, width=8) self.Quar_Label = Label(self.ScanFrame, text=L.Quar_Label) self.Quar_RadButton1 = Radiobutton(self.ScanFrame, text=L.Quar_RadButton1, variable=self.quar, value=False) self.Quar_RadButton2 = Radiobutton(self.ScanFrame, text=L.Quar_RadButton2, variable=self.quar, value=True) self.Scn_OptionMenu1 = OptionMenu(self.ScanFrame, self.size_unit, *self.size_units.values()) self.Scn_Edit_Targets = Button( self.ScanFrame, text=L.Scn_Edit_Targets, command=lambda: EntryOptionsWindow( 'SCAN_TARGETS', self.Root, select_path=True)) self.Scn_Edit_Exceptions = Button( self.ScanFrame, text=L.Scn_Edit_Exceptions, command=lambda: EntryOptionsWindow('SCAN_EXCLUDE', self.Root)) self.Quar_Button1 = Button( self.ScanFrame, text=L.Quar_Button1, command=lambda: self.quar_path.set(filedialog.askdirectory())) self.ReportFrame = LabelFrame(self.App, text=L.ReportFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.Rpt_Label1 = Label(self.ReportFrame, text=L.Rpt_Label1) self.Rpt_Checkbutton1 = Checkbutton(self.ReportFrame, variable=self.rpt_enabled) self.Rpt_Label2 = Label(self.ReportFrame, text=L.Rpt_Label2) self.Rpt_Entry1 = Entry(self.ReportFrame, textvariable=self.email, width=32) self.Rpt_Label3 = Label(self.ReportFrame, text=L.Rpt_Label3) self.Rpt_Entry2 = Entry(self.ReportFrame, textvariable=self.passwd, width=32, show='*') self.Rpt_Label4 = Label(self.ReportFrame, text=L.Rpt_Label4) self.Rpt_Spinbox1 = Spinbox(self.ReportFrame, textvariable=self.units_amount2, from_=1, to=999999999, width=4) self.Rpt_OptionMenu1 = OptionMenu(self.ReportFrame, self.rpt_unit, *self.time_units.values()) self.Rpt_Button1 = Button( self.ReportFrame, text=L.Rpt_Button1, command=lambda: EntryOptionsWindow('SEND_TO', self.Root)) self.Buttons = Frame(self.App, padding=(5, 2)) self.Button1 = Button(self.Buttons, text=L.Done, command=self.save_conf) self.Button2 = Button(self.Buttons, text=L.Cancel, command=self.Root.destroy) def main(self) -> None: self.upd_unit.set(self.time_units[type(UPDATE_FREQ)]) self.units_amount1.set(UPDATE_FREQ.value) self.upd_enabled.set(CHECK_FOR_UPDATES) self.Upd_Checkbutton1.configure(command=(lambda: self.__change_state( self.upd_enabled, self.Upd_Label2, self.Upd_Spinbox1, self. Upd_OptionMenu1, self.Upd_Button1) and self.upd_enabled.set( not self.upd_enabled.get()))) self.Rpt_Checkbutton1.configure(command=(lambda: self.__change_state( self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self. Rpt_Label3, self.Rpt_Entry2, self.Rpt_Label4, self.Rpt_Spinbox1, self.Rpt_OptionMenu1, self.Rpt_Button1) and self.rpt_enabled.set( not self.rpt_enabled.get()))) self.maxfsize.set(MAX_FILE_SIZE.value) self.size_unit.set(self.size_units[type(MAX_FILE_SIZE)]) self.quar.set(REMOVE_THREATS) self.quar_path.set(QUARANTINE_PATH) self.rpt_enabled.set(SEND_SCAN_REPORTS) self.email.set(SEND_FROM) try: with open('/root/.cobpwd', 'r') as f: self.passwd.set(f.read()) except FileNotFoundError: pass self.rpt_unit.set(self.time_units[type(SEND_FREQ)]) self.units_amount2.set(SEND_FREQ.value) self.App.pack(fill='both', expand=True) center_win(self.Root, '500x500') self.Root.resizable(False, False) self.Root.title('CobraAV Configuration') self.UpdatesFrame.place(y=0, height=150, width=490) self.__change_state(self.upd_enabled, self.Upd_Label2, self.Upd_Spinbox1, self.Upd_OptionMenu1) self.__change_state(self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self.Rpt_Label3, self.Rpt_Entry2, self.Rpt_Label4, self.Rpt_Spinbox1, self.Rpt_OptionMenu1, self.Rpt_Button1) self.Upd_Label1.place(relx=.01, rely=.05) # Проверять обновления ? self.Upd_Checkbutton1.place(relx=.8, rely=.05) # Да/Нет self.Upd_Label2.place(relx=.01, rely=.3) # Частота проверки self.Upd_Spinbox1.place(relx=.55, rely=.3, width=60) # Количество self.Upd_OptionMenu1.place(relx=.72, rely=.28) # Единицы измерения self.Upd_Button1.place(relx=.01, rely=.65) # Источники сигнатур self.ScanFrame.place(y=150, height=150, width=490) self.Scn_Label1.place(relx=.01, rely=.05) # Максимальный размер файла self.Scn_Spinbox1.place(relx=.55, rely=.05, width=60) # Количество self.Quar_Label.place(relx=.01, rely=.35) self.Quar_RadButton1.place( relx=.52, rely=.35) # Переключатель на удаление угрозы self.Quar_RadButton2.place( relx=.72, rely=.35) # Переключатель на добавление вкарантина угрозы self.Quar_Button1.place(relx=.56, rely=.65) # Расположение карантина self.Scn_OptionMenu1.place(relx=.72, rely=.014) # Единицы измерения self.Scn_Edit_Targets.place(relx=.01, rely=.65) # Цели сканирования self.Scn_Edit_Exceptions.place(relx=.33, rely=.65) # Исключения self.Rpt_Label1.place(relx=.01, rely=.05) # Отправлять отчеты ? self.Rpt_Checkbutton1.place(relx=.8, rely=.05) # Да/Нет self.ReportFrame.place(y=300, height=150, width=490) self.Rpt_Label2.place(relx=.01, rely=.35) # Адрес отправки отчетов: self.Rpt_Entry1.place(relx=.35, rely=.35) # Ввод адреса отправки отчетов self.Rpt_Label3.place(relx=.01, rely=.50) # Пароль: self.Rpt_Entry2.place(relx=.35, rely=.50) # Ввод пароля: self.Rpt_Label4.place(relx=.01, rely=.75) # Частота отправки self.Rpt_Spinbox1.place(relx=.35, rely=.75, width=60) # Количество self.Rpt_OptionMenu1.place(relx=.52, rely=.72) # Единицы измерения self.Rpt_Button1.place(relx=.72, rely=.74) # Получатели self.Buttons.place(y=450, height=50, width=490) self.Button1.place(relx=.62, rely=.2) # Кнопка "Готово" self.Button2.place(relx=.82, rely=.2) # Кнопка "Отмена" self.Root.mainloop() @staticmethod def __change_state(state: BooleanVar, *args: Widget) -> None: for i in args: i.configure(state=('disabled', 'normal')[state.get()]) def save_conf(self) -> None: size_units = {v: k for k, v in self.size_units.items()} time_units = {v: k for k, v in self.time_units.items()} def wrap_list(a: 'list[str]') -> str: return '[' + ', \n'.join(f"r'{i}'" for i in a) + ']' def wrap_cls(_unit: Variable, amount: Variable) -> str: unit = _unit.get() if unit in size_units: return size_units[unit].__name__ + f'({amount.get()})' elif unit in time_units: return time_units[unit].__name__ + f'({amount.get()})' else: raise NotImplementedError if self.upd_enabled.get() and not CHECK_FOR_UPDATES: system('systemctl enable cobra-update.service') system('systemctl restart cobra-update.service') else: system('systemctl stop cobra-update.service') system('systemctl disable cobra-update.service') if self.rpt_enabled.get() and not SEND_SCAN_REPORTS: system('systemctl enable cobra-notify.service') system('systemctl restart cobra-notify.service') else: system('systemctl stop cobra-notify.service') system('systemctl disable cobra-notify.service') with open('/root/.cobpwd', 'w') as f: f.write(self.passwd.get()) with open(CONF_PATH, 'w') as f: f.write(f"""from libunits import * CHECK_FOR_UPDATES = {int(self.upd_enabled.get())} # Check for updates UPDATE_FREQ = {wrap_cls(self.upd_unit, self.units_amount1)} # Check interval MAX_FILE_SIZE = {wrap_cls(self.size_unit, self.maxfsize)} # Max file size # Antivirus database sources AV_SOURCES = {wrap_list(AV_SOURCES)} # Antivirus database path DB_PATH = r'{DB_PATH}' # On threat: # 0 - quarantine # 1 - remove REMOVE_THREATS = {int(self.quar.get())} # Directories to scan SCAN_TARGETS = {wrap_list(SCAN_TARGETS)} # Exclude from scanning SCAN_EXCLUDE = {wrap_list(SCAN_EXCLUDE)} # quarantine location QUARANTINE_PATH = r'{self.quar_path.get() or QUARANTINE_PATH}' # Send scan reports SEND_SCAN_REPORTS = {int(self.rpt_enabled.get())} # Scan reports frequency SEND_FREQ = {wrap_cls(self.rpt_unit, self.units_amount2)} # Send from this email SEND_FROM = r'{self.email.get()}' # Send to these emails SEND_TO = {wrap_list(SEND_TO)} # SMTP settings (preset for gmail) SMTP_HOST = 'smtp.gmail.com' SMTP_PORT = 587 # GUI Language LANG = '{LANG}' """) self.Root.destroy()
def __init__(self, parent, sourceCmdGen, audioRec): Toplevel.__init__(self, parent) #self.transient(parent) self.cmdGen = sourceCmdGen self.audioRec = audioRec self.title(string="Screen Recorder - Settings") self.iconbitmap("icon.ico") self.resizable(width=False, height=False) self.minsize(400, 450) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.notebook = Notebook(self) self.notebook.grid(row=0, column=0, columnspan=4, sticky="nesw", padx=5, pady=5) ########################################### VIDEO OPTIONS ############################################## self.videoOptions = Frame(self) self.videoOptions.columnconfigure(1, weight=1) Label(self.videoOptions, text="Suggested FPS (Not guaranteed): ").grid(row=0, column=0) self.FPSVar = StringVar() self.FPSspin = Spinbox(self.videoOptions, from_=1, to=120, textvariable=self.FPSVar) self.FPSspin.grid(row=0, column=1, sticky="ew", pady=5) self.FPSVar.set(self.cmdGen.fps) self.hwaccVar = StringVar() Label( self.videoOptions, text= "Encoding (GPU encoding may improve perfomance, but also may result in corrupted files):" ).grid(row=1, column=0, columnspan=2, sticky="w") self.buttonCPU = Radiobutton(self.videoOptions, text="CPU-only encoder", variable=self.hwaccVar, value="CPU") self.buttonCPU.grid(row=2, column=0, columnspan=2, sticky="w") self.buttonNVENC = Radiobutton( self.videoOptions, text="Nvidia NVENC GPU encoder (experimental)", variable=self.hwaccVar, value="NVENC") self.buttonNVENC.grid(row=3, column=0, columnspan=2, sticky="w") if self.cmdGen.encoder == "mpeg4": self.hwaccVar.set("CPU") elif self.cmdGen.encoder == "h264_nvenc": self.hwaccVar.set("NVENC") self.drawMouseVar = IntVar() self.drawMouseVar.set(self.cmdGen.drawMouse) self.drawMouseCheck = Checkbutton(self.videoOptions, text="Draw mouse", variable=self.drawMouseVar) self.drawMouseCheck.grid(row=5, column=0, columnspan=2, sticky='w', pady=10) self.notebook.add(self.videoOptions, text="Video Options") ###################################################################################################################### ############################################### AUDIO OPTIONS ##################################################### self.audioOptions = Frame(self) self.audioOptions.columnconfigure(0, weight=1) self.audioOptions.rowconfigure(2, weight=1) self.audInputVar = StringVar() self.defaultCheck = Radiobutton( self.audioOptions, text="Record from the default device only", value="default", variable=self.audInputVar) self.defaultCheck.grid(row=0, column=0, sticky="w") self.selectedCheck = Radiobutton(self.audioOptions, text="Record from these devices:", value="selected", variable=self.audInputVar) self.selectedCheck.grid(row=1, column=0, sticky="w") self.audioDevices = Listbox(self.audioOptions, selectmode="multiple") self.audioDevices.grid(row=2, column=0, sticky='news') self.deviceIDList = [] for i in range(self.audioRec.getDeviceCount()): if self.audioRec.isInputDevice(i): self.deviceIDList.append(i) self.audioDevices.insert( "end", self.audioRec.getAPIName(i) + " || " + self.audioRec.getDeviceName(i)) if i in self.audioRec.devices: self.audioDevices.selection_set('end') self.audInputVar.trace("w", self.audButtonChange) if self.audioRec.devices == [None]: self.audInputVar.set("default") else: self.audInputVar.set("selected") self.notebook.add(self.audioOptions, text="Audio Options") #################################################################################################################### self.okButton = Button(self, text="OK", width=9, command=self.applyQuit) self.okButton.grid(row=1, column=1, padx=4, pady=4) self.cancelButton = Button(self, text="Cancel", width=9, command=self.destroy) self.cancelButton.grid(row=1, column=2, padx=4, pady=4) self.applyButton = Button(self, text="Apply", width=9, command=self.apply) self.applyButton.grid(row=1, column=3, padx=4, pady=4) self.grab_set() self.focus()
def __init__(self) -> None: self.Root = Tk() self.App = Frame(self.Root, padding=(5, 2)) self.UpdatesFrame = LabelFrame(self.App, text=L.UpdatesFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.upd_enabled = BooleanVar() # Флаг обновлений self.upd_unit = StringVar() # Единица измерения времени self.time_units = { Minutes: L.Minutes, Hours: L.Hours, Days: L.Days, Weeks: L.Weeks, Months: L.Months } self.size_units = { Bytes: L.Bytes, KBytes: L.KBytes, MBytes: L.MBytes, GBytes: L.GBytes, TBytes: L.TBytes } # Список единиц измерения времени self.maxfsize = StringVar() # Максимальный размер файла self.size_unit = StringVar() # Единица измерения информации self.units_amount1 = StringVar() # Количество единиц self.quar = BooleanVar() # False - удалять, True - карантин self.quar_path = StringVar() # Расположение карантина self.rpt_enabled = BooleanVar() # Флаг отправки отчета self.email = StringVar() # Адрес отправки self.passwd = StringVar() # Пароль исходящего ящика self.rpt_unit = StringVar() # Единица измерения времени self.units_amount2 = StringVar() # Количество единиц self.Upd_Label1 = Label(self.UpdatesFrame, text=L.Upd_Label1) self.Upd_Checkbutton1 = Checkbutton(self.UpdatesFrame, variable=self.upd_enabled) self.Upd_Label2 = Label(self.UpdatesFrame, text=L.Upd_Label2) self.Upd_Spinbox1 = Spinbox(self.UpdatesFrame, textvariable=self.units_amount1, from_=1, to=999999999, width=4) self.Upd_OptionMenu1 = OptionMenu(self.UpdatesFrame, self.upd_unit, *self.time_units.values()) self.Upd_Button1 = Button( self.UpdatesFrame, text=L.Upd_Button1, command=lambda: EntryOptionsWindow('AV_SOURCES', self.Root)) self.ScanFrame = LabelFrame(self.App, text=L.ScanFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.Scn_Label1 = Label(self.ScanFrame, text=L.Scn_Label1) self.Scn_Spinbox1 = Spinbox(self.ScanFrame, textvariable=self.maxfsize, from_=0, to=999999999, width=8) self.Quar_Label = Label(self.ScanFrame, text=L.Quar_Label) self.Quar_RadButton1 = Radiobutton(self.ScanFrame, text=L.Quar_RadButton1, variable=self.quar, value=False) self.Quar_RadButton2 = Radiobutton(self.ScanFrame, text=L.Quar_RadButton2, variable=self.quar, value=True) self.Scn_OptionMenu1 = OptionMenu(self.ScanFrame, self.size_unit, *self.size_units.values()) self.Scn_Edit_Targets = Button( self.ScanFrame, text=L.Scn_Edit_Targets, command=lambda: EntryOptionsWindow( 'SCAN_TARGETS', self.Root, select_path=True)) self.Scn_Edit_Exceptions = Button( self.ScanFrame, text=L.Scn_Edit_Exceptions, command=lambda: EntryOptionsWindow('SCAN_EXCLUDE', self.Root)) self.Quar_Button1 = Button( self.ScanFrame, text=L.Quar_Button1, command=lambda: self.quar_path.set(filedialog.askdirectory())) self.ReportFrame = LabelFrame(self.App, text=L.ReportFrame, borderwidth=2, relief='sunken', padding=(5, 2)) self.Rpt_Label1 = Label(self.ReportFrame, text=L.Rpt_Label1) self.Rpt_Checkbutton1 = Checkbutton(self.ReportFrame, variable=self.rpt_enabled) self.Rpt_Label2 = Label(self.ReportFrame, text=L.Rpt_Label2) self.Rpt_Entry1 = Entry(self.ReportFrame, textvariable=self.email, width=32) self.Rpt_Label3 = Label(self.ReportFrame, text=L.Rpt_Label3) self.Rpt_Entry2 = Entry(self.ReportFrame, textvariable=self.passwd, width=32, show='*') self.Rpt_Label4 = Label(self.ReportFrame, text=L.Rpt_Label4) self.Rpt_Spinbox1 = Spinbox(self.ReportFrame, textvariable=self.units_amount2, from_=1, to=999999999, width=4) self.Rpt_OptionMenu1 = OptionMenu(self.ReportFrame, self.rpt_unit, *self.time_units.values()) self.Rpt_Button1 = Button( self.ReportFrame, text=L.Rpt_Button1, command=lambda: EntryOptionsWindow('SEND_TO', self.Root)) self.Buttons = Frame(self.App, padding=(5, 2)) self.Button1 = Button(self.Buttons, text=L.Done, command=self.save_conf) self.Button2 = Button(self.Buttons, text=L.Cancel, command=self.Root.destroy)
class DownloadPopup(Toplevel): def __init__(self, master, info: dict, message_store: MessageStore, video_id: str = None): Toplevel.__init__(self, master) self.bind('<Escape>', lambda _: self.cancel()) self.bind('<Return>', lambda _: self.ok()) self.title('Get VOD') self.transient(master) self.grab_set() self.info: dict = info self.message_store: MessageStore = message_store self.chat_downloader: ChatDownloader = None self.updated_info: bool = False self.status_var = StringVar(value='...') self.content = Frame(self) self.content.pack(padx=20, pady=15) self.video_title_var = StringVar(value='') self.download_info_var = StringVar(value='') self.eta_var = StringVar(value='') Label(self.content, text='Enter a VOD URL or video ID:').pack(side=TOP, anchor=W, pady=(0, 5)) self.entry = Entry(self.content, width=50) self.entry.pack(side=TOP, padx=2, pady=(0, 5)) Label(self.content, textvariable=self.status_var).pack(side=TOP, anchor=W, pady=(0, 5)) self.progress_var = IntVar(value=0) self.progress = Progressbar(self.content, variable=self.progress_var, maximum=1) self.progress.pack(side=TOP, fill=X, padx=2) Label(self.content, textvariable=self.video_title_var).pack(side=TOP, anchor=W, pady=(0, 5)) Label(self.content, textvariable=self.download_info_var).pack(side=TOP, anchor=W, pady=(0, 5)) Label(self.content, textvariable=self.eta_var).pack(side=TOP, anchor=W, pady=(0, 5)) self.overwrite_cache_var = BooleanVar(value=False) self.overwrite_cache_check = Checkbutton(self.content, text='Overwrite cache', variable=self.overwrite_cache_var) self.overwrite_cache_check.pack(side=TOP, anchor=W, pady=(0, 5)) self.button = Button(self.content, text='OK', command=self.ok) self.button.pack(side=TOP) self.update() x_coord = self.master.winfo_x() + (self.master.winfo_width() // 2) - (self.winfo_width() // 2) y_coord = self.master.winfo_y() + (self.master.winfo_height() // 2) - (self.winfo_height() // 2) self.geometry(f'{self.winfo_width()}x{self.winfo_height()}+{x_coord}+{y_coord}') self.entry.focus_set() self.protocol('WM_DELETE_WINDOW', self.cancel) if video_id: self.entry.insert(0, video_id) self.overwrite_cache_check.focus_set() chat_filename: str = os.path.join(CACHE_FOLDER, f'chat-{video_id}.json') if not os.path.exists(chat_filename): self.ok() def cancel(self): if self.chat_downloader: self.chat_downloader.kill() self.info.clear() self.info.update({'title': 'Chat Player'}) self.destroy() def ok(self): self.button.config(state=DISABLED) self.overwrite_cache_check.config(state=DISABLED) self.status_var.set('Validating...') self.after(1, self.validate) def validate(self): video_id: str = self.entry.get() if 'http' in video_id or 'twitch.tv' in video_id: video_id = parse_url(video_id) if len(video_id) > 0 and video_exists(video_id): self.chat_downloader = ChatDownloader(video_id, overwrite_cache=self.overwrite_cache_var.get()) self.chat_downloader.start() self.after(1, self.download) else: self.status_var.set('Error: Invalid URL or video ID.') self.button.config(state=NORMAL) def download(self): if not self.chat_downloader.info: self.status_var.set('Getting info') self.after(100, self.download) elif not self.chat_downloader.messages: if not self.updated_info: self.status_var.set('Downloading chat') self.info.update(self.chat_downloader.info) self.video_title_var.set(self.info.get('title')) self.updated_info = True self.progress_var.set(self.chat_downloader.progress) self.download_info_var.set( f'{self.chat_downloader.num_messages} messages downloaded. ' f'Duration {self.chat_downloader.duration_done_str}/{self.chat_downloader.duration_str}.') self.eta_var.set(f'ETA: {self.chat_downloader.eta_str}') self.after(100, self.download) else: self.message_store.set_messages(self.chat_downloader.messages) self.destroy()
def __init__(self, master, ordinances=False, **kwargs): super(Options, self).__init__(master, **kwargs) self.ancestors = IntVar() self.ancestors.set(4) self.descendants = IntVar() self.spouses = IntVar() self.ordinances = IntVar() self.contributors = IntVar() self.start_indis = StartIndis(self) self.fid = StringVar() btn = Frame(self) entry_fid = EntryWithMenu(btn, textvariable=self.fid, width=16) entry_fid.bind("<Key>", self.enter) label_ancestors = Label(self, text=_("Number of generations to ascend")) entry_ancestors = EntryWithMenu(self, textvariable=self.ancestors, width=5) label_descendants = Label(self, text=_("Number of generations to descend")) entry_descendants = EntryWithMenu(self, textvariable=self.descendants, width=5) btn_add_indi = Button(btn, text=_("Add a FamilySearch ID"), command=self.add_indi) btn_spouses = Checkbutton(self, text="\t" + _("Add spouses and couples information"), variable=self.spouses) btn_ordinances = Checkbutton(self, text="\t" + _("Add Temple information"), variable=self.ordinances) btn_contributors = Checkbutton(self, text="\t" + _("Add list of contributors in notes"), variable=self.contributors) self.start_indis.grid(row=0, column=0, columnspan=3) entry_fid.grid(row=0, column=0, sticky="w") btn_add_indi.grid(row=0, column=1, sticky="w") btn.grid(row=1, column=0, columnspan=2, sticky="w") entry_ancestors.grid(row=2, column=0, sticky="w") label_ancestors.grid(row=2, column=1, sticky="w") entry_descendants.grid(row=3, column=0, sticky="w") label_descendants.grid(row=3, column=1, sticky="w") btn_spouses.grid(row=4, column=0, columnspan=2, sticky="w") if ordinances: btn_ordinances.grid(row=5, column=0, columnspan=3, sticky="w") btn_contributors.grid(row=6, column=0, columnspan=3, sticky="w") entry_ancestors.focus_set()
class NewSliderWindow(Toplevel): def __init__(self, master=None): super().__init__(master=master) self.set_basic() self.bind('<Configure>', lambda e: self.place_buttons()) def set_basic(self): self.overrideredirect(1) self.set_geometry() self.set_scale() self.set_checkButton() self.set_save_closeButtons() def set_geometry(self): self.width = 60 parentX = self.master.winfo_rootx() parentY = self.master.winfo_rooty() parentHeight = self.master.winfo_height() parentWidth = self.master.winfo_width() self.geometry( '%dx%d+%d+%d' % (self.width, parentHeight, parentX + parentWidth + 2, parentY)) def set_save_closeButtons(self): self.saveButton = Button(self, image=saveIcon, command=self.update_image) self.cancelButton = Button(self, image=closeIcon, command=self.cancel) self.saveButton.place(relx=0.1, rely=0.8, relwidth=0.4) self.cancelButton.place(relx=0.55, rely=0.8, relwidth=0.4) self.saveButton.place( relx=0.1, rely=1 - ((0.4 * self.width) / self.master.winfo_height()), relwidth=0.4) self.cancelButton.place( relx=0.55, rely=1 - ((0.4 * self.width) / self.master.winfo_height()), relwidth=0.4) def place_buttons(self): self.saveButton.place( relx=0.03, rely=1 - ((0.45 * self.width) / self.master.winfo_height()), relwidth=0.45) self.cancelButton.place( relx=0.52, rely=1 - ((0.45 * self.width) / self.master.winfo_height()), relwidth=0.45) def set_scale(self): self.var = IntVar() self.scale = Scale(self, length=256, from_=0, to=255, orient=VERTICAL, command=lambda e: self.update_preview( int(self.var.get()), self.cbVal.get()), variable=self.var, digits=1, resolution=1) self.scale.place(relx=0, rely=0.1, relwidth=0.9, relheight=0.7) self.scale.set(0) def set_checkButton(self): self.cbVal = IntVar() self.cb = Checkbutton(self, width=0, variable=self.cbVal, command=lambda: self.update_preview( int(self.var.get()), self.cbVal.get())) self.cb.place(relx=0.4, rely=0.78) self.cb.invoke() #UPDATE IMAGE ON SLIDER CHANGE def update_preview(self, thresholdVal, checkBoxVal): self.master.image.threshold(thresholdVal, checkBoxVal) self.master.update_visible_image() #UPDATE IMAGE ON "SAVE" AND UPDATE HISTOGRAM def update_image(self): self.master.update_visible_image() self.master.image.copy = copy.deepcopy(self.master.image.cv2Image) self.master.image.fill_histogram() self.master.update_child_windows() self.master.thresholdScaleWindow = None self.master.manager.new_state(self.master.image.cv2Image) self.destroy() #GO BACK TO ORIGINAL ON "CANCEL" def cancel(self): self.master.image.cv2Image = copy.deepcopy(self.master.image.copy) self.master.update_visible_image() self.master.image.fill_histogram() self.master.update_child_windows() self.master.thresholdScaleWindow = None self.destroy()
def create_widgets(self): ''' Creates all widgets. ''' rts_lbl = Label(self, text='Return to scale:') rts_lbl.grid(row=0, column=0, padx=XPAD_VALUE, pady=YPAD_VALUE, sticky=W) self._create_frame_with_radio_btns(self, 'RETURN_TO_SCALE', ['VRS', 'CRS'], row_index=1, column_index=0) orientation_lbl = Label(self, text='Orientation:') orientation_lbl.grid(row=0, column=1, sticky=W, padx=XPAD_VALUE, pady=YPAD_VALUE) self._create_frame_with_radio_btns(self, 'ORIENTATION', ['Input', 'Output'], row_index=1, column_index=1) model_lbl = Label(self, text='Model:') model_lbl.grid(row=0, column=2, padx=XPAD_VALUE, pady=YPAD_VALUE, sticky=W) self._create_frame_with_radio_btns(self, 'DEA_FORM', ['Envelopment', 'Multiplier'], row_index=1, column_index=2, add_both=False) other_lbl = Label(self, text='Others:') other_lbl.grid(row=0, column=3, sticky=W, padx=XPAD_VALUE) max_slacks = IntVar() self.options['MAXIMIZE_SLACKS'] = max_slacks frame_other_options = Frame(self) self.max_slack_box = max_slacks_check_btn = Checkbutton( frame_other_options, text='Two phase', variable=max_slacks, command=(lambda: self.on_check_box_click( max_slacks, 'MAXIMIZE_SLACKS'))) max_slacks_check_btn.grid(row=1, column=0, sticky=W) super_efficiency = IntVar() self.options['USE_SUPER_EFFICIENCY'] = super_efficiency super_efficiency_check_btn = Checkbutton(frame_other_options, text='Super efficiency', variable=super_efficiency, command=( lambda: self.on_check_box_click( super_efficiency, 'USE_SUPER_EFFICIENCY'))) super_efficiency_check_btn.grid(row=2, column=0, sticky=W) peel_the_onion = IntVar() self.options['PEEL_THE_ONION'] = peel_the_onion peel_the_onion_check_btn = Checkbutton( frame_other_options, text='Peel the onion', variable=peel_the_onion, command=(lambda: self.on_check_box_click(peel_the_onion, 'PEEL_THE_ONION'))) peel_the_onion_check_btn.grid(row=3, column=0, sticky=W) frame_other_options.grid(row=1, column=3, padx=XPAD_VALUE, pady=YPAD_VALUE, sticky=W) frame_for_toleramce = Frame(self) tolerance_lbl = Label(frame_for_toleramce, text='Multiplier model tolerance:') tolerance_lbl.grid(row=0, column=0, padx=XPAD_VALUE, pady=YPAD_VALUE, sticky=W) tolerance_ent = Entry(frame_for_toleramce, width=5, textvariable=self.multi_tol_strvar) tolerance_ent.insert(END, 0) tolerance_ent.grid(row=0, column=1, sticky=W, padx=XPAD_VALUE) categorical_lbl = Label(frame_for_toleramce, text='Categorical:') categorical_lbl.grid(row=1, column=0, padx=XPAD_VALUE, pady=YPAD_VALUE, sticky=W) self.categorical_box = categorical_box = Combobox( frame_for_toleramce, textvariable=self.combobox_text_var, exportselection=0, state="readonly", width=20, values=(''), postcommand=self.change_categorical_box) categorical_box.grid(row=1, column=1, padx=XPAD_VALUE, pady=YPAD_VALUE, sticky=W) frame_for_toleramce.grid(row=5, column=0, sticky=W, padx=XPAD_VALUE, pady=YPAD_VALUE, columnspan=4)
hFinal.place(relx=0.82, rely=0.2, anchor=CENTER) total = Entry(janela) total.place(relx=0.65, rely=0.8, anchor=CENTER) calculado = Entry(janela) calculado.place(relx=0.65, rely=0.9, anchor=CENTER) chuveiroEstado = BooleanVar() chuveiroEstado.set(False) lampadaEstado = BooleanVar() lampadaEstado.set(False) tomadaEstado = BooleanVar() tomadaEstado.set(False) arEstado = BooleanVar() arEstado.set(False) lampada = Checkbutton(janela, text='Lâmpadas', var=lampadaEstado) lampada.place(relx=0.407, rely=0.55, anchor=CENTER) chuveiro = Checkbutton(janela, text='Chuveiro', var=chuveiroEstado) chuveiro.place(relx=0.4, rely=0.65, anchor=CENTER) tomada = Checkbutton(janela, text='Tomadas', var=tomadaEstado) tomada.place(relx=0.61, rely=0.55, anchor=CENTER) ar = Checkbutton(janela, text='Ar Condicionado', var=arEstado) ar.place(relx=0.655, rely=0.65, anchor=CENTER) #FUNÇÕES def aluno(): mensagem = messagebox.showinfo( "Discente", "Nome: Milena Teixeira Correia\n\nR.A: 22.219.011-8")
def __init__(self, master=None, attributes='standard', target_var=None, header='Desired Tract Attributes', show_ok=True, show_cancel=True, ok_button_text='Confirm Attributes', cancel_button_text='Cancel', confirm_cancel_prompt=None, exit_after_ok=True, prompt_after_ok=None, external_var_dict=None, **kw): """ :param master: The tkinter master (same as for tkinter.Frame) :param target_var: A tk.StringVar to which the chosen attributes should be stored when the OK button is clicked. Stored as a single string, with attribute names separated by a comma and no spaces. :param attributes: Which attributes to allow the user to select from; may be passed as a list, or as a string with attributes separated by commas (defaults to 'standard') :param header: Text to be placed above the attribute options. :param show_ok: Include the OK button. :param ok_button_text: A string, for custom text for the OK button. :param prompt_after_ok: A string to display in a messagebox after the OK button has been clicked. Defaults to None. :param exit_after_ok: Whether to close the window after OK button is clicked. Defaults to False. :param cancel_button_text: A string, for custom text for the Cancel button. :param show_cancel: Include the Cancel button. IMPORTANT: If the Cancel button is clicked, it will set the `target_var` to the string 'CANCEL' and close the window. :param confirm_cancel_prompt: A string to display in a yes/no messagebox when the Cancel button is clicked. Defaults to None. :param external_var_dict: A dict with the key 'attrib_list', to which the chosen attributes should be set (as a list of strings). (Only used by `prompt_attrib()` -- probably ignore this parameter.) :param kw: Kwargs to pass through to tkinter.Frame at init. """ default_master = False if not master: default_master = True master = tk.Tk() master.title('Select pyTRS Tract Attributes') tk.Frame.__init__(self, master, **kw) self.master = master if default_master: self.pack(padx=20, pady=20) if not target_var: target_var = tk.StringVar() self.target_var = target_var if not external_var_dict: external_var_dict = {'attrib_list': []} self.external_var_dict = external_var_dict self.show_ok = show_ok self.show_cancel = show_cancel self.prompt_after_ok = prompt_after_ok self.exit_after_ok = exit_after_ok self.confirm_cancel_prompt = confirm_cancel_prompt if isinstance(attributes, str): if attributes.lower() == 'standard': attributes = PromptAttrib.STANDARD_OPTIONS elif attributes.lower() == 'all': attributes = PromptAttrib.ALL_ATTRIBUTES.keys() else: attributes = [ at.lower().strip() for at in attributes.split(',') ] if header: hdr = tk.Label(self, text=str(header), font='"Arial Black"') hdr.grid(row=0, column=0, sticky='n') # Generate a new IntVar for each available attribute option, set # its value to the default value per STANDARD_ATTRIBUTES, store # it as an instance variable, and also set it to the attrib_dict. # Finally, create a checkbutton for that attribute. # So for attribute 'qqs': # -> self.qqs_var --> a tk.IntVar with initial value 0 # -> self.attrib_dict['qqs'] --> self.qqs_var # -> <create a checkbutton for qqs> self.attrib_dict = dict() cur_row = 5 for att in attributes: new_var = tk.IntVar() new_var.set(PromptAttrib.ALL_ATTRIBUTES[att][1]) setattr(self, f"{att}_var", new_var) self.attrib_dict[att] = new_var cb = Checkbutton(self, text=PromptAttrib.ALL_ATTRIBUTES[att][0], var=self.attrib_dict[att]) cb.grid(row=cur_row, column=0, sticky='w', pady=2) cur_row += 1 ctrl_frame = tk.Frame(self) ctrl_frame.grid(row=cur_row, column=0, padx=10, pady=10) if show_ok: ok_btn = tk.Button(ctrl_frame, text=ok_button_text, command=self.ok_clicked) ok_btn.grid(row=0, column=1, sticky='e', padx=20, pady=10) if show_cancel: cancel_btn = tk.Button(ctrl_frame, text=cancel_button_text, command=self.cancel_clicked) cancel_btn.grid(row=0, column=0, sticky='e', padx=20, pady=10)
def makegridsquare(self, parent, imageobj, setguidata): frame = tk.Frame(parent, width=self.thumbnailsize + 14, height=self.thumbnailsize + 24) frame.obj = imageobj try: if setguidata: if not os.path.exists(imageobj.thumbnail): self.fileManager.makethumb(imageobj) try: buffer = pyvips.Image.new_from_file(imageobj.thumbnail) img = ImageTk.PhotoImage( Image.frombuffer("RGB", [buffer.width, buffer.height], buffer.write_to_memory())) except: # Pillow fallback img = ImageTk.PhotoImage(Image.open(imageobj.thumbnail)) else: img = imageobj.guidata['img'] canvas = tk.Canvas(frame, width=self.thumbnailsize, height=self.thumbnailsize) tooltiptext = tk.StringVar(frame, self.tooltiptext(imageobj)) ToolTip(canvas, msg=tooltiptext.get, delay=1) canvas.create_image(self.thumbnailsize / 2, self.thumbnailsize / 2, anchor="center", image=img) check = Checkbutton(frame, textvariable=imageobj.name, variable=imageobj.checked, onvalue=True, offvalue=False) canvas.grid(column=0, row=0, sticky="NSEW") check.grid(column=0, row=1, sticky="N") frame.rowconfigure(0, weight=4) frame.rowconfigure(1, weight=1) frame.config(height=self.thumbnailsize + 12) if ( setguidata ): # save the data to the image obj to both store a reference and for later manipulation imageobj.setguidata({ "img": img, "frame": frame, "canvas": canvas, "check": check, "show": True, "tooltip": tooltiptext }) # anything other than rightclicking toggles the checkbox, as we want. canvas.bind("<Button-1>", partial(bindhandler, check, "invoke")) canvas.bind("<Button-3>", partial(self.displayimage, imageobj)) check.bind("<Button-3>", partial(self.displayimage, imageobj)) canvas.bind("<MouseWheel>", partial(bindhandler, parent, "scroll")) frame.bind("<MouseWheel>", partial(bindhandler, self.imagegrid, "scroll")) check.bind("<MouseWheel>", partial(bindhandler, self.imagegrid, "scroll")) if imageobj.moved: frame.configure(highlightbackground="green", highlightthickness=2) if os.path.dirname( imageobj.path) in self.fileManager.destinationsraw: color = self.fileManager.destinations[indexOf( self.fileManager.destinationsraw, os.path.dirname(imageobj.path))]['color'] frame['background'] = color canvas['background'] = color frame.configure(height=self.thumbnailsize + 10) if imageobj.dupename: frame.configure(highlightbackground="yellow", highlightthickness=2) except Exception as e: logging.error(e) return frame
def __init__(self,root): self.root = root self.check_line_on = BooleanVar() self.code_text = ScrolledText(self.root,bd=4,relief=GROOVE) self.code_text.place(x=0,y=0,height=300,width=300) self.output_code = ScrolledText(self.root,bd=4,relief=GROOVE) self.output_code.place(x=300,y=0,height=300,width=300) self.control_frame = Frame(self.root,bd=2,relief=GROOVE) self.control_frame.place(x=25,y=310,height=130,width=550) # ................ controls in control frames ................... self.languages = ['python','C','C++','java','php','C#'] self.borders = ['dotted','dashed','solid','double','groove','ridge','inset','none','hidden'] #self.border_width = ['2px','4px','6px','8px','10px','medium','thick'] self.border_clrs = ['red','black','gray','white','green','yellow','pink','cyan','sky blue'] self.styles = ['default', 'emacs', 'friendly', 'colorful', 'autumn', 'murphy', 'monokai', 'perldoc', 'pastie', 'borland', 'trac', 'native', 'fruity', 'bw', 'vim', 'vs', 'tango', 'rrt', 'xcode', 'igor', 'paraiso-light', 'paraiso-dark', 'lovelace', 'algol', 'algol_nu', 'arduino', 'rainbow_dash', 'abap', 'solarized-dark', 'solarized-light', 'sas', 'stata', 'stata-light', 'stata-dark', 'inkpot'] self.style_combo = Combobox(self.control_frame,width=20,values=self.styles,justify=CENTER) self.style_combo.set('Select Style') self.style_combo.place(x=10,y=5) self.border_combo = Combobox(self.control_frame,width=20,values=self.borders,justify=CENTER) self.border_combo.set('Select Border') self.border_combo.place(x=10,y=45) self.border_color_combo = Combobox(self.control_frame,width=20,values=self.border_clrs,justify=CENTER) self.border_color_combo.set('Border Color') self.border_color_combo.place(x=10,y=85) self.language_combo = Combobox(self.control_frame,width=15,values=self.languages,justify=CENTER) self.language_combo.set('python') self.language_combo.place(x=180,y=40) self.Line_no_check = Checkbutton(self.control_frame,text='Enable Line No.',onvalue=True,offvalue=False, variable=self.check_line_on) self.Line_no_check.place(x=180,y=9) highlight_btn = ttk.Button(self.control_frame,text='Highlight',command=self.highlight_code) highlight_btn.place(x=300,y=10) copy_edit_code = ttk.Button(self.control_frame,text='Copy Code',command=self.copy_code) copy_edit_code.place(x=300,y=50) clear_input_text = ttk.Button(self.control_frame,text='Clear Input Box', width=20,command=lambda:self.code_text.delete(0.0,END)) clear_input_text.place(x=400,y=10) clear_output_text = ttk.Button(self.control_frame,text='Clear Output Box', width=20,command=lambda:self.output_code.delete(0.0,END)) clear_output_text.place(x=400,y=50)
class TkApp(Tk): """ The main Tk class for the gui of simplebackup """ def __init__(self, **kwargs): super().__init__() title = "Simple Backup | V" + __version__ self.wm_title(title) self.protocol("WM_DELETE_WINDOW", self.on_closing) self.__thread = None self.__files_found = 0 self.__files_copied = 0 config_fn = kwargs.get("config_fn", user_config_filepath()) self.__app_config = Config_Handler(config_fn) self.__curr_config = self.__app_config.default_config_i self.__menu = Menu(self) self.__menu_file = Menu(self.__menu, tearoff=0) self.__menu_file.add_command(label="Quit", command=self.quit) self.__menu_config = Menu(self.__menu, tearoff=0) self.__menu_config.add_command(label="New", command=self.new_config) self.__menu_config.add_command(label="Load", command=self.switch_config) self.__menu_config.add_command(label="Change Default", command=self.change_default_config) self.__menu_config.add_command(label="Rename Current", command=self.rename_curr_conf) self.__menu_config.add_separator() self.__menu_config.add_command(label="Delete Current", command=self.delete_current_config) self.__menu_config.add_command(label="Delete All", command=self.reset_config) self.__menu_help = Menu(self.__menu, tearoff=0) self.__menu_help.add_command(label="Check for Updates", command=self.show_update_popup) self.__menu_help.add_command(label="About", command=self.show_about_popup) self.__menu.add_cascade(label="File", menu=self.__menu_file) self.__menu.add_cascade(label="Config", menu=self.__menu_config) self.__menu.add_cascade(label="Help", menu=self.__menu_help) self.__title_l = Label(self, text=title, font=(16)) self.__curr_config_name_l = Label(self) self.__last_backup_l = Label(self) self.__set_versions_to_keep = Button( self, text="Set Versions To Keep", command=self.update_versions_to_keep) self.__versions_to_keep_l = Label(self) self.__inc_folder_bnt = Button(self, text="Include Another Folder", command=self.add_included_folder) self.__included_folders_lb = Listbox(self, height=4) self.__included_folders_lb.bind("<<ListboxSelect>>", self.remove_selected_included_folder) self.__included_folders_lb.bind('<FocusOut>', self.deselect_included_folder) self.__excl_folder_bnt = Button(self, text="Exclude Another Folder", command=self.add_excluded_folder) self.__excluded_folders_lb = Listbox(self, height=4) self.__excluded_folders_lb.bind("<<ListboxSelect>>", self.remove_selected_excluded_folder) self.__excluded_folders_lb.bind('<FocusOut>', self.deselect_excluded_folder) self.__backup_to_bnt = Button(self, text="Backup Folder", command=self.set_backup_folder) self.__backup_folder_l = Label(self) self.__use_tar_l = Label(self, text="Use Tar") self.__use_tar_var = BooleanVar(self) self.__use_tar_var.trace_add("write", self.use_tar_changed) self.__use_tar = Checkbutton(self, variable=self.__use_tar_var) self.__backup_start_bnt = Button(self, text="Start Backup", command=self.start_backup) self.__progress = Progressbar(self) self.__statusbar = Label(self, text="ok", relief=SUNKEN, anchor=W) self._load_display() self._layout() if self.__app_config.show_help: self.show_help_popup() def on_closing(self): """ called on window close """ if self.__files_found != self.__files_copied: if messagebox.askyesno("Backup Running", "Do you want to stop the backup?"): self.destroy() else: self.destroy() def _load_display(self): """ load the widgets with data from the current backup config, should be run after loading a config from file and at app launch """ self.__versions_to_keep = self.__app_config.get_versions_to_keep( self.__curr_config) self.__included_folders = self.__app_config.get_included_folders( self.__curr_config) self.__excluded_folders = self.__app_config.get_excluded_folders( self.__curr_config) self.__backup_location = self.__app_config.get_backup_path( self.__curr_config) curr_conf_name = self.__app_config.get_config_name(self.__curr_config) self.__curr_config_name_l.config(text=f"Config Name: {curr_conf_name}") self.__last_backup_l.config( text= f"Last Known Backup: {self.__app_config.get_human_last_backup(self.__curr_config)}" ) self.__versions_to_keep_l.config(text=self.__versions_to_keep) self.__included_folders_lb.delete(0, END) self.__included_folders_lb.insert(0, *self.__included_folders) self.__excluded_folders_lb.delete(0, END) self.__excluded_folders_lb.insert(0, *self.__excluded_folders) self.__backup_folder_l.config(text=str(self.__backup_location)) self.__use_tar_var.set( self.__app_config.get_use_tar(self.__curr_config)) def switch_config(self): """ switches what config to use for backup, asks the user for a config to load, then loads the display """ next_combo = ask_combobox("Load Config", "Config Name", self.__app_config.get_config_names()) if next_combo != None: self.__curr_config = next_combo self._load_display() def change_default_config(self): """ switches what config to use for the default backup, asks the user for a config to load """ next_combo = ask_combobox("Default Config", "Config Name", self.__app_config.get_config_names()) if next_combo != None: self.__app_config.default_config_i = next_combo def rename_curr_conf(self): """ rename a existing config, will ask the user in a popup string input """ new_name = simpledialog.askstring("Rename Config", "New Name") if new_name: self.__app_config.rename_config(self.__curr_config, new_name) self._load_display() def new_config(self): """ creates a new empty backup config, asks the user for config name """ name = simpledialog.askstring("New Config", "Config Name") if name: self.__app_config.create_config(name) def delete_current_config(self): """ deletes the current selected config, asks the user to confirm """ if messagebox.askyesno( "Confirm Delete", "Are you sure you want to delete the current config?"): self.__app_config.remove_config(self.__curr_config) self.__curr_config = self.__app_config.default_config_i self._load_display() def reset_config(self): """ resets all the user configs, asks the user to confirm """ if messagebox.askyesno( "Confirm Reset", "Are you sure you want to reset the all configurations?"): self.__app_config.reset_config() self.__curr_config = self.__app_config.default_config_i self._load_display() def use_tar_changed(self, *args): """ called each time the __use_tar_var is called """ self.__app_config.set_use_tar(self.__curr_config, self.__use_tar_var.get()) def update_versions_to_keep(self): """ update the number of versions to keep, asks the user for a integer """ new_val = simpledialog.askinteger( "Versions To Keep", "How many backups do you want to keep", minvalue=0) if new_val != self.__versions_to_keep and new_val != None: self.__versions_to_keep = new_val self.__app_config.set_versions_to_keep(self.__curr_config, self.__versions_to_keep) self.__versions_to_keep_l.config(text=self.__versions_to_keep) def deselect_included_folder(self, *args): """ deselects the selected element in included folder """ self.__included_folders_lb.selection_clear(0, END) def deselect_excluded_folder(self, *args): """ deselects the selected element in excluded folder """ self.__excluded_folders_lb.selection_clear(0, END) def add_included_folder(self): """ add a folder to include in the backup, will ask user for a directory """ folder = filedialog.askdirectory(initialdir="/", title="Select Folder To Backup") if folder: folder_path = Path(folder) if folder_path != self.__backup_location: self.__included_folders.append(folder_path) self.__included_folders_lb.insert(END, folder_path) self.__app_config.set_included_folders(self.__curr_config, self.__included_folders) else: messagebox.showwarning( title="Folder Same As Backup Path", message= "You selected a folder that was the same as the backup path!" ) def remove_selected_included_folder(self, *args): """ remove the currently selected item in the included folders ListBox, will ask the user to confirm """ curr_selection = self.__included_folders_lb.curselection() # check if there is a selection if curr_selection: if messagebox.askyesno("Confirm Delete", "Are you want to delete this folder?"): index_to_del = curr_selection[0] self.__included_folders.pop(index_to_del) self.__app_config.set_included_folders(self.__curr_config, self.__included_folders) self.__included_folders_lb.delete(index_to_del) self.deselect_included_folder() def add_excluded_folder(self): """ add a folder to exclude in the backup, will ask user for a directory """ folder = filedialog.askdirectory(initialdir="/", title="Select Folder To Exclude") if folder: folder_path = Path(folder) self.__excluded_folders.append(folder_path) self.__excluded_folders_lb.insert(END, folder_path) self.__app_config.set_excluded_folders(self.__curr_config, self.__excluded_folders) def remove_selected_excluded_folder(self, *args): """ remove the currently selected item in the excluded folders ListBox, will ask the user to confirm """ curr_selection = self.__excluded_folders_lb.curselection() # check if there is a selection if curr_selection: if messagebox.askyesno("Confirm Delete", "Are you want to delete this folder?"): index_to_del = curr_selection[0] self.__excluded_folders.pop(index_to_del) self.__app_config.set_excluded_folders(self.__curr_config, self.__excluded_folders) self.__excluded_folders_lb.delete(index_to_del) self.deselect_excluded_folder() def set_backup_folder(self): """ sets the backup folder by asking the user for a base directory """ folder = filedialog.askdirectory(initialdir="/", title="Select Where To Backup To") if folder: self.__backup_location = Path(folder) self.__backup_folder_l.config(text=folder) self.__app_config.set_backup_path(self.__curr_config, self.__backup_location) def enable_gui(self): """ enable the gui buttons, run when a backup has completed """ self.__set_versions_to_keep.config(state=NORMAL) self.__inc_folder_bnt.config(state=NORMAL) self.__included_folders_lb.config(state=NORMAL) self.__excl_folder_bnt.config(state=NORMAL) self.__excluded_folders_lb.config(state=NORMAL) self.__backup_to_bnt.config(state=NORMAL) self.__use_tar.config(state=NORMAL) self.__backup_start_bnt.config(state=NORMAL) def disable_gui(self): """ disable the gui buttons, run when a backup is started """ self.__set_versions_to_keep.config(state=DISABLED) self.__inc_folder_bnt.config(state=DISABLED) self.__included_folders_lb.config(state=DISABLED) self.__excl_folder_bnt.config(state=DISABLED) self.__excluded_folders_lb.config(state=DISABLED) self.__backup_to_bnt.config(state=DISABLED) self.__use_tar.config(state=DISABLED) self.__backup_start_bnt.config(state=DISABLED) def progress_find_incr(self, finished=False): """ increment the progress bar for finding files by 1 or mark as finished :param finished: mark the progressbar as finished """ if finished: self.__progress.config(mode="determinate") self.__progress.config(value=0, maximum=self.__files_found) self.__statusbar.config(text=f"Found {self.__files_found} Files") else: self.__files_found += 1 self.__progress.config(value=self.__files_found) self.__statusbar.config( text=f"Searching For Files, Found {self.__files_found} Files") def progress_copy_incr(self): """ increment the progress bar for copying files by 1 or mark as finished """ self.__files_copied += 1 self.__progress.config(value=self.__files_copied) self.__statusbar.config( text=f"Copying Files {self.__files_copied} of {self.__files_found}" ) if self.__files_copied == self.__files_found: self.__app_config.set_last_backup(self.__curr_config, datetime.utcnow()) self.__last_backup_l.config( text= f"Last Known Backup: {self.__app_config.get_human_last_backup(self.__curr_config)}" ) self.__statusbar.config(text=f"Finished Copying Files") messagebox.showinfo(title="Finished Copying Files", message="Finished copying all found files") # reset counters self.__files_found = 0 self.__files_copied = 0 self.__progress.config(value=0, maximum=100) self.enable_gui() def start_backup(self): """ starts the backup """ if not self.__backup_location: # no backup location was selected messagebox.showwarning( title="Backup Location Not Selected", message="You did not select a backup location!") elif not self.__included_folders: # no folders where found to backup messagebox.showwarning( title="No Folders To Backup", message="You did not add any folders to backup!") else: # basic checks passed self.disable_gui() # prep for search of files self.__progress.config(mode="indeterminate") self.__statusbar.config(text=f"Searching For Files") self.__thread = BackupThread( self.__included_folders, self.__excluded_folders, self.__backup_location, self.__versions_to_keep, self.progress_find_incr, self.progress_copy_incr, self.handle_error_message, self.__use_tar_var.get()) # start the background backup thread so GUI wont appear frozen self.__thread.start() def show_about_popup(self): """ show the about popup """ messagebox.showinfo( "About", "simplebackup V" + __version__ + """ is cross-platform backup program written in python. This app was made by enchant97/Leo Spratt. It is licenced under GPL-3.0""") def show_update_popup(self): """ open the default webbrowser to the update url """ webbrowser.open(UPDATE_URL) def show_help_popup(self): messagebox.showinfo( "Welcome", """Welcome to simplebackup, here is some help to get you started: \nIncluding a folder to backup - Press the 'Include Folder' button to add a folder to backup - Remove a entry by clicking on the list below \nExcluding a folder from the backup - Press the 'Exclude Folder' button to skip a folder to backup - Remove a entry by clicking on the list below \nSetting where backups are stored - Click the 'Backup Folder' button to set where backups should be placed \nMultiple backup configs Use the 'Config' button in the titlebar to change varius settings like creating a new config \nVersions to keep This will be the number of backup to keep in the backup folder """) self.__app_config.show_help = False def handle_error_message(self, error_type: ERROR_TYPES): self.__statusbar.config(text="Failed") if error_type is ERROR_TYPES.NO_BACKUP_WRITE_PERMISION: messagebox.showerror("No Write Permission", ERROR_TYPES.NO_BACKUP_WRITE_PERMISION.value) elif error_type is ERROR_TYPES.NO_BACKUP_READ_PERMISION: messagebox.showerror("No Read Permission", ERROR_TYPES.NO_BACKUP_READ_PERMISION.value) elif error_type is ERROR_TYPES.NO_FILES_FOUND_TO_BACKUP: messagebox.showerror("No Files Found", ERROR_TYPES.NO_FILES_FOUND_TO_BACKUP.value) elif error_type is ERROR_TYPES.NO_BACKUP_PATH_FOUND: messagebox.showerror("No Backup Path Found", ERROR_TYPES.NO_BACKUP_PATH_FOUND.value) self.__progress.config(mode="determinate") self.enable_gui() def _layout(self): self.config(menu=self.__menu) self.__title_l.pack(fill=X, pady=10, padx=5) self.__curr_config_name_l.pack(fill=X, padx=5) self.__last_backup_l.pack(fill=X, padx=5) self.__set_versions_to_keep.pack(fill=X, padx=5) self.__versions_to_keep_l.pack(fill=X, padx=5) self.__inc_folder_bnt.pack(fill=X, padx=5) self.__included_folders_lb.pack(fill=X, padx=5) self.__excl_folder_bnt.pack(fill=X, padx=5) self.__excluded_folders_lb.pack(fill=X, padx=5) self.__backup_to_bnt.pack(fill=X, padx=5) self.__backup_folder_l.pack(fill=X, padx=5) self.__use_tar_l.pack(fill=X, padx=5) self.__use_tar.pack(fill=X, padx=5) self.__backup_start_bnt.pack(fill=X, padx=5) self.__progress.pack(fill=X) self.__statusbar.pack(side=BOTTOM, fill=X) self.wm_minsize(300, self.winfo_height()) self.wm_resizable(True, False)
class App_test(object): def __init__(self): self.win = Tk() self.win.title('12306火车票查询系统V2.6') self.win.geometry('860x400') self.creat_res() self.add_train_info() self.add_check_button() self.res_config() self.train_message = {} # self.get_train_args() self.win.mainloop() def creat_res(self): self.v = IntVar() #车票查询 self.v.set(True) self.temp = StringVar() #开始站 self.temp2 = StringVar() #目的站 self.start_mon = StringVar() #出发月 self.start_day = StringVar() #出发日 self.start_year = StringVar() #出啊年 self.E_startstation = Entry(self.win, textvariable=self.temp) self.E_endstation = Entry(self.win, textvariable=self.temp2) self.La_startstation = Label(self.win, text="出发站:") self.La_endstation = Label(self.win, text="目的站:") self.La_time = Label(self.win, text="请选择出发时间-年-月-日", fg="blue") self.B_search = Button(self.win, text="搜索") self.R_site = Radiobutton(self.win, text="车票查询", variable=self.v, value=True) self.R_price = Radiobutton(self.win, text="票价查询", variable=self.v, value=False) self.B_buy_tick = Button(self.win, text="购票") self.C_year = Combobox(self.win, textvariable=self.start_year) self.C_mon = Combobox(self.win, textvariable=self.start_mon) self.La_s = Label(self.win, text="--") self.C_day = Combobox(self.win, textvariable=self.start_day) self.S_move = Scrollbar(self.win) self.E_startstation.place(x=70, y=10, width=65, height=30) self.E_endstation.place(x=70, y=60, width=65, height=30) self.La_startstation.place(x=10, y=10, width=50, height=30) self.La_endstation.place(x=10, y=60, width=50, height=30) self.La_time.place(x=10, y=100, width=150, height=30) self.C_year.place(x=10, y=140, width=70, height=30) self.C_mon.place(x=100, y=140, width=50, height=30) self.C_day.place(x=100, y=180, width=50, height=30) self.La_s.place(x=80, y=140, width=20, height=30) self.B_search.place(x=10, y=180, width=50, height=30) self.S_move.place(x=834, y=40, width=30, height=350) self.B_buy_tick.place(x=10, y=260, width=80, height=40) self.R_site.place(x=10, y=230, width=70, height=30) self.R_price.place(x=90, y=230, width=70, height=30) def res_config(self): self.C_year.config(values=[x for x in range(2018, 2020)]) self.C_mon.config(values=["{:02d}".format(x) for x in range(1, 13)]) #时间格式是2018-01-01 self.C_day.config(values=["{:02d}".format(x) for x in range(1, 32)]) self.B_search.config(command=self.search_train_message) self.S_move.config(command=self.tree.yview) self.tree.config(yscrollcommand=self.S_move.set) def add_train_info(self): lis_train = ["C" + str(x) for x in range(0, 15)] tuple_train = tuple(lis_train) self.tree = Treeview(self.win, columns=tuple_train, height=30, show="headings") self.tree.place(x=168, y=40, width=670, height=350) train_info = [ ' 车次 ', ' 出发/到达站', '出发/到达时间', '历时 ', '商/特座', '一等座', '二等座', '高软', '软卧', '动卧', '硬卧', '软座', '硬座', '无座', '其他' ] for i in range(0, len(lis_train)): self.tree.column(lis_train[i], width=len(train_info[i]) * 11, anchor='center') self.tree.heading(lis_train[i], text=train_info[i]) def add_check_button(self): self.v1 = IntVar() self.v2 = IntVar() self.v3 = IntVar() self.v4 = IntVar() self.v5 = IntVar() self.v6 = IntVar() self.v7 = IntVar() self.v1.set("T") self.Check_total = Checkbutton(self.win, text="全部车次", variable=self.v1, onvalue='T') self.Check_total.place(x=168, y=7, width=80, height=30) self.Check_total = Checkbutton(self.win, text="G-高铁", variable=self.v2, onvalue='T') self.Check_total.place(x=258, y=7, width=70, height=30) self.Check_total = Checkbutton(self.win, text="D-动车", variable=self.v3, onvalue='T') self.Check_total.place(x=348, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="Z-直达", variable=self.v4, onvalue='T') self.Check_total.place(x=418, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="T-特快", variable=self.v5, onvalue='T') self.Check_total.place(x=488, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="K-快速", variable=self.v6, onvalue='T') self.Check_total.place(x=568, y=7, width=60, height=30) self.Check_total = Checkbutton(self.win, text="其他", variable=self.v7, onvalue='T') self.Check_total.place(x=648, y=7, width=60, height=30) def get_train_args(self): #输出获得的日期,出发站代码,目的站代码 date = self.start_year.get() + "-" + self.start_mon.get( ) + "-" + self.start_day.get() start_station = self.temp.get() end_station = self.temp2.get() start_station_str = "" end_station_str = "" count1, count2 = 0, 0 with open("res/dict2.txt", mode='r', encoding='utf-8') as f: mes = f.readlines() for i in mes: d = json.loads(i) if start_station in d: start_station_str = d[start_station] else: count1 += 1 if end_station in d: end_station_str = d[end_station] else: count2 += 1 if count1 == len(mes) or count2 == len(mes): messagebox.showwarning(title="友情提示", message="无法找到车站数据") return date, start_station_str, end_station_str def is_leapyear(self): #先判断输入是否是日期,如果是日期执行方法体, a = self.C_year.get() b = self.C_mon.get() c = self.C_day.get() pa_year = '20[\d][\d]' # 2018 if re.compile(pa_year).findall(a) and b in [ "{:02d}".format(x) for x in range(1, 13) ] and c in ["{:02d}".format(x) for x in range(1, 32)]: nowtime = time.localtime() now_time_sp = time.mktime(nowtime) start_time = a + "-" + b + "-" + c + " 23:59:29" #"2018-08-09 23:59:29" start_timestrip = time.strptime(start_time, "%Y-%m-%d %H:%M:%S") start_times = time.mktime(start_timestrip) days = (start_times - now_time_sp) / 60 / 60 / 24 print(days) print(a, b, c) if days > 29: messagebox.showerror(title="警告", message="大于30天无法获取数据") elif days < 0: messagebox.showerror(title="警告", message="小于1天无法获取数据") elif days > 0 and days < 30: if int(a) % 4 == 0 and int(a) % 100 != 0 or int( a) % 400 == 0: #如果是闰年 if (int(b) in (1, 3, 5, 7, 8, 10, 12) and int(c) > 31) or ( (int(b) in (4, 6, 9, 11) and int(c) > 30)) or (int(b) == 2 and int(c) > 29): messagebox.showerror(title="警告", message="你确定这个月有这一天么") else: if (int(b) in (1, 3, 5, 8, 10, 12) and int(c) > 31) or ( (int(b) in (4, 6, 9, 11) and int(c) > 30)) or (int(b) == 2 and int(c) > 28): messagebox.showerror(title="警告", message="你确定这个月有这一天么") else: messagebox.showerror(title="警告", message="请输入正确格式的年:月:日") def manage_date(self): #处理时间,闰年以及当天时间 self.is_leapyear() def change_str(self, mm): for i, j in mm.items(): with open("res/dict.txt", mode='r', encoding='utf-8') as f: mes = f.readlines() for s in mes: d = json.loads(s) if j[0] in d: j[0] = d[j[0]] if j[1] in d: j[1] = d[j[1]] # print(self.new_train_message) #车次信息 non_empty_str = [''] for m, n in mm.items(): mm[m] = ['-' if x in non_empty_str else x for x in n] # 替换''字符为'-' return mm def trans_train_dic(self): #输出出发站-目的站-名字 date, start_station, end_station = self.get_train_args() print(date, start_station, end_station) try: p = Pro_train(date, start_station, end_station) self.train_message = p.get_train_res() # 获得车次信息字典 车次英文 self.train_tick = p.get_tarin_ticket() #获得票价信息 # print(self.train_message) #车次信息 self.new_train_message = self.train_message #复制一份 self.new_train_tick = self.train_tick self.new_train_message = self.change_str(self.new_train_message) self.new_train_tick = self.change_str(self.new_train_tick) return self.new_train_message, self.new_train_tick # 中文字典 except Exception as e: # messagebox.showerror(title="警告",message="无法解析数据,请重新选择") print("错误码:", e.args) def search_train_message(self): self.manage_date() #处理日期-True-transe-view if self.v.get(): self.view_list() else: self.view_price() def clear_tree(self): x = self.tree.get_children() for n in x: self.tree.delete(n) def view_list(self): #显示到网格 # 车次 出发/站 出发到达时间 历时 商务座31 一等座30 二等座29 高软20 软卧22 动卧 硬卧27 软座23 硬座28 无座25 其他21 try: self.clear_tree() self.new_train_message, x = self.trans_train_dic() #生成新车次字典 for i, j in self.new_train_message.items(): self.tree.insert("", "end", values=(i, j[0] + "->" + j[1], j[2] + "->" + j[3], j[4], j[5], j[6], j[7], j[8], j[9], j[10], j[11], j[12], j[13], j[14], j[15])) except Exception as e: # messagebox.showerror(title="警告",message="无法处理数据") print("错误:", e.args) def view_price(self): print("-------票价ok-------") try: self.clear_tree() y, self.new_train_tick = self.trans_train_dic() #生成新车次字典 for i, j in self.new_train_tick.items(): self.tree.insert("", "end", values=(i, j[0] + "->" + j[1], j[2] + "->" + j[3], j[4], j[5], j[6], j[7], j[8], j[9], j[10], j[11], j[12], j[13], j[14], "-")) except Exception as e: # messagebox.showerror(title="警告",message="无法处理数据") print("错误:", e.args)
def __init__(self, **kwargs): super().__init__() title = "Simple Backup | V" + __version__ self.wm_title(title) self.protocol("WM_DELETE_WINDOW", self.on_closing) self.__thread = None self.__files_found = 0 self.__files_copied = 0 config_fn = kwargs.get("config_fn", user_config_filepath()) self.__app_config = Config_Handler(config_fn) self.__curr_config = self.__app_config.default_config_i self.__menu = Menu(self) self.__menu_file = Menu(self.__menu, tearoff=0) self.__menu_file.add_command(label="Quit", command=self.quit) self.__menu_config = Menu(self.__menu, tearoff=0) self.__menu_config.add_command(label="New", command=self.new_config) self.__menu_config.add_command(label="Load", command=self.switch_config) self.__menu_config.add_command(label="Change Default", command=self.change_default_config) self.__menu_config.add_command(label="Rename Current", command=self.rename_curr_conf) self.__menu_config.add_separator() self.__menu_config.add_command(label="Delete Current", command=self.delete_current_config) self.__menu_config.add_command(label="Delete All", command=self.reset_config) self.__menu_help = Menu(self.__menu, tearoff=0) self.__menu_help.add_command(label="Check for Updates", command=self.show_update_popup) self.__menu_help.add_command(label="About", command=self.show_about_popup) self.__menu.add_cascade(label="File", menu=self.__menu_file) self.__menu.add_cascade(label="Config", menu=self.__menu_config) self.__menu.add_cascade(label="Help", menu=self.__menu_help) self.__title_l = Label(self, text=title, font=(16)) self.__curr_config_name_l = Label(self) self.__last_backup_l = Label(self) self.__set_versions_to_keep = Button( self, text="Set Versions To Keep", command=self.update_versions_to_keep) self.__versions_to_keep_l = Label(self) self.__inc_folder_bnt = Button(self, text="Include Another Folder", command=self.add_included_folder) self.__included_folders_lb = Listbox(self, height=4) self.__included_folders_lb.bind("<<ListboxSelect>>", self.remove_selected_included_folder) self.__included_folders_lb.bind('<FocusOut>', self.deselect_included_folder) self.__excl_folder_bnt = Button(self, text="Exclude Another Folder", command=self.add_excluded_folder) self.__excluded_folders_lb = Listbox(self, height=4) self.__excluded_folders_lb.bind("<<ListboxSelect>>", self.remove_selected_excluded_folder) self.__excluded_folders_lb.bind('<FocusOut>', self.deselect_excluded_folder) self.__backup_to_bnt = Button(self, text="Backup Folder", command=self.set_backup_folder) self.__backup_folder_l = Label(self) self.__use_tar_l = Label(self, text="Use Tar") self.__use_tar_var = BooleanVar(self) self.__use_tar_var.trace_add("write", self.use_tar_changed) self.__use_tar = Checkbutton(self, variable=self.__use_tar_var) self.__backup_start_bnt = Button(self, text="Start Backup", command=self.start_backup) self.__progress = Progressbar(self) self.__statusbar = Label(self, text="ok", relief=SUNKEN, anchor=W) self._load_display() self._layout() if self.__app_config.show_help: self.show_help_popup()
def make_peptide_frame(self, parent): pep_f = Frame(parent, borderwidth=1, relief="sunken") self.peptide = IntVar(pep_f, value=0) Checkbutton(pep_f,variable=self.peptide,text="get protein as FASTA")\ .grid(row=1,column=1,sticky="NSW") return pep_f
img4 = PhotoImage("check-nu", file='../images/lime/check-nu.png') img5 = PhotoImage("check-dc", file='../images/lime/check-dc.png') img6 = PhotoImage("check-du", file='../images/lime/check-du.png') style = Style() # both theme_create and theme_settings worked style.theme_create( "yummy", parent="clam", settings={ #style.theme_settings('default', { # start of theme extract 'Checkbutton.indicator': {"element create": ('image', "check-nu", ('active', 'selected', "check-hc"), ('active', "check-hu"), ('disabled', 'selected', "check-dc"), ('selected', "check-nc"), ('disabled', "check-du"), { 'sticky': "w", 'padding':3}) # 'width':24, } # end of theme extract - don't forget to add comma at end when inserting }) style.theme_use('yummy') # 'default' widg = Checkbutton(fr, text='Cheese' ,width=-8) widg1 = Checkbutton(fr, text='Tomato' ,width=-8) widg.grid(column=0,row=11,sticky='nsew', padx=5, pady=5) widg1.grid(column=0,row=12,sticky='nsew', padx=5, pady=5) run_state(fr,widg,widg1) root.mainloop()