class EpFpFrame(ttk.LabelFrame): """ Part of characters panel. Contains ep and fp fields with labels. """ def __init__(self, character_panel): ttk.LabelFrame.__init__(self, character_panel, text=EP_FRAME_TITLE) self.ep_field = CharacterValueField(self, validate_integer, width=3, name=mgc.MAX_EP) self.akt_ep_field = CharacterValueField(self, validate_integer, width=3, name=mgc.ACT_EP, to_trace=self.ep_field.value) self.fp_field = CharacterValueField(self, validate_integer, width=3, name=mgc.MAX_FP) self.akt_fp_field = CharacterValueField(self, validate_integer, width=3, name=mgc.ACT_FP, to_trace=self.fp_field.value) self.is_not_living_state = IntVar() self.is_not_living_state.set(0) self.is_not_living = Checkbutton(self, text='Elettelen', variable=self.is_not_living_state) self.is_not_living_state.trace('w', self._set_living_state) ep_last_column = place_fields_separator( self, self.ep_field, self.akt_ep_field, label_text=EP_LABEL) place_fields_separator( self, self.fp_field, self.akt_fp_field, label_text=FP_LABEL, start_row=1) self.is_not_living.grid(column=ep_last_column, row=0) def reset_frame(self): """ Resets all the child widgets of the frame. """ on_all_children('reset_fld', self) def _set_living_state(self, *_args): if self.is_not_living_state.get(): self.fp_field.disable() self.akt_fp_field.disable() else: self.fp_field.enable() self.akt_fp_field.enable()
def __init__(self, parent): global loaded, devicesLoaded, deviceChosen loaded = IntVar() loaded.set(getNumDevicesLoaded()) loaded.trace("w", updateDevicesLoaded) s = ttk.Style() s.theme_use('default') s.configure("red.Horizontal.TProgressbar", foreground='red', background='red') s.configure("green.Horizontal.TProgressbar", foreground='green', background='green') self.parent = parent self.parent.title("NET232Plus Programmer") self.stations = [] self.frame = tk.Frame(self.parent) # self.configureMenu() self.titleLabel = tk.Label(self.frame, text = 'Details/Instructions', font = 10) self.instructions = tk.Label(self.frame, text = '- Programming stations \ are labelled with both COM ports listed in config.txt\n \ - Click START to begin the upload and verification', pady = 5) devices = getCOMPorts() # Size of window based on how many stations are present root_width = max(700, (len(devices) - 1) * 205) self.parent.geometry(str(root_width) + "x900+0+0") long_len = 10 devicesLoaded = tk.Label(self.frame, text = ("Devices Loaded: " + str(loaded.get())).ljust(long_len), pady = 10) self.buttonFrame = tk.Frame(self.frame) self.clearCounter = tk.Button(self.buttonFrame, text = "Clear Counter", width = 10, bg = gridColor, height = 2, command = clearDevCounter) self.start = tk.Button(self.buttonFrame, text = "START", width = 22, bg = gridColor, height = 3, command = self.startUpload) OPTIONS = [] for option in deviceOptions: OPTIONS.append(option) # print(OPTIONS) def callback(*args): device_details = deviceOptions[deviceChosen.get()] # print(device_details.web_files) # print(device_details.firmware_files) deviceChosen = StringVar(self.parent) deviceChosen.set(OPTIONS[0]) # default value deviceChosen.trace("w", callback) self.optionMenu = tk.OptionMenu(self.frame, deviceChosen, *OPTIONS) self.packObjects() for d in range(0, len(devices)): self.stations.append(Station(root, devices[d], d))
class ResizeImageDialog(CustomDialog): def __init__(self, root, width, height, maintain_aspect_ratio=False, primary_dimension='width', title="Resize", on_change=list(), on_cancel=list(), on_confirm=list(), **kwargs): self.init_width = width self.init_height = height self.init_maintain_aspect_ratio = maintain_aspect_ratio self.init_primary_dimension = primary_dimension self.on_change = on_change self.on_confirm = on_confirm self.on_cancel = on_cancel self.window = Toplevel() self.window.title(title) self.window.transient(root) self.window.grab_set() self.primary_dimension = StringVar() self.primary_dimension.set(primary_dimension) self.resize_mode = StringVar() self.resize_mode.set('percentage') self.resize_percentage = IntVar() self.resize_percentage.set(100.0) self.resize_width = IntVar() self.resize_width.set(width) self.resize_height = IntVar() self.resize_height.set(height) self.maintain_aspect_ratio = IntVar() # See https://stackoverflow.com/a/4140988/11628429 self.vcmd_is_float = (self.window.register(self.is_float), '%P') self.vcmd_is_int = (self.window.register(self.is_int), '%P') self.percentage_radiobutton = Radiobutton(self.window, text='By percentage', value='percentage', variable=self.resize_mode, command=self.set_mode) self.percentage_radiobutton.grid(row=0, column=0) self.percentage_entry = Spinbox(self.window, from_=0, to=float('inf'), textvariable=self.resize_percentage, validate='all', validatecommand=self.vcmd_is_float) self.percentage_entry.grid(row=0, column=1) self.absolute_radiobutton = Radiobutton(self.window, text='By absolute value', value='absolute', variable=self.resize_mode, command=self.set_mode) self.absolute_radiobutton.grid(row=2, column=0) self.ratio_checkbox = Checkbutton(self.window, text='Maintain aspect ratio', variable=self.maintain_aspect_ratio, command=self.ratio_change) self.ratio_checkbox.grid(row=3, column=0) self.width_label = Label(self.window, text='Width') self.width_label.grid(row=5, column=0) self.width_entry = Spinbox( self.window, from_=0, to=float('inf'), textvariable=self.resize_width, validate='all', validatecommand=self.vcmd_is_int ) # needs a command to respect aspect ratio on change self.width_entry.grid(row=5, column=1) self.height_label = Label(self.window, text='Height') self.height_label.grid(row=6, column=0) self.height_entry = Spinbox(self.window, from_=0, to=float('inf'), textvariable=self.resize_height, validate='all', validatecommand=self.vcmd_is_int) self.height_entry.grid(row=6, column=1) self.cancel_button = Button(self.window, text='Cancel', command=self.cancel) self.cancel_button.grid(row=9, column=0) self.reset_button = Button(self.window, text='Reset', command=self.reset) self.reset_button.grid(row=9, column=1) self.confirm_button = Button(self.window, text='Confirm', command=self.confirm) self.confirm_button.grid(row=9, column=2) self.resize_percentage.trace('w', self.on_percentage_change) self.resize_width_trace_id = self.resize_width.trace( 'w', self.on_width_change) self.resize_height_trace_id = self.resize_height.trace( 'w', self.on_height_change) self.set_mode() def set_resize_width_without_trace(self, value): if not isinstance(value, int): raise TypeError('height should be an int') self.resize_width.trace_vdelete("w", self.resize_width_trace_id) self.resize_width.set(value) self.resize_width_trace_id = self.resize_width.trace( 'w', self.on_width_change) def set_resize_height_without_trace(self, value): if not isinstance(value, int): raise TypeError('width should be an int') self.resize_height.trace_vdelete("w", self.resize_height_trace_id) self.resize_height.set(value) self.resize_height_trace_id = self.resize_height.trace( 'w', self.on_height_change) def on_update(self, *args): mode = self.resize_mode.get() for callback in self.on_change: if mode == 'percentage': percentage = self.resize_percentage.get() / 100 callback(percentage, percentage, self.maintain_aspect_ratio.get(), self.primary_dimension.get()) else: callback(self.resize_width.get(), self.resize_height.get(), self.maintain_aspect_ratio.get(), self.primary_dimension.get()) def on_percentage_change(self, *args): self.on_update() def on_width_change(self, *args): self.primary_dimension.set('width') if self.maintain_aspect_ratio.get(): self.set_resize_height_without_trace( round(self.init_height * (self.resize_width.get() / self.init_width))) self.on_update() def on_height_change(self, *args): self.primary_dimension.set('height') if self.maintain_aspect_ratio.get(): self.set_resize_width_without_trace( round(self.init_width * (self.resize_height.get() / self.init_height))) self.on_update() def reset(self): self.resize_percentage.set(100.0) self.set_resize_width_without_trace(self.init_width) self.set_resize_height_without_trace(self.init_height) self.maintain_aspect_ratio.set(self.init_maintain_aspect_ratio) self.primary_dimension.set(self.init_primary_dimension) self.on_update() def set_mode(self): mode = self.resize_mode.get() if mode == 'percentage': self.percentage_entry.config(state='normal') self.ratio_checkbox.config(state='disabled') self.width_label.config(state='disabled') self.width_entry.config(state='disabled') self.height_label.config(state='disabled') self.height_entry.config(state='disabled') else: self.percentage_entry.config(state='disabled') self.ratio_checkbox.config(state='normal') self.width_label.config(state='normal') self.width_entry.config(state='normal') self.height_label.config(state='normal') self.height_entry.config(state='normal') def is_float(self, P): try: float(P) return True except ValueError: return False def is_int(self, P): return str.isdecimal(P) def ratio_change(self): if self.maintain_aspect_ratio.get(): if self.primary_dimension.get() == 'width': self.set_resize_height_without_trace( round(self.init_height * (self.resize_width.get() / self.init_width))) else: self.set_resize_width_without_trace( round(self.init_width * (self.resize_height.get() / self.init_height))) self.on_update() print(self.maintain_aspect_ratio.get()) print('w', self.resize_width.get()) print('h', self.resize_height.get())
class MyApp(Tk): """ This class serves as a central control. Where are all process are launched and variables are set and shared. """ __title__ = "Senior" def __init__(self, *args, **kwargs): Tk.__init__(self, *args, **kwargs) container = Frame(self) container.grid() self.serial = SerialComm() self.frames = {} self.q = LifoQueue() self.eye_tracker = EyeTracker(self.q) self.variables = {} self.fps = IntVar() self.fps.set(20) self.temp = IntVar() self.temp.set(20) self.temp.trace("w", self.send_command) self.variables[self.temp.__str__()] = 't', self.temp self.temp_current = StringVar() self.temp_current.set('Temperature') self.tts = StringVar() self.tts.set('Type and Play') self.temp_offset = IntVar() self.temp_offset.set(5) self.temp_offset.trace("w", self.send_command) self.variables[self.temp_offset.__str__()] = 'o', self.temp_offset self.samples = 9 self.window = IntVar() self.window.trace("w", self.send_command) self.variables[self.window.__str__()] = 'w', self.window self.mouse_control = BooleanVar() self.mouse_control.set(False) self.talk = BooleanVar() self.talk.set(True) self.alarm = BooleanVar() self.alarm.set(False) self.alarm.trace("w", self.send_command) self.variables[self.alarm.__str__()] = 'a', self.alarm self.light = BooleanVar() self.light.set(False) self.light.trace("w", self.send_command) self.variables[self.light.__str__()] = 'l', self.light self.heater = BooleanVar() self.heater.set(False) self.heater.trace("w", self.send_command) self.variables[self.heater.__str__()] = 'h', self.heater self.ac = BooleanVar() self.ac.set(False) self.ac.trace("w", self.send_command) self.variables[self.ac.__str__()] = 'f', self.ac self.move = BooleanVar() self.move.set(False) self.w, self.h = pyautogui.size() self.hor_div = DoubleVar() self.hor_div.set(5) self.hor_div.trace("w", self.send_command) self.variables[self.hor_div.__str__()] = 'hor', self.hor_div self.ver_div = DoubleVar() self.ver_div.set(5) self.ver_div.trace("w", self.send_command) self.variables[self.ver_div.__str__()] = 'ver', self.ver_div self.mouse_directions = [] self.mouse = MouseAndSpeech(self) self.t = Thread(target=self.mouse.process) self.t.start() self.frame = None self.draw = False frame = Preview(container, self) self.frames[Preview] = frame frame.grid(row=0, column=1, sticky="nsew", rowspan=100) self.current_frame = frame frame = Settings(container, self) self.frames[Settings] = frame frame.grid(row=0, column=0, sticky="nsew", pady=10, padx=10) frame.grid_remove() frame = Applications(container, self) self.frames[Applications] = frame frame.grid(row=0, column=0, sticky="nsew", pady=10, padx=10) frame.grid_remove() # Menu Bar menu = MyMenu(self) self.config(menu=menu) Tk.iconbitmap(self, default=resource_path('icon.ico')) Tk.wm_title(self, "Senior") w = (self.winfo_screenwidth() - self.eye_tracker.window_size) // 2 self.geometry('+{}+{}'.format(w, 0)) self.protocol("WM_DELETE_WINDOW", lambda: self.close()) def show_frame(self, cont): """ This method is used to switch betwen views. """ if self.current_frame is not None: self.current_frame.grid_remove() frame = self.frames[cont] frame.grid() self.current_frame = frame if cont is Applications: frame.button_alarm.focus() def send_command(self, widget, *args): """ This method send data to the Arduino whenever a button is clicked. """ w = self.variables[widget] try: indicator = w[0] value = str(int(w[1].get())) if indicator == 'f' and value == '1': self.heater.set(False) self.serial.send_serial('h0') elif indicator == 'h' and value == '1': self.ac.set(False) self.serial.send_serial('f0') elif indicator == 't': self.heater.set(False) self.ac.set(False) s = indicator + value self.serial.send_serial(s) if len(value) > 0: value = float(w[1].get()) if indicator in ['ver', 'hor']: x_offset = self.ver_div.get() y_offset = self.hor_div.get() if indicator == 'ver': y_offset = value * (self.h // 100) elif indicator == 'hor': x_offset = value * (self.w // 100) self.mouse_directions = [(-x_offset, -y_offset), (0, -y_offset), (x_offset, -y_offset), (-x_offset, 0), 0, (x_offset, 0), (-x_offset, y_offset), (0, y_offset), (x_offset, y_offset), 0] except: pass def close(self): """ Method used to to close the program orderly so no threads are left hanging. """ print(self.__title__) while self.mouse.isTalking: print('Is Talking') self.eye_tracker.video_capture.release() clear_queue(self.q) self.q.put(False) self.q.join() self.t.join() self.destroy()
class UserInterface(UIfunctions): def __init__(self, filehandler, databasehandler, path=None): self.title = "OpenKeynote (BETA)" self._filehandler = filehandler self._databasehandler = databasehandler self.path = path self.itemlist = [] self.root = Tk() self.previeweditem = "" self.editeditem = "" self.case_selected = IntVar() self.parentname = "" self.autosave = IntVar() self._html_path = None self._default_title = self.title self.main_window() self.tree_view() self.frame_vertical_bar() self.bindings_and_menu() self.frame_setup() self.update_status() self.root.mainloop() def main_window(self, *args): self.mainframe = Frame(self.root) self.mainframe.grid(column=0, row=0, sticky=E+W+N+S) self.bottomframe = Frame(self.root) self.bottomframe.grid(column=0, row=1, sticky=E+W) self.statusbar = Label( self.bottomframe, text=self._filehandler.statustext, anchor=W) self.statusbar.pack(fill=BOTH, padx=0, pady=0) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.root.rowconfigure(1, pad=10) self.pw = PanedWindow(self.mainframe, orient=HORIZONTAL) self.pw.pack(fill=BOTH, expand=1) self.pane_left = Frame(self.root) self.pw.add(self.pane_left) self.pane_right = Frame(self.root) self.pw.add(self.pane_right) self.frame_left = Frame(self.pane_left) self.frame_left.pack(fill=BOTH, expand=1, padx=3, pady=3) self.frame_center = Frame(self.pane_right) self.frame_center.grid(row=0, column=0, sticky=W+N, rowspan=4) self.frame_right = Frame(self.pane_right) self.frame_right.grid(row=0, column=1, sticky=W+E+N+S, padx=3, pady=3) self.pane_right.columnconfigure(1, weight=1) self.pane_right.rowconfigure(0, weight=1) self.sf1 = Text(self.frame_left, height=1, width=25, borderwidth=1, relief="solid", highlightthickness=0) self.sf1.insert(1.0, "TODO: Searchbar") self.sf1.grid(row=0, column=0, sticky=W+E+N+S, pady=5) self.sf1.config(state=DISABLED) self.cs = Button(self.frame_left, text="X", width=1) self.cs.grid(row=0, column=1) self.frame_left.columnconfigure(0, weight=1) def tree_view(self, *args): """ Tree view """ self.l1 = ttk.Treeview(self.frame_left, columns=["stuff"], show="tree") self.yscroll = Scrollbar(self.frame_left, orient=VERTICAL) self.yscroll.config(width=10) self.l1['yscrollcommand'] = self.yscroll.set self.yscroll['command'] = self.l1.yview self.l1.grid(row=1, column=0, columnspan=3, padx=30, pady=10, sticky=N+S+E+W) self.yscroll.grid(row=1, column=0, columnspan=3, sticky=N+S+E) self.l1.bind("<ButtonRelease-1>", self.change_selection) self.frame_left.rowconfigure(1, weight=1) def frame_vertical_bar(self, *args): self.vbs = [] middlebuttons = ("New Item", "New Subitem", "Delete", "Rename", "Change Parent","- Descriptions (BETA) -") middlefunctions = ( lambda: self.add_item(parent=self.parentname), lambda: self.add_item(parent=self.previeweditem), lambda: self.delete_item_dialog(), self.rename_item_dialog, self.change_parent_dialog, lambda: self.description_window(database_rows=self._databasehandler.view()) #lambda: self.save_keynote_to_database(title="title",keynote="KN10", entreprise="min entreprise", category="") #self.save_all_keynotes_to_database ) for a, button_text in enumerate(middlebuttons): self.vbs.append(ttk.Button(self.frame_center, text=button_text)) self.vbs[a].pack(fill=BOTH) self.vbs[a].config(command=middlefunctions[a], width=10) for x in [2, 3, 4]: self.vbs[x].config(state=DISABLED) self.tx1 = Label(self.frame_right, text="Preview", anchor=W) self.tx1.grid(row=0, column=0, columnspan=3, sticky=W+E) self.tx2 = Label(self.frame_right, text="Editing", anchor=W) self.tx2.grid(row=2, column=0, sticky=W+E) self.e1 = scrolledtext.ScrolledText(self.frame_right, fg="#555", font=("Courier", 13), padx=10, pady=10, highlightthickness=0, borderwidth=1, relief="solid") self.e1.grid(row=1, column=0, columnspan=3, sticky=N+S+E+W) # was Text before self.e2 = scrolledtext.ScrolledText(self.frame_right, font=("Courier", 13), borderwidth=1, relief="solid", padx=10, pady=10, highlightthickness=0) self.e2.grid(row=3, column=0, columnspan=3, sticky=E+W+S+N) # AUTOSAVE self.autosaveFrame = LabelFrame(self.frame_center, text=' Autosave ') self.autosaveFrame.pack(fill=BOTH) self.autosave.trace( 'w', lambda *args: print(f"Autosave: {self.autosave.get()}")) self.autosaveCheck = Checkbutton( self.autosaveFrame, text="Enabled", variable=self.autosave, anchor=W) self.autosaveCheck.select() self.autosaveCheck.pack(fill=BOTH) self.labelsFrame = LabelFrame(self.frame_center, text=' Change Case ') self.labelsFrame.pack(fill=BOTH) # CASE BUTTONS self.case_radiobuttons = [] self.case_selected.set(99) rbtns = ['No change', 'UPPERCASE', 'lowercase', 'First Letter'] for a, button_text in enumerate(rbtns): self.case_radiobuttons.append( Radiobutton(self.labelsFrame, text=button_text, variable=self.case_selected, value=a, command=self.change_case, width=10, anchor=W)) self.case_radiobuttons[a].grid(sticky="W", row=a) def change_case(self, *args): pass def bindings_and_menu(self, *args): """ Main key bindings """ if os.name == "nt": self.CTRL = "Control" self.MBTN = "3" else: self.CTRL = "Command" self.MBTN = "2" def bindings_key(event): if event.state == 8 or event.state == 12: return else: return("break") self.sf1.bind("<Tab>", lambda a: self.focus_on(target=self.l1)) self.sf1.bind("<Shift-Tab>", lambda a: self.focus_on(target=self.vb2)) self.e1.bind("<Key>", bindings_key) self.e1.bind("<Tab>", lambda a: self.focus_on(target=self.e2)) self.e1.bind( "<Shift-Tab>", lambda a: self.focus_on(target=self.vbs[-1])) self.e2.bind("<Tab>", lambda a: self.focus_on(target=self.vb1)) self.e2.bind("<Shift-Tab>", lambda a: self.focus_on(target=self.e1)) self.vb1 = ttk.Button(self.frame_right, text="Edit") self.vb1.grid(row=2, column=1) self.vb1.config(command=self.edit_item) self.vb2 = ttk.Button(self.frame_right, text="Save") self.vb2.grid(row=2, column=2) self.vb2.config(command=self.saveitem) self.frame_right.rowconfigure(1, weight=1) self.frame_right.rowconfigure(3, weight=1) self.frame_right.columnconfigure(0, weight=1) self.menu = Menu(self.root) self.root.config(menu=self.menu) file = Menu(self.menu, tearoff=0) # TODO is it a win thing? file.add_command(label='New File*', command=self.close_file) file.add_command( label='Open File...', accelerator=f"{self.CTRL}-o", command=self.open_file_dialog) file.add_command(label='Save File', accelerator=f"{self.CTRL}-s", command=self.save_file) file.add_command(label='Save File As...', command=self.save_file_dialog) file.add_command(label='Close file', command=self.close_file) file.add_command( label='Exit', accelerator=f"{self.CTRL}-q", command=self.client_exit) self.menu.add_cascade(label='File', menu=file) self.clickmenu = Menu(self.root, tearoff=0) self.clickmenu.add_command(label="Cut") self.clickmenu.add_command(label="Copy") self.clickmenu.add_command(label="Paste") self.root.bind_class( "Text", f"<Button-{self.MBTN}><ButtonRelease-{self.MBTN}>", lambda event=None: self.right_click_menu()) menu_edit = Menu(self.menu, tearoff=0) menu_edit.add_command(label='Select All', accelerator=f"{self.CTRL}-a", command=self.select_all) self.root.bind(f"<{self.CTRL}-a>", self.select_all) self.e1.bind(f"<{self.CTRL}-a>", self.select_all) self.e1.bind(f"<{self.CTRL}-c>", self.e1.event_generate("<<Copy>>")) self.e2.bind(f"<{self.CTRL}-a>", self.select_all) menu_edit.add_command(label='Cut', accelerator=f"{self.CTRL}-x", command=lambda: self.root.event_generate("<<Cut>>")) menu_edit.add_command(label='Copy', accelerator=f"{self.CTRL}-c", command=lambda: self.copy_text()) menu_edit.add_command(label='Paste', accelerator=f"{self.CTRL}-v", command=lambda: self.root.event_generate("<<Paste>>")) self.menu.add_cascade(label='Edit', menu=menu_edit) menu_help = Menu(self.menu, tearoff=0) menu_help.add_command(label='About', command=self.about) self.menu.add_cascade(label='Help', menu=menu_help) for i in "Up,Down,Right,Return,Left".split(","): self.root.bind("<"+i+">", self.change_selection) self.e1.bind("<F2>", self.rename_item_dialog) self.e1.bind(f"<{self.CTRL}-s>", None) self.e1.bind(f"<{self.CTRL}-o>", None) self.root.bind("<F2>", self.rename_item_dialog) self.root.bind(f"<{self.CTRL}-s>", self.save_file) self.root.bind(f"<{self.CTRL}-o>", self.open_file_dialog) def copy_text(self, event=None): w = self.root.focus_get() w.event_generate("<<Copy>>") def update_title(self, title=""): self.root.title(title) def frame_setup(self, *args): """ Misc UI functions """ # sharp fonts in high res (https://stackoverflow.com/questions/41315873/ # attempting-to-resolve-blurred-tkinter-text-scaling-on-windows-10-high-dpi-disp) if os.name == "nt": # TODO # self.root.protocol("WM_DELETE_WINDOW", self.client_exit) from ctypes import windll, pointer, wintypes try: windll.shcore.SetProcessDpiAwareness(1) except Exception: pass # this will fail on Windows Server and maybe early Windows # TODO: Put link to ico file on windows. try: iconpath = Path("icon.ico") self.root.iconbitmap(Path()) except: print("error with icon") else: # mac? self.root.createcommand('exit', self.client_exit) self.root.title(self.title) if self.path: self.open_file(path=self.path) """ TODO: ICON /Windows self.root.iconbitmap("/Users/msn/Dropbox/py/Git/OpenKeynote/images/ico.icns") img = Image( "photo", file="/Users/msn/Dropbox/py/Git/OpenKeynote/images/large.gif") self.root.iconphoto(True, img) # you may also want to try this. self.root.call('wm','iconphoto', self.root._w, img) """ self.width = min(int(self.root.winfo_screenwidth()-500), 1500) self.height = int(self.root.winfo_screenheight()-500) self.root.winfo_width() self.root.winfo_height() self.x = (self.root.winfo_screenwidth() // 2) - (self.width // 2) # self.x = 0 self.y = (self.root.winfo_screenheight() // 2) - (self.height // 2) # self.y = 50 self.root.geometry(f"{self.width}x{self.height}+{self.x}+{self.y}") self.root.update() self.root.after(0, self.fixUI) def right_click_menu(self, event=None): x, y = self.root.winfo_pointerxy() w = self.root.winfo_containing(x, y) # https://stackoverflow.com/a/8476726/11514850 # w = self.root self.clickmenu.entryconfigure("Cut", command=lambda: w.event_generate("<<Cut>>")) self.clickmenu.entryconfigure("Copy", command=lambda: w.event_generate("<<Copy>>")) self.clickmenu.entryconfigure("Paste", command=lambda: w.event_generate("<<Paste>>")) self.clickmenu.tk.call("tk_popup", self.clickmenu, w.winfo_pointerx(), w.winfo_pointery()) def update_status(self, event=None): """ Set statusbar in bottom of the window """ self.statusbar.config(text=self._filehandler.refresh_status()) self.root.after(100, self.update_status) def client_exit(self, *args): answer = messagebox.askyesnocancel('quit?', 'Save file first?') if answer == True: self.save_file() sys.exit() if answer == None: return if answer == False: exit()
class App(Tk): STEP_MODE: IntVar # Пошаговое проигрывание анимации. SHOW_INFLECTION_POINTS: IntVar started = False # Мы начали искать корни, в это время нельзя менять менять уравнение. paused = False # Пауза для анимации. done: bool = False st: float en: float div: int eps: float lin_x: any # Множество точек для построения графика. lin_space_size: int = 400 # Кол-во точек для построения графика solver: HordEquationSolver expr: StringVar # Введенное пользователем выражение # График ax: plt.Axes plots: List[Line2D] = [] h_lines: List[Line2D] = [] # Горизонтальные линии main_plot: any = None deriv_plot: any = None inflection_points: any = None # Список решений solutions: List[Solution] = [] solution_ids: List[str] = [] tree: Treeview # Таблица результатов b_start: Button # Кнопка начала/остановки lin_space_label: Label # Надпись о точности графика cached_function: any # Декодированная функция, что бы каждый раз не вызывать eval after_job_id: any = None # id отложенного вызова функции для её отмены def f(self, x): return self.cached_function(x) def __init__(self, st: float, en: float, div: int, eps: float): super().__init__() self.st = st self.en = en self.div = div self.eps = eps self.lin_x = np.linspace( st, en, self.lin_space_size) # Множество точек для построения графика. fig = plt.Figure(tight_layout=True) self.ax = fig.add_subplot() self.ax.axhline(0, color='black') self.grid_columnconfigure(0, weight=2) self.grid_columnconfigure(1, weight=1) self.grid_rowconfigure(0, weight=1) self.fagg = FigureCanvasTkAgg(fig, self) self.fagg.get_tk_widget().grid(row=0, column=0, sticky='WNSE') self.frame = Frame(self) self.frame.grid(row=0, column=1, sticky='WNSE', rowspan=2) self.init_sidebar() self.solver = HordEquationSolver(st, en, div, eps, self.f) self.prepare() self.fagg.draw() button_frame = Frame(self) button_frame.grid(row=1, column=0, sticky='WE') self.b_start = Button(button_frame, text='start') self.b_start.pack(side='left', anchor='center') self.b_start.bind('<Button>', self.start) Button(button_frame, text='reset', command=self.reset).pack(side='left', anchor='center') def init_sidebar(self): self.cached_function = eval('lambda x: ' + DEFAULT_EXPRESSION) self.expr = StringVar(self) self.expr.set(DEFAULT_EXPRESSION) self.expr.trace_variable('w', self.var_debounce(self.expression_input)) # Динамические переменные для входных полей start_v = DoubleVar(self, value=self.st) end = DoubleVar(self, value=self.en) epsilon = DoubleVar(self, value=self.eps) divs = IntVar(self, value=self.div) lin_space_var = DoubleVar(self, value=math.log(self.lin_space_size, LOG_BASE)) variables = ((start_v, 'st'), (end, 'en'), (epsilon, 'eps'), (divs, 'div')) # Функция обертка для сигнализирования о смене переменной. def outer(var, var_name): def inner(*_args): try: self.params_input(var.get(), var_name) except Exception: pass return inner for (v, name) in variables: v.trace('w', self.debounce(outer(v, name), 250)) lin_debouncer = self.debounce(self.modify_lin_space_size, 150) lin_space_var.trace( 'w', lambda *_args: self.modify_lin_space_size_callback( lin_space_var.get(), lin_debouncer)) self.frame.columnconfigure(1, weight=2) Label(self.frame, text='Выражение:').grid(column=0, row=0, columnspan=2, sticky='EW') Entry(self.frame, textvariable=self.expr).grid(column=0, row=1, columnspan=2, sticky='EW') self.frame.rowconfigure(2, minsize=25) Label(self.frame, text='Начало').grid(column=0, row=3, sticky='W') Entry(self.frame, textvariable=start_v).grid(column=1, row=3, sticky='EW') Label(self.frame, text='Конец').grid(column=0, row=4, sticky='W') Entry(self.frame, textvariable=end).grid(column=1, row=4, sticky='EW') Label(self.frame, text='Точность').grid(column=0, row=5, sticky='W') Entry(self.frame, textvariable=epsilon).grid(column=1, row=5, sticky='EW') Label(self.frame, text='Разделение').grid(column=0, row=6, sticky='W') Entry(self.frame, textvariable=divs).grid(column=1, row=6, sticky='EW') self.frame.rowconfigure(7, minsize=25) self.lin_space_label = Label( self.frame, text=f'Количество точек графика: {self.lin_space_size}') self.lin_space_label.grid(column=0, row=8, columnspan=2, sticky='W') w = Scale(self.frame, from_=math.log(5, LOG_BASE), to=math.log(MAX_LINE_SPACE_SIZE, LOG_BASE), resolution=0.1 / LOG_BASE, orient=HORIZONTAL, variable=lin_space_var) w.grid(column=0, row=9, columnspan=2, sticky='EW') self.tree = Treeview(self.frame) self.tree['columns'] = (1, 2, 3, 4, 5) self.tree.column('#0', width=35) self.tree.column(1, width=130, anchor='center') self.tree.column(2, width=80, anchor='center') self.tree.column(3, width=80, anchor='center') self.tree.column(4, width=80, anchor='center') self.tree.column(5, width=80, anchor='center') self.tree.heading('#0', text='№') self.tree.heading(1, text='Интервал') self.tree.heading(2, text='Корень') self.tree.heading(3, text='Значение') self.tree.heading(4, text='Итераций') self.tree.heading(5, text='Ошибка') self.tree.grid(column=0, row=10, columnspan=2, sticky='EWSN') self.STEP_MODE = IntVar(self, value=0) self.SHOW_INFLECTION_POINTS = IntVar(self, value=1) self.SHOW_INFLECTION_POINTS.trace( 'w', lambda *_args: self.redraw_main_plot(True)) Checkbutton(self.frame, text='Пошаговый режим', variable=self.STEP_MODE).grid(column=0, row=11, sticky='WS') Checkbutton(self.frame, text='Показывать точка перегиба', variable=self.SHOW_INFLECTION_POINTS)\ .grid(column=0, row=12, sticky='WS') def modify_lin_space_size_callback(self, value, callback): self.lin_space_label.configure( text=f'Количество точек графика: {round(LOG_BASE**value)}') callback(value) def modify_lin_space_size(self, size): self.lin_space_size = round(LOG_BASE**size) self.redraw_main_plot(True) def redraw_main_plot(self, draw=False): if self.st != self.lin_x.min() or self.en != self.lin_x.max( ) or self.lin_space_size != len(self.lin_x): self.lin_x = np.linspace(self.st, self.en, self.lin_space_size) if self.main_plot: self.main_plot.remove() if self.deriv_plot: self.deriv_plot.remove() self.deriv_plot = None if self.inflection_points: self.inflection_points.remove() self.inflection_points = None v = self.f(self.lin_x) self.main_plot = self.ax.plot(self.lin_x, v, label='f(x)', color='tab:blue')[0] if self.SHOW_INFLECTION_POINTS.get(): v2 = np.diff(v) v2 = np.insert(v2, 0, v2[0] - (v2[1] - v2[0])) v2 /= ((self.en - self.st) / self.lin_space_size) v2 = np.diff(v2) second_derivative_is_zero = all([x < self.eps for x in v2]) if not second_derivative_is_zero: v2 = np.append(v2, v2[-1]) v2 /= ((self.en - self.st) / self.lin_space_size) inflection_points_x = [] inflection_points_y = [] for i in range(1, len(v2)): if v2[i - 1] * v2[i] <= 0: if v[i - 1] == 0: continue n = i - 1 if v2[i - 1] < v2[i] else i x = self.st + (self.en - self.st) / self.lin_space_size * n y = self.f(x) inflection_points_x.append(x) inflection_points_y.append(y) self.inflection_points = self.ax.scatter(inflection_points_x, inflection_points_y, 80, marker='x', color='violet') self.deriv_plot = self.ax.plot(self.lin_x, v2, label="f''(x)", color='tab:green')[0] mx_y = max(v) mn_y = min(v) m = (mx_y - mn_y) / 50 dx = abs(self.en - self.st) * 0.05 self.ax.set_ylim(mn_y - m, mx_y + m) self.ax.set_xlim(self.st - dx, self.en + dx) if draw: self.fagg.draw() # Первичное отображение, подготавливает все данные для него. def prepare(self): step = (self.en - self.st) / self.div self.redraw_main_plot() for plt in self.plots: plt.remove() self.plots.clear() for line in self.h_lines: line.remove() self.h_lines.clear() for i in range(self.div + 1): x = (self.st + step * i) self.h_lines.append(self.ax.axvline(x, color='black')) self.plots = [ self.ax.plot(self.lin_x, self.solver.hord.k * self.lin_x + self.solver.hord.b, label='lin', color='tab:orange')[0], self.ax.scatter([self.solver.p1.x], [self.solver.p1.y], marker='o', color='red'), self.ax.scatter([self.solver.p_fixed.x], [self.solver.p_fixed.y], marker='o', color='blue') ] self.fagg.draw() def var_debounce(self, func: Callable[[str], None], t: int = 500) -> Callable: def inner(*args): func(self.tk.globalgetvar(args[0])) return self.debounce(inner, t) def debounce(self, func: Callable[..., None], t: int = 500) -> Callable: return Debouncer(self, func, t) def expression_input(self, value): try: self.cached_function = eval('lambda x: ' + value) self.reset() except Exception as e: # traceback.print_exc() # print(e) pass def params_input(self, value, var_name): self.__setattr__(var_name, value) self.reset() def reset(self): if self.after_job_id: self.after_cancel(self.after_job_id) self.started = False self.done = False self.tree.delete(*self.solution_ids) self.solutions.clear() self.solution_ids.clear() self.solver = HordEquationSolver(self.st, self.en, self.div, self.eps, self.f) self.b_start.configure(text='start') self.b_start.bind('<Button>', self.start) self.prepare() def start(self, event): if self.STEP_MODE.get(): self.step_solve() else: if not self.started or self.paused: self.started = True self.paused = False self.step_solve() event.widget.configure(text='stop') event.widget.bind('<Button>', self.stop) def stop(self, event): self.paused = True if self.after_job_id: self.after_cancel(self.after_job_id) event.widget.configure(text='start') event.widget.bind('<Button>', self.start) # Перерисовка хорды и точек пересечения. def redraw_solution(self): for pt in self.plots: pt.remove() self.plots = [ self.ax.plot(self.lin_x, self.solver.hord.k * self.lin_x + self.solver.hord.b, label='lin', color='tab:orange')[0], self.ax.scatter([self.solver.p1.x], [self.solver.p1.y], marker='o', color='red'), self.ax.scatter([self.solver.p_fixed.x], [self.solver.p_fixed.y], marker='o', color='blue') ] self.fagg.draw() self.ax.relim() def step_solve(self): if self.started and not self.solver.done or self.STEP_MODE.get(): status = self.solver.next_step() self.redraw_solution() if not status: if self.started and not self.paused and not self.STEP_MODE.get( ): self.after_job_id = self.after(100, self.step_solve) else: self.add_solution(self.solver.get_solution()) if self.solver.next_segment(): print('DONE!!!!') self.b_start.configure(text='DONE!!!!') self.b_start.unbind('<Button>') else: self.redraw_solution() if not self.STEP_MODE.get(): self.after_job_id = self.after(200, self.step_solve) def add_solution(self, sol): if sol.err == 0: interval = f'({sol.interval[0]:.5} : {sol.interval[1]:.5})' iid = self.tree.insert('', 'end', text=str(len(self.solutions) + 1), values=(interval, f'{sol.x:.7}', f'{sol.y:.5}', sol.iter, sol.err)) else: iid = self.tree.insert('', 'end', text=str(len(self.solutions) + 1), values=('', '', '', '', sol.err)) self.solutions.append(sol) self.solution_ids.append(iid)
class PanelFrame(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.parent = parent CTRL_BUTTONS = ["TOGGLE BT", "SET PORT", "DELAY (seconds)"] #use radiobuttons to set one thing at once? -toggle bt starts the run... ENTRIES = ["", str(use_Reader(1)), str(use_Reader(3))] for i in range(3): print(ENTRIES[i]) buttons = [] self.entries = [] self.e_vars = [] self.var = IntVar() #self.colconfigure(0, weight=1) #self.colconfigure(1, weight=0) self.prev = 0 self.active = 0 self.var.set(0) for i in range(len(CTRL_BUTTONS)): el = self.create_button_frame(CTRL_BUTTONS[i], ENTRIES[i], i) buttons.append(el) e_var = StringVar() #print(ENTRIES[i])#debug e_var.set(ENTRIES[i]) e = Entry(self, textvariable=e_var) self.entries.append(e) self.e_vars.append(e_var) #self.rowconfigure(1, weight=1) el.grid(row=0, column=i, sticky="nsew") e.grid(row=1, column=i, sticky="nsew") self.prev_vars = [] for ev in self.e_vars: self.prev_vars.append(ev.get()) #disable useless entry under "toggle BT" self.entries[0].config(state=tk.DISABLED) self.activate_entries() self.var.trace("w", self.activate_entries) def create_button_frame(self, b_name, entry_text, index): button = Radiobutton(self, text=b_name,indicatoron=False,\ variable=self.var, value=index) return button def activate_entries(self, *args): #CTRL_BUTTONS =["TOGGLE BT","SET PORT", "DELAY (seconds)"] self.active = self.var.get() for i in range(1, len(self.e_vars)): if i == self.active: #self.entries[i].enable() self.prev_vars[i] = self.e_vars[i].get() self.entries[i].config(state=tk.NORMAL) else: #copy the old values (just debug) self.prev_vars[i] = self.e_vars[i].get() #self.e_vars[i].set(self.prev_vars[self.active]) #self.entries[i].disable() self.entries[i].config(state=tk.DISABLED) if self.active == 0: manage_Reader(1) #connect else: manage_Reader(2) #disconnect if self.active == 1: #set port #print(self.e_vars[1].get())#debug if (self.e_vars[1].get().isalnum()): setup_Reader(2, self.e_vars[1].get()) elif self.prev == 2: #set delay #print(self.e_vars[2].get())#debug if (self.e_vars[2].get().isdigit() and self.e_vars[2].get().isalnum()): setup_Reader(4, int(self.e_vars[2].get())) #if self.prev == self.active: # self.var.set(len(self.e_vars)) self.prev = self.active
class ImageSlider(Frame): try: NOIMAGE = PILImage.open( open( os.path.join(os.path.dirname(__file__), 'images/noimages.png'), 'rb')) BUTTONLEFT = PILImage.open( open(os.path.join(os.path.dirname(__file__), 'images/left.png'), 'rb')) BUTTONRIGHT = PILImage.open( open(os.path.join(os.path.dirname(__file__), 'images/right.png'), 'rb')) except FileNotFoundError as e: try: NOIMAGE = PILImage.open(open('images/noimages.png', 'rb')) BUTTONLEFT = PILImage.open(open('images/left.png', 'rb')) BUTTONRIGHT = PILImage.open(open('images/right.png', 'rb')) except Exception as f: raise f def __init__(self, parent, directory=os.getcwd(), placeholder=NOIMAGE, leftarrow=BUTTONLEFT, rightarrow=BUTTONRIGHT, *args, **kw): Frame.__init__(self, parent, *args, **kw) self.directory = directory if placeholder != ImageSlider.NOIMAGE: placeholder = PILImage.open(open(placeholder, 'rb')) if leftarrow != ImageSlider.BUTTONLEFT: leftarrow = PILImage.open(open(leftarrow, 'rb')) if rightarrow != ImageSlider.BUTTONRIGHT: rightarrow = PILImage.open(open(rightarrow, 'rb')) self.placeholder = ImageTk.PhotoImage(placeholder) self.leftarrow, self.rightarrow = ImageTk.PhotoImage( leftarrow), ImageTk.PhotoImage(rightarrow) self.pics, self.photoims = None, None self.scalevar = IntVar() tf = Frame(self, bg=self['bg']) tf.pack(fill='both', expand=True) t1 = Frame(tf, bg=self['bg']) t1.pack(side='left', fill='y') Button( t1, image=self.leftarrow, command=lambda: self.scalevar.set(self.scalevar.get() - 1)).pack( side='left') t2 = Frame(tf, bg=self['bg']) t2.pack(side='left', fill='both', expand=True) self.imagelabel = Label(t2, image=self.placeholder, text='', compound='top') self.imagelabel.pack(side='bottom') t3 = Frame(tf, bg=self['bg']) t3.pack(side='right', fill='y') Button( t3, image=self.rightarrow, command=lambda: self.scalevar.set(self.scalevar.get() + 1)).pack( side='right') self.scalevar.trace('w', lambda *event: self.changepic()) self.slider = Scale(self, variable=self.scalevar, orient='horizontal') self.slider.pack(side='bottom') self.loaddirectory(directory) def loaddirectory(self, directory): self.directory = directory self.pics = [ directory + '/' + pic for pic in os.listdir(directory) if pic.split('.')[-1] in ('gif', 'png', 'jpg') ] pics = [PILImage.open(open(pic, 'rb')) for pic in self.pics] for pic in pics: if max(pic.size) > 200: pic.thumbnail((200, 200), PILImage.ANTIALIAS) self.photoims = [ImageTk.PhotoImage(pic) for pic in pics] if not self.photoims: self.scalevar.set(0) self.slider.configure(from_=0, to_=0) self.imagelabel.configure(image=self.placeholder, text='') else: self.slider.configure(from_=1, to=len(self.photoims)) self.scalevar.set(1) def changepic(self): if not self.photoims: return index = self.scalevar.get() if index == 0: self.scalevar.set(len(self.photoims)) elif index > len(self.photoims): self.scalevar.set(1) else: self.imagelabel.configure(image=self.photoims[index - 1], text=self.pics[index - 1].rsplit( '/', maxsplit=1)[-1]) def getpic(self): return self.pics[self.scalevar.get() - 1]
class Roller(Frame): def __init__(self, group, index): Frame.__init__(self, group) self.group = group self.index = index self.results = [0] self.history = [] self.name = StringVar() self.dice_qty = IntVar() self.die_faces = IntVar() self.modifier = IntVar() self.finalmod = IntVar() self.results_text = StringVar() self.name.trace('w', self.group.mainframe.set_unsaved_title) self.dice_qty.trace('w', self.group.mainframe.set_unsaved_title) self.die_faces.trace('w', self.group.mainframe.set_unsaved_title) self.modifier.trace('w', self.group.mainframe.set_unsaved_title) self.finalmod.trace('w', self.group.mainframe.set_unsaved_title) self.results_text.trace('w', self.group.mainframe.set_unsaved_title) default_font = ('Courier', 14) self.menu_btn = Menubutton(self, bd=1, relief='solid', font=('Courier', 8), text='\u25e2', takefocus=1, highlightthickness=1) self.name_entry = Entry(self, bd=1, relief='solid', font=('Verdana', 12), width=16, textvariable=self.name) self.dice_qty_spin = NumericSpinner(self, self.dice_qty, 1, 99, callback=self.reset, initial=1) self.die_faces_spin = NumericSpinner( self, self.die_faces, 2, 100, interval=self.group.mainframe.allow_odd.get(), initial=10) self.modifier_spin = NumericSpinner(self, self.modifier, -99, 100, callback=self.apply_modifiers) self.finalmod_spin = NumericSpinner(self, self.finalmod, -99, 100, callback=self.apply_modifiers) self.dice_lbl = Label(self, text=' d', font=default_font) self.modifier_lbl = Label(self, text='\u002b', font=default_font) self.finalmod_lbl = Label(self, text='\u002b', font=default_font) self.roll_btn = Button(self, bd=0, image=self.group.roll_img, command=lambda: self.roll(single=True)) self.results_entry = Entry(self, bd=0, relief='solid', font=default_font, width=0, textvariable=self.results_text, state='readonly', justify='center') self.menu_btn.config(menu=self.create_menu()) self.menu_btn.grid(row=index, column=0, padx=(4, 0)) self.name_entry.grid(row=index, column=1, padx=(4, 0)) self.dice_qty_spin.grid(row=index, column=2, padx=(4, 0)) self.dice_lbl.grid(row=index, column=3, padx=(0, 0)) self.die_faces_spin.grid(row=index, column=4, padx=(0, 0)) self.modifier_lbl.grid(row=index, column=5, padx=(6, 6)) self.modifier_spin.grid(row=index, column=6, padx=(0, 0)) self.roll_btn.grid(row=index, column=7, padx=(8, 0)) self.results_entry.grid(row=index, column=8, padx=(8, 0)) self.finalmod_lbl.grid(row=index, column=9, padx=(6, 6)) self.finalmod_spin.grid(row=index, column=10, padx=(0, 4)) self.name.set('Roller {}'.format(len(self.group.rollers) + 1)) self.die_faces.set(10) self.results_text.set('0 = 0') self.grid(row=index, sticky='w', pady=4) def create_menu(self): menu = Menu(self.menu_btn, tearoff=0, postcommand=self.group.maintain_roller_indices) menu.add_command(label='Add', underline=0, command=self.add_roller) menu.add_command(label='Clone', underline=0, command=lambda: self.add_roller(clone=True)) menu.add_command(label='Up', underline=0, command=lambda: self.move_roller(offset=-1)) menu.add_command(label='Down', underline=0, command=lambda: self.move_roller(offset=1)) menu.add_separator() # ------ menu.add_command(label='Remove', underline=0, command=self.remove_roller) return menu def create_hist_record(self): record = { 'dice_qty': self.dice_qty.get(), 'die_faces': self.die_faces.get(), 'modifier': self.modifier.get(), 'results_text': self.results_text.get(), 'finalmod': self.finalmod.get(), 'timestamp': str(dt.now().time())[:8], 'results': self.results } return record def add_roller(self, clone=False): destination_index = self.index + 1 roller = Roller(self.group, destination_index) self.group.rollers.insert(roller.index, roller) for i in range(destination_index, len(self.group.rollers)): self.group.rollers[i].grid(row=i + 1) if clone: roller.name.set(self.name.get()) roller.dice_qty.set(self.dice_qty.get()) roller.die_faces.set(self.die_faces.get()) roller.modifier.set(self.modifier.get()) roller.finalmod.set(self.finalmod.get()) roller.reset() for h in self.history: record = roller.create_hist_record() record['timestamp'] = h['timestamp'] roller.history.append(record) roller.apply_modifiers() for r in self.group.rollers: r.lift() self.group.mainframe.editmenu.entryconfigure( self.group.mainframe.editmenu.index('end'), command=lambda: self.add_roller(clone=clone)) self.group.mainframe.bind_all('<Control-r>', lambda e: self.add_roller(clone=clone)) def move_roller(self, offset=0, destination_index=0): if not destination_index: destination_index = self.index + offset if destination_index >= 0: roller = self.group.rollers.pop(self.index) self.group.rollers.insert(destination_index, roller) self.group.maintain_roller_indices() self.name.set(self.name.get()) self.group.mainframe.editmenu.entryconfigure( self.group.mainframe.editmenu.index('end'), command=lambda: self.move_roller(offset=offset)) self.group.mainframe.bind_all( '<Control-r>', lambda e: self.move_roller(offset=offset)) def remove_roller(self): if len(self.group.rollers) > 1: self.grid_remove() self.group.rollers.remove(self) self.name.set('') def reset(self, loading=False): self.results = [0 for i in range(self.dice_qty.get())] self.dice_qty_spin.step(0) self.die_faces_spin.step(0) self.modifier_spin.step(0) self.finalmod_spin.step(0) if not loading: self.apply_modifiers() self.group.maintain_result_widths() def roll(self, single=False): rolls = self.dice_qty.get() sides = self.die_faces.get() if self.group.mainframe.allow_odd.get() % 2 == 0 and sides % 2 != 0: self.die_faces.set(sides - 1) sides -= 1 mod = self.modifier.get() fmod = self.finalmod.get() max_roll = sides min_roll = 1 results = [] if self.group.mainframe.use_random_org.get(): url = 'https://www.random.org/integers/?col={0}&num={0}&min={1}&max={2}&base=10&format=plain&rnd=new' url = url.format(rolls, min_roll, max_roll) try: resp = urlopen(url) results.extend([ int(x) for x in str(resp.read().rstrip(), encoding='utf8').split('\t') ]) sleep(0.1) except: print('Failed to use random.org, falling back to CSPRNG!') if not results: csprng = SystemRandom() for i in range(rolls): roll = csprng.randint(min_roll, sides) results.append(roll) self.results = [] for n in results: if n == max_roll: self.results.append(n * CRIT) elif n == min_roll: self.results.append(n * FAIL) else: self.results.append(n) self.apply_modifiers(True) self.history.append(self.create_hist_record()) hist_index = len(self.history) - 1 if single: for roller in self.group.rollers: if roller is not self: roller.history.append(roller.create_hist_record()) self.group.navigate_history(desired_index=hist_index) self.group.hist_index = hist_index self.name.set(self.name.get()) self.group.mainframe.editmenu.entryconfigure( self.group.mainframe.editmenu.index('end'), command=lambda: self.roll(single=single)) self.group.mainframe.bind_all('<Control-r>', lambda e: self.roll(single=single)) def apply_modifiers(self, rolling=False): fmod = self.finalmod.get() dmod = self.modifier.get() dqty = self.dice_qty.get() formatted_results = [] total = 0 for n in self.results: if n > CRIT: n = int(n / CRIT) n = n + dmod formatted_results.append('\u25b2{}'.format(str(n))) elif 0 < n < 1: n = int(n / FAIL) n = n + dmod formatted_results.append('\u25bc{}'.format(str(n))) else: n = n + dmod formatted_results.append(str(n)) total += n s = ' + '.join(formatted_results) s = '{} = {}'.format(total + fmod, s) if not rolling and self.history: self.history[self.group.hist_index]['modifier'] = dmod self.history[self.group.hist_index]['finalmod'] = fmod self.history[self.group.hist_index]['results_text'] = s self.results_text.set(s) self.group.maintain_result_widths()
class Application(Tk): def __init__(self, debug_mode=0): Tk.__init__(self) self.engine = None self.language = None self.width = 0 self.height = 0 self.resolution_code = None self.is_full_screen = IntVar() self.screen_ratio = None self.resolution_list = [] self.debug_mode = debug_mode if self.debug_mode: basicConfig(level=DEBUG) pil_logger = getLogger("PIL.PngImagePlugin") pil_logger.level = WARNING self.data_reader = DataReader(self) self._process_config() self.card_texts = {} self.ui_text_variables = {} self._load_text_variables() self.save_handler = SaveHandler(self) self.is_game_setup_in_progress = IntVar(value=0) self.is_game_in_progress = IntVar(value=0) self.is_turn_in_progress = IntVar(value=1) self._render_panes() self.is_game_in_progress.trace('w', self._follow_game_progress_change) self.is_turn_in_progress.trace('w', self._follow_turn_progress_change) self.players = {} self._text_placer() self.protocol("WM_DELETE_WINDOW", self.shutdown_ttk_repeat_fix) self.exit_in_progress = False @property def board_width(self): return self.height - 10 def _process_config(self): settings = self.data_reader.load_settings() self.language = Languages.get_language_by_name(settings.language) s.language = Languages.get_language_by_name(settings.language) s.application_width = self.width = settings.width s.application_height = self.height = settings.height self.resolution_code = settings.resolution_code self.resolution_list = settings.resolution_list self.screen_ratio = self.resolution_code[:4] self.is_full_screen.set(settings.full_screen) self._fix_window_size() def _fix_window_size(self): self.minsize(self.width, self.height) self.maxsize(self.width, self.height) if self.is_full_screen.get(): self._set_full_screen_position() else: self._set_windowed_position() def _set_full_screen_position(self): self.overrideredirect(1) self.geometry("{}x{}+0+0".format(self.width, self.height)) def _set_windowed_position(self): self.overrideredirect(0) self.geometry("{}x{}+{}+{}".format(self.width, self.height, 100, 100)) def _load_text_variable_values(self): text_variable_values = self.data_reader.load_dictionary( { Languages.HUNGARIAN.value: "hu", Languages.ENGLISH.value: "en", Languages.PIRATE.value: "arr" }[self.language], entry_type='textvariable') return text_variable_values def _load_text_variables(self): for term, translation in s.language.var_terms.items(): self.ui_text_variables.setdefault(term, StringVar()).set(translation) def _text_placer(self): picked_nations = [] self.title(s.language.title) self.menu.load_ui_texts() if self.is_game_setup_in_progress.get(): picked_nations = self._save_game_setup_state() if self.is_game_setup_in_progress.get(): self._reload_game_setup_state(picked_nations) if self.is_game_in_progress.get(): self.menu.reset_game_tab() def _save_game_setup_state(self): picked_nations = [] for i in range(6): empire_name = self.game_board.player_setups[i].empire_picker.get() if empire_name != '': current_empire = Empires.get_by_name(empire_name) picked_nations.append(current_empire) else: picked_nations.append('') return picked_nations def _reload_game_setup_state(self, picked_nations: List[Empire]): adjectives = [empire.value.adjective for empire in Empires] translated_adjectives = [ s.language.get(adjective) for adjective in adjectives ] for index, picked_nation in enumerate(picked_nations): self.game_board.player_setups[index].empire_picker.config( value=translated_adjectives) if picked_nation: self.game_board.player_setups[index].empire_picker.set( s.language.get(picked_nation.adjective)) def set_new_language(self, new_language): if self.language == new_language: return self.language = new_language s.language = new_language self._load_text_variables() self._text_placer() self.card_texts = self.data_reader.load_cards_text() self.status_bar.log(s.language.new_language) self.data_reader.save_settings(new_language=new_language) def _render_panes(self): self.columnconfigure('all', weight=1) self.rowconfigure('all', weight=1) menu_width = int((self.height / 3) - 10) self.status_bar = LogFrame(self, menu_width) self.status_bar.grid(row=1, column=0, sticky=S + W, padx=5, pady=5) if self.is_game_in_progress.get(): self._render_game_board() else: self._render_game_board_placeholder() self.menu = Tabs(self, menu_width) self.menu.grid(row=0, column=0, sticky=N + W, padx=5, pady=5) if self.screen_ratio == 'wide': ship_width = self.width - menu_width - self.board_width - 30 self.ship = Frame(self, width=ship_width) self.ship.grid(row=0, column=2, rowspan=2, sticky=W + N + E, padx=5, pady=5) def _render_game_board_placeholder(self): self.game_board = Frame(self, width=self.board_width, height=self.board_width) self.game_board.player_setups = [] self.game_board.grid(row=0, column=1, rowspan=2, sticky=N + W, padx=5, pady=5) def _render_game_board(self): self.game_board = Board(self, self.board_width) self.game_board.render_board() self.game_board.grid(row=0, column=1, rowspan=2, sticky=N + W, padx=5, pady=5) def resize(self, new_resolution, is_new_full_screen): is_same_resolution = (self.width, self.height) == (new_resolution[0], new_resolution[1]) is_same_full_screen_setting = self.is_full_screen.get( ) == is_new_full_screen if is_same_resolution and is_same_full_screen_setting: return self.data_reader.save_settings(new_resolution[2], str(is_new_full_screen)) player_data = [] if self.is_game_setup_in_progress.get(): player_data = self._save_game_setup_before_resize() self._process_config() self._remove_everything() self._render_panes() if self.is_game_setup_in_progress.get(): self._load_game_setup_before_resize(player_data) self._text_placer() self.menu.select(self.menu.settings_tab) self.status_bar.log( '%s %i×%i' % (s.language.new_resolution, self.width, self.height)) def _save_game_setup_before_resize(self): player_data = [] for i in range(6): if self.game_board.player_setups[i].active.get(): player_data.append( self.game_board.player_setups[i].get_player_state()) return player_data def _load_game_setup_before_resize(self, player_data): self.start_game_setup() for i, player_state in enumerate(player_data): self.game_board.player_setups[i].set_player_state(player_state) def _remove_everything(self): Gallery.discard_cache() self.menu.destroy() self.game_board.destroy() self.status_bar.destroy() try: self.ship.destroy() except AttributeError: pass def confirm_discard_game(self): is_game_in_progress = self.is_game_in_progress.get() if is_game_in_progress and not askokcancel( self.ui_text_variables['new_game'].get(), s.language.discard_game): return False elif is_game_in_progress: self.is_game_in_progress.set(0) return True else: return True def start_game_setup(self): confirmed = self.confirm_discard_game() if confirmed: if self.is_game_setup_in_progress.get(): self._reset_board() self._prepare_game_setup() def _reset_board(self): self.is_game_setup_in_progress.set(0) self.game_board.destroy() self._render_game_board_placeholder() self.menu.release_new_game_button() def _prepare_game_setup(self): self.is_game_setup_in_progress.set(1) self.menu.push_new_game_button() self.game_board.destroy() self._render_game_board_placeholder() self.game_board = NewGamePanel(self) self.game_board.columnconfigure('all', weight=1) self.game_board.rowconfigure('all', weight=1) self.game_board.grid(row=0, column=1, rowspan=2, sticky=N + E + W + S, padx=5, pady=5) def select_file_to_load(self): if self.is_game_in_progress.get(): if not askokcancel(self.ui_text_variables['new_game'].get(), s.language.discard_game_b): return game_state = self.save_handler.load_saved_state() if game_state is None or not game_state.check(): return self.status_bar.log(s.language.loading_game) self.load_game(game_state) def load_game(self, game_state): self._reset_for_game_start() for data in game_state.player_data: empire_literal = game_state.player_data[data].empire game_state.player_data[data].empire = Empires.get_by_adjective( empire_literal) self.players[data] = Player(self.game_board, game_state.player_data[data]) self._prepare_new_ui() while self.player_order[0] != game_state.next_player: self.player_order.append(self.player_order.pop(0)) self.engine = Vezerlo(self, game_state.taverns) self.game_board.update_wind_direction(game_state.wind_index) if game_state.is_lieutenant_found: self.engine.set_hadnagyElokerult() if game_state.is_grog_lord_defeated: self.engine.set_grogbaroLegyozve() self.menu.update_developer_tab() self.engine.set_paklik(game_state.card_decks) self.status_bar.log(s.language.loading_done) self.engine.szakasz_0() def _reset_for_game_start(self): self.is_game_setup_in_progress.set(0) self.card_texts = self.data_reader.load_cards_text() self.players = {} self.update_idletasks() self.is_game_in_progress.set(1) self.game_board.destroy() self.game_board = Board(self, self.board_width) self.game_board.grid(row=0, column=1, rowspan=2, sticky=N + W, padx=5, pady=5) def _prepare_new_ui(self): self.player_order = sorted(self.players.keys()) self.game_board.render_board() self.menu.release_new_game_button() self.menu.select(self.menu.game_tab) def start_game(self, player_states): self._reset_for_game_start() for index, player_state in enumerate(player_states): self.players['player' + str(index)] = Player( self.game_board, player_state) self._prepare_new_ui() self.engine = Vezerlo(self) self.menu.update_developer_tab() self.status_bar.log(s.language.start_game_done) self.engine.szakasz_0() def _follow_game_progress_change(self, *args, **kwargs): if self.is_game_in_progress.get(): self.menu.tab(1, state=NORMAL) else: self.menu.tab(1, state=DISABLED) def _follow_turn_progress_change(self, *args, **kwargs): if not self.is_turn_in_progress.get(): self.menu.enable_save_buttons() self.menu.tab(0, state=NORMAL) self.menu.tab(2, state=NORMAL) else: self.menu.disable_save_buttons() self.menu.tab(0, state=DISABLED) self.menu.tab(2, state=DISABLED) def shutdown_ttk_repeat_fix(self): self.eval('::ttk::CancelRepeat') self.exit_in_progress = True self.exit() def get_window_position(self): info = self.winfo_geometry() xpos = info.index('+') + 1 ypos = info[xpos:].index('+') + xpos x = int(info[xpos:ypos]) y = int(info[ypos:]) return x, y def save_game(self): game_state = GameState() game_state.next_player = self.player_order[0] game_state.wind_index = self.game_board.wind_direction.index(0) for player in sorted(list(self.players)): game_state.player_data[player] = self.players[player].export() for empire in Empires: game_state.taverns[empire.value.capital] = self.engine.varostar[ empire.value.capital].export_matroz() game_state.card_decks = [ self.engine.eventdeck, self.engine.eventstack, self.engine.kincspakli, self.engine.treasurestack ] game_state.is_grog_lord_defeated = self.engine.grogbaroLegyozve.get() game_state.is_lieutenant_found = self.engine.hadnagyElokerult.get() if game_state.check(): self.save_handler.write_save(game_state) else: raise RuntimeError('Invalid game state.') def save_and_exit(self): self.save_game() self.shutdown_ttk_repeat_fix() def exit(self): if self.is_game_in_progress.get( ) and self.game_board.is_field_select_blinking: self.game_board.is_field_select_blinking = False self.destroy()
class MainFrame(Frame): def set_saved_title(self, fpath): fname = split(fpath)[-1].replace('.json', '') self.master.title('{} - {}'.format(fname, _title)) def set_unsaved_title(self, *args): if len(roller_groups) < 1: return if self.autosave.get(): self.save_config(self.fpath) return title = self.master.title() if title == _title: title = '{} - {}'.format('Unsaved', title) if '*' not in title: title = '*' + title self.master.title(title) def __init__(self, master): Frame.__init__(self, master) self.master = master self.use_random_org = BooleanVar() self.allow_odd = IntVar() self.always_on_top = BooleanVar() self.autosave = BooleanVar() self.use_random_org.trace('w', self.set_unsaved_title) self.allow_odd.trace('w', self.set_unsaved_title) self.always_on_top.trace('w', self.set_unsaved_title) self.set_defaults() self.menubar = Menu(master) self.filemenu = Menu(self.menubar, tearoff=0, postcommand=maintain_group_indices) self.filemenu.add_command(label='New', underline=0, command=self.reset_default_group, accelerator='Ctrl+N') self.filemenu.add_command(label='Load', underline=3, command=self.load_config, accelerator='Ctrl+D') self.filemenu.add_command( label='Save', underline=1, command=lambda: self.save_config(fpath=self.fpath), accelerator='Ctrl+S') self.filemenu.add_command(label='Save as...', underline=4, command=self.save_config, accelerator='Ctrl+Shift+S') self.editmenu = Menu(self.menubar, tearoff=0) self.editmenu.add_checkbutton(label='Use random.org', underline=0, variable=self.use_random_org) self.editmenu.add_checkbutton(label='Allow odd dice', underline=6, variable=self.allow_odd, command=self.toggle_odd, onvalue=1, offvalue=2) self.editmenu.add_separator() # ------------------ self.editmenu.add_checkbutton(label='Always on top', underline=10, variable=self.always_on_top, command=self.pin) self.editmenu.add_checkbutton(label='Autosave', underline=4, variable=self.autosave, command=self.toggle_autosave) self.editmenu.add_separator() # ------------------ self.editmenu.add_command(label='Repeat last action', underline=0, accelerator='Ctrl+R') self.menubar.add_cascade(label='File', underline=0, menu=self.filemenu) self.menubar.add_cascade(label='Edit', underline=0, menu=self.editmenu) self.menubar.config(relief='flat') master.config(menu=self.menubar) self.reset_default_group() self.bind_all('<Control-n>', lambda e: self.reset_default_group()) self.bind_all('<Control-d>', lambda e: self.load_config()) self.bind_all('<Control-s>', lambda e: self.save_config(fpath=self.fpath)) self.bind_all('<Control-Shift-S>', lambda e: self.save_config()) def ask_proceed(self): if '*' in self.master.title(): if not askyesno( 'Unsaved changes!', 'There are unsaved changes!\r\nWould you like to proceed anyway?' ): return False return True def pin(self): self.master.wm_attributes('-topmost', self.always_on_top.get()) def toggle_odd(self): for group in roller_groups: for roller in group.rollers: roller.die_faces_spin.interval = self.allow_odd.get() num = roller.die_faces.get() if num % 2 != 0: roller.die_faces.set(num - 1) def toggle_autosave(self): if self.autosave.get(): self.save_config(self.fpath) else: self.set_unsaved_title() def set_defaults(self): self.master.title(_title) self.fpath = '' self.use_random_org.set(False) self.allow_odd.set(2) self.always_on_top.set(False) self.autosave.set(False) def reset_default_group(self): if self.ask_proceed(): self.autosave.set(False) self.clear_groups() self.set_defaults() self.create_group(0, 1) @staticmethod def clear_groups(): temp_groups = list(roller_groups) for group in temp_groups: group.remove_group(override=True) def create_group(self, index, rollers): default_group = RollerGroup(self, index) for i in range(rollers): default_group.rollers.append(Roller(default_group, i)) roller_groups.append(default_group) def load_config(self): autosave = False self.autosave.set(autosave) if not self.ask_proceed(): return fpath = askopenfilename(filetypes=[('JSON', '*.json'), ('All', '*.*')], defaultextension='.json') if not fpath or not isfile(fpath): return self.fpath = fpath self.clear_groups() with open(fpath, 'r') as f: group_dict = load(f) try: settings_dict = group_dict.pop('settings') autosave = (settings_dict['autosave']) self.use_random_org.set(settings_dict['use_random_org']) self.allow_odd.set(settings_dict['allow_odd']) self.always_on_top.set(settings_dict['always_on_top']) except KeyError: pass g = 0 for group_name, group_settings in group_dict.items(): self.create_group(g, len(group_settings['rollers'])) group = roller_groups[g] group.name.set(group_name) group.index = group_settings['index'] r = 0 h = 0 for roller_name, roller_settings in group_settings[ 'rollers'].items(): roller = group.rollers[r] roller.name.set(roller_name) for attr, value in roller_settings.items(): try: getattr(roller, attr).set(value) except AttributeError: setattr(roller, attr, value) roller.reset(loading=True) h = len(roller.history) - 1 r += 1 group.navigate_history(desired_index=h) g += 1 roller_groups.sort(key=lambda x: x.index) maintain_group_indices() for group in roller_groups: group.rollers.sort(key=lambda x: x.index) group.maintain_roller_indices() for roller in group.rollers: roller.apply_modifiers() maintain_tabstops() self.pin() self.autosave.set(autosave) self.set_saved_title(fpath) def save_config(self, fpath=''): if not fpath: fpath = asksaveasfilename(filetypes=[('JSON', '*.json'), ('All', '*.*')], defaultextension='.json') if not fpath: if '*' in self.master.title(): self.autosave.set(False) return self.fpath = fpath d1 = {} d1['settings'] = { 'use_random_org': self.use_random_org.get(), 'allow_odd': self.allow_odd.get(), 'always_on_top': self.always_on_top.get(), 'autosave': self.autosave.get() } for group in roller_groups: group.maintain_roller_indices() d2 = {} d2['index'] = group.index d2['rollers'] = {} for roller in group.rollers: name = roller.name.get() while name in d2['rollers']: name += '!' d2['rollers'][name] = { 'index': roller.index, 'history': roller.history, 'dice_qty': roller.dice_qty.get(), 'die_faces': roller.die_faces.get(), 'modifier': roller.modifier.get(), 'finalmod': roller.finalmod.get() } name = group.name.get() if name in d1: name += '!' d1[name] = d2 with open(fpath, 'w') as f: f.write(dumps(d1, indent=2, separators=(',', ': '))) self.set_saved_title(fpath)
def __init__(self, master, par=False): """ GUI for selecting default parameters - will write parameters to file \ of users choosing. :type master: Tk :param master: Tkinter window :type par: EQcorrscanParameters :param par: Default parameters to start-up with. """ from tkinter import Label, Button, Entry, DoubleVar, StringVar, IntVar from tkinter import BooleanVar, OptionMenu, Checkbutton import tkMessageBox from eqcorrscan.utils import parameters from obspy import UTCDateTime import warnings # Set the default par, only if they don't already exist. if not par: par = parameters.EQcorrscanParameters([''], 2, 10, 4, 100, 2, '1900-01-01', '2300-01-01', '', 'seishub', 4, False, '', 'jpg', False, 8, 'MAD', 6) # Callback functions for all variables (ugly) def update_template_names(*args): par.template_names = [name.strip() for name in template_names.get().split(',')] template_names.set(', '.join(par.template_names)) def update_lowcut(*args): par.lowcut = lowcut.get() lowcut.set(par.lowcut) def update_highcut(*args): par.highcut = highcut.get() if par.highcut >= 0.5 * par.samp_rate: msg = ('Highcut must be less than the Nyquist, setting to ' + str((par.samp_rate / 2.0) - 1)) tkMessageBox.showwarning(title="Nyquist error", message=msg) par.highcut = (par.samp_rate / 2.0) - 1 highcut.set(par.highcut) def update_filt_order(*args): par.filt_order = filt_order.get() filt_order.set(par.filt_order) def update_samp_rate(*args): par.samp_rate = samp_rate.get() if par.highcut >= 0.5 * par.samp_rate: msg = ('Highcut must be less than the Nyquist, setting to ' + str((par.samp_rate / 2.0) - 1)) tkMessageBox.showwarning(title="Nyquist error", message=msg) par.highcut = (par.samp_rate / 2.0) - 1 highcut.set(par.highcut) samp_rate.set(par.samp_rate) def update_debug(*args): par.debug = debug.get() debug.set(par.debug) def update_startdate(*args): par.startdate = UTCDateTime(startdate.get()) startdate.set(str(par.startdate)) def update_enddate(*args): par.enddate = UTCDateTime(enddate.get()) enddate.set(str(par.enddate)) def update_archive(*args): par.archive = archive.get() archive.set(par.archive) def update_arc_type(*args): par.arc_type = arc_type.get() arc_type.set(par.arc_type) def update_cores(*args): par.cores = cores.get() cores.set(par.cores) def update_plotvar(*args): par.plotvar = plotvar.get() plotvar.set(par.plotvar) def update_plot_format(*args): par.plot_format = plot_format.get() plot_format.set(par.plot_format) def update_tempdir(*args): par.tempdir = tempdir.get() tempdir.set(par.tempdir) def update_threshold(*args): par.threshold = threshold.get() threshold.set(par.threshold) def update_threshold_type(*args): par.threshold_type = threshold_type.get() threshold_type.set(par.threshold_type) def update_plotdir(*args): par.plotdir = plotdir.get() plotdir.set(par.plotdir) def update_trigger_interval(*args): par.trigger_interval = trigger_interval.get() trigger_interval.set(par.trigger_interval) # Set some grid parameters nrows = 25 ncolumns = 3 self.master = master master.title("EQcorrscan parameter setup") self.label = Label(master, text="Alpha GUI for default setup") self.label.grid(column=0, columnspan=ncolumns, row=0) # Set up parameter input self.t_names_label = Label(master, text="Template names", anchor='e') self.t_names_label.grid(column=0, row=1, sticky='e') template_names = StringVar() template_names.set(', '.join(par.template_names)) self.t_names_box = Entry(master, bd=2, textvariable=template_names) self.t_names_box.grid(column=1, row=1) template_names.trace("w", update_template_names) self.t_names_lookup = Button(master, text="Lookup", command=lambda: self.get_template_names(par)) self.t_names_lookup.grid(column=2, row=1) self.lowcut_label = Label(master, text="Lowcut (Hz)", anchor='e') self.lowcut_label.grid(column=0, row=2, sticky='e') lowcut = DoubleVar() lowcut.set(par.lowcut) self.lowcut_box = Entry(master, bd=2, textvariable=lowcut) self.lowcut_box.grid(column=1, row=2) lowcut.trace("w", update_lowcut) self.highcut_label = Label(master, text="Highcut (Hz)", anchor='e') self.highcut_label.grid(column=0, row=3, sticky='e') highcut = DoubleVar() highcut.set(par.highcut) self.highcut_box = Entry(master, bd=2, textvariable=highcut) self.highcut_box.grid(column=1, row=3) highcut.trace("w", update_highcut) self.filt_order_label = Label(master, text="Filter order") self.filt_order_label.grid(column=0, row=4, sticky='e') filt_order = DoubleVar() filt_order.set(par.filt_order) self.filt_order_box = Entry(master, bd=2, textvariable=filt_order) self.filt_order_box.grid(column=1, row=4) filt_order.trace("w", update_filt_order) self.samp_rate_label = Label(master, text="Sample rate (Hz)") self.samp_rate_label.grid(column=0, row=5, sticky='e') samp_rate = DoubleVar() samp_rate.set(par.samp_rate) self.samp_rate_box = Entry(master, bd=2, textvariable=samp_rate) self.samp_rate_box.grid(column=1, row=5) samp_rate.trace("w", update_samp_rate) self.debug_label = Label(master, text="Debug") self.debug_label.grid(column=0, row=6, sticky='e') debug = IntVar() debug.set(par.debug) self.debug_box = Entry(master, bd=2, textvariable=debug) self.debug_box.grid(column=1, row=6) debug.trace("w", update_debug) self.startdate_label = Label(master, text="Start date (yyyy-mm-dd)") self.startdate_label.grid(column=0, row=6, sticky='e') startdate = StringVar() startdate.set(par.startdate) self.startdate_box = Entry(master, bd=2, textvariable=startdate) self.startdate_box.grid(column=1, row=6) startdate.trace("w", update_startdate) self.enddate_label = Label(master, text="End date (yyyy-mm-dd)") self.enddate_label.grid(column=0, row=8, sticky='e') enddate = StringVar() enddate.set(par.enddate) self.enddate_box = Entry(master, bd=2, textvariable=enddate) self.enddate_box.grid(column=1, row=8) enddate.trace("w", update_enddate) self.archive_label = Label(master, text="Archive") self.archive_label.grid(column=0, row=9, sticky='e') archive = StringVar() archive.set(par.archive) self.archive_box = Entry(master, bd=2, textvariable=archive) self.archive_box.grid(column=1, row=9) archive.trace("w", update_archive) self.archive_lookup = Button(master, text="Lookup", command=lambda: self.get_archive(par)) self.archive_lookup.grid(column=2, row=9) self.arc_type_label = Label(master, text="Archive type") self.arc_type_label.grid(column=0, row=10, sticky='e') arc_type = StringVar() arc_type.set(par.arc_type) self.arc_type_box = OptionMenu(master, arc_type, "seishub", "fdsn", "day_vols") self.arc_type_box.grid(column=1, row=10, sticky='w,e') arc_type.trace("w", update_arc_type) self.cores_label = Label(master, text="Number of cores") self.cores_label.grid(column=0, row=11, sticky='e') cores = IntVar() cores.set(par.cores) self.cores_box = Entry(master, bd=2, textvariable=cores) self.cores_box.grid(column=1, row=11) cores.trace("w", update_cores) self.plotvar_label = Label(master, text="Plotting on/off") self.plotvar_label.grid(column=0, row=12, sticky='e') plotvar = BooleanVar() plotvar.set(par.plotvar) self.plotvar_box = Checkbutton(master, text='Plot on', var=plotvar, onvalue=True, offvalue=False) self.plotvar_box.grid(column=1, row=12) plotvar.trace("w", update_plotvar) self.plotdir_label = Label(master, text="Plot directory") self.plotdir_label.grid(column=0, row=13, sticky='e') plotdir = StringVar() plotdir.set(par.plotdir) self.plotdir_box = Entry(master, bd=2, textvariable=plotdir) self.plotdir_box.grid(column=1, row=13) plotdir.trace("w", update_plotdir) self.plotdir_lookup = Button(master, text="Lookup", command=lambda: self.get_plotdir(par)) self.plotdir_lookup.grid(column=2, row=13) self.plot_format_label = Label(master, text="Plot format") self.plot_format_label.grid(column=0, row=14, sticky='e') plot_format = StringVar() plot_format.set(par.plot_format) self.plot_format_box = OptionMenu(master, plot_format, "jpg", "eps", "pdf", "png") self.plot_format_box.grid(column=1, row=14, sticky='w,e') plot_format.trace("w", update_plot_format) self.tempdir_label = Label(master, text="Temporary directory") self.tempdir_label.grid(column=0, row=15, sticky='e') tempdir = StringVar() tempdir.set(par.tempdir) self.tempdir_box = Entry(master, bd=2, textvariable=tempdir) self.tempdir_box.grid(column=1, row=15) tempdir.trace("w", update_tempdir) self.tempdir_lookup = Button(master, text="Lookup", command=lambda: self.get_tempdir(par)) self.tempdir_lookup.grid(column=2, row=15) self.threshold_label = Label(master, text="Threshold") self.threshold_label.grid(column=0, row=16, sticky='e') threshold = DoubleVar() threshold.set(par.threshold) self.threshold_box = Entry(master, bd=2, textvariable=threshold) self.threshold_box.grid(column=1, row=16) threshold.trace("w", update_threshold) self.threshold_type_label = Label(master, text="Threshold type") self.threshold_type_label.grid(column=0, row=17, sticky='e') threshold_type = StringVar() threshold_type.set(par.threshold_type) self.threshold_type_box = OptionMenu(master, threshold_type, "MAD", "absolute", "av_chan_corr") self.threshold_type_box.grid(column=1, row=17, sticky='w,e') threshold_type.trace("w", update_threshold_type) self.trigger_interval_label = Label(master, text="Minimum trigger " + "interval (s)") self.trigger_interval_label.grid(column=0, row=18, sticky='e') trigger_interval = DoubleVar() trigger_interval.set(par.trigger_interval) self.trigger_interval_box = Entry(master, bd=2, textvariable=trigger_interval) self.trigger_interval_box.grid(column=1, row=18) trigger_interval.trace("w", update_trigger_interval) # End of user editable section, now we have read/write buttons self.read_button = Button(master, text="Read parameters", command=lambda: self.read_par(master)) self.read_button.grid(column=0, row=nrows-2, sticky='w,e') self.write_button = Button(master, text="Write parameters", command=lambda: self.write_par(par)) self.write_button.grid(column=1, row=nrows-2, sticky='w,e')
class View(object): def __init__(self, master=None): self.root = master self.status_build = False self.init_view() def init_view(self): '''基本框架''' self.frm_main = LabelFrame(self.root, borderwidth=0) self.frm_main.pack(side='left', fill='y') self.frm_advance = LabelFrame(self.root, text='高级选项') # self.frm_advance.pack(expand='yes', side='right', fill='both', padx=15, pady=10) # self.frm_2 = LabelFrame(self.frm_advance, text='高级配置', width=300) # self.frm_2.pack(expand='yes', side='top', fill='both', padx=15, pady=10) self.frm_project = LabelFrame(self.frm_main, text='项目信息') self.frm_config = LabelFrame(self.frm_main, text='配置信息') self.frm_operate = LabelFrame(self.frm_main, text='操作') self.frm_status = LabelFrame(self.frm_main, text='状态') self.frm_project.pack(expand='yes', side='top', fill='both', padx=15, pady=10) self.frm_config.pack(fill='x', padx=15, pady=10) self.frm_operate.pack(fill='x', padx=15, pady=10) self.frm_status.pack(side='bottom', fill='x', padx=15, pady=10) self.init_project() self.init_config() self.init_operate() self.init_status() def init_project(self): '''项目配置''' labels = ['入口文件:', '工作目录:', '目标路径:', '图标路径:'] self.entry_value_list = list() for index, label_text in enumerate(labels): temp_strvar = StringVar() temp_label = Label(self.frm_project, text=label_text) temp_entry = Entry(self.frm_project, textvariable=temp_strvar, width=50) self.entry_value_list.append(temp_strvar) temp_label.grid(row=index % 4, column=0, padx=5, pady=5, sticky='w') temp_entry.grid(row=index % 4, column=1, padx=5, pady=5, sticky='we') self.btn_main_path = Button(self.frm_project, text='选择文件', command=self.fn_select_main) self.btn_work_path = Button(self.frm_project, text='选择路径', command=self.fn_work_path) self.btn_dist_path = Button(self.frm_project, text='选择路径', command=self.fn_dist_path) self.btn_ico_path = Button(self.frm_project, text='选择图标', command=self.fn_icon_path) self.btn_main_path.grid(row=0, column=2, padx=5, pady=5, sticky='we') self.btn_work_path.grid(row=1, column=2, padx=5, pady=5, sticky='w') self.btn_dist_path.grid(row=2, column=2, padx=5, pady=5, sticky='e') self.btn_ico_path.grid(row=3, column=2, padx=5, pady=5, sticky='e') def init_config(self): '''配置选项''' # 定义变量,并初始化 self.cfg_onefile = IntVar(value=1) self.cfg_onedir = IntVar(value=0) self.cfg_noconsole = IntVar(value=1) self.cfg_clean = IntVar(value=1) self.cfg_upx = IntVar(value=1) # UPX 默认开启 self.cfg_rename = IntVar() self.cfg_exe_name = StringVar() # 自定义配置文件 self.cfg_specfile = StringVar(value='build.spec') # 子配置框架 self.frm_config_base = LabelFrame(self.frm_config, text='基本', borderwidth=0) self.frm_config_base.pack(fill='x', padx=10, pady=5, ipady=5) self.frm_config_exe = LabelFrame(self.frm_config, text='生成执行文件类型', borderwidth=0) self.frm_config_exe.pack(fill='x', padx=10, pady=5, ipady=5) self.frm_config_other = LabelFrame(self.frm_config, text='其它', borderwidth=0) self.frm_config_other.pack(fill='x', padx=10, pady=5, ipady=5) self.frm_config_spec = LabelFrame(self.frm_config, text='配置文件', borderwidth=0) self.frm_config_spec.pack(fill='x', padx=10, pady=5, ipady=5) # 定义按钮 self.btn_noconsole = Checkbutton(self.frm_config_base, text='关闭控制台', variable=self.cfg_noconsole) self.btn_clean = Checkbutton(self.frm_config_base, text='构建前清理', variable=self.cfg_clean) self.btn_upx = Checkbutton(self.frm_config_base, text='UPX压缩', variable=self.cfg_upx) self.btn_isonefile = Checkbutton(self.frm_config_exe, text='独立执行文件', variable=self.cfg_onefile) self.btn_isonedir = Checkbutton(self.frm_config_exe, text='文件夹包含', variable=self.cfg_onedir) self.btn_rename = Checkbutton(self.frm_config_other, text='修改执行文件名', variable=self.cfg_rename) self.entry_rename = Entry(self.frm_config_other, textvariable=self.cfg_exe_name) # self.btn_rename = Checkbutton(self.frm_config_spec, text='生成配置文件', variable=self.cfg_specfile) self.entry_specfile = Entry(self.frm_config_spec, textvariable=self.cfg_specfile) # 放置按钮 self.btn_isonefile.pack(side='left', fill='x') self.btn_isonedir.pack(side='left', fill='x') self.btn_noconsole.pack(side='left', fill='x') self.btn_clean.pack(side='left', fill='x') self.btn_upx.pack(side='left', fill='x') self.btn_rename.pack(side='left', fill='x') self.entry_rename.pack(fill='x') self.entry_specfile.pack(fill='x') # 变量自动切换操作 self.cfg_onefile.trace('w', self.cfg_onefile_trace) self.cfg_onedir.trace('w', self.cfg_onedir_trace) def cfg_onefile_trace(self, *args): '''cfg_onefile 与 cfg_onedir 可以同时不选,但不能同时选中,选中独立执行文件时不能选中文件夹包''' if self.cfg_onefile.get() == 1: self.cfg_onedir.set(0) def cfg_onedir_trace(self, *args): '''cfg_onefile 与 cfg_onedir 可以同时不选,但不能同时选中,选中文件夹包含时不能选中独立执行文件''' if self.cfg_onedir.get() == 1: self.cfg_onefile.set(0) def init_operate(self): '''操作命令''' # 定义按钮 self.btn_build = Button(self.frm_operate, text='构建生成', command=self.fn_build) self.btn_clear = Button(self.frm_operate, text='清理', command=self.fn_clear) self.btn_reset = Button(self.frm_operate, text='重置', command=self.fn_reset) self.btn_advance = Button(self.frm_operate, text='高级选项', command=self.fn_toggle_advance) # 放置按钮 self.btn_build.pack(fill='x', side='left') self.btn_clear.pack(fill='x', side='left') self.btn_reset.pack(fill='x', side='left') self.btn_advance.pack(fill='x', side='right') def init_status(self): '''状态栏''' self.label_status = Label(self.frm_status, text='待命') self.label_status.grid(row=1, column=0, padx=5, pady=5, sticky='we') def fn_build(self): '''生成可执行文件''' if len(self.entry_value_list[0].get()) == 0: self.label_status['text'] = '请选择源文件' return if not self.status_build: thread_build = Thread(target=self.fn_thread) thread_build.setDaemon(True) thread_build.start() else: self.label_status['text'] = '正在打包,请稍后再操作!' def fn_thread(self): '''线程执行生成动作''' self.status_build = True self.label_status['text'] = '正在打包,请稍等。。。' try: cmd = self.fn_build_cmd() print(cmd) # pirun(cmd) system(' '.join(cmd)) # call(split(' '.join(cmd)), shell=True) self.status_build = False self.label_status['text'] = '打包成功!' except Exception as e: self.label_status['text'] = str(e) self.status_build = False def fn_clear(self): '''清理生成文件''' pass def fn_reset(self): '''重置表单内容''' for i in range(4): self.entry_value_list[i].set('') self.cfg_onefile.set(1) self.cfg_noconsole.set(1) self.cfg_clean.set(1) self.cfg_upx.set(1) self.cfg_rename.set(0) self.cfg_exe_name.set('') def fn_toggle_advance(self): '''切换高级选项界面''' if self.frm_advance.winfo_ismapped(): set_window_center(self.root, width=(self.root.winfo_width() - 400)) self.frm_advance.pack_forget() else: set_window_center(self.root, width=(self.root.winfo_width() + 400)) self.frm_advance.pack(expand='yes', side='right', fill='both', padx=15, pady=10) def fn_select_main(self): '''选择源文件''' types = (('py files', '*.py'), ('pyc files', '*.pyc'), ('spec files', '*.spec'), ('All files', '*.*')) path = filedialog.askopenfilename(filetypes=types) if not path: return _path = os.path.dirname(path) # 主文件 self.entry_value_list[0].set(path) # 工作目录 self.entry_value_list[1].set(os.path.join(_path, 'build/')) # dist目录 self.entry_value_list[2].set(os.path.join(_path, 'dist/')) def fn_work_path(self): '''选择工作目录''' path = filedialog.askdirectory() if not path: return self.entry_value_list[1].set(path) def fn_dist_path(self): '''选择生成文件目录''' path = filedialog.askdirectory() if not path: return self.entry_value_list[2].set(path) def fn_icon_path(self): '''选择图标文件''' types = (('ico files', '*.ico'), ('icns files', '*.icns'), ('All files', '*.*')) path = filedialog.askopenfilename(filetypes=types) if not path: return self.entry_value_list[3].set(path) def fn_build_cmd(self, cli=True): '''组装命令''' cmds = [] if cli is True: # 使用系统命令行 cmds.append('pyinstaller') if len(self.entry_value_list[0].get()) > 0: cmds.append(self.entry_value_list[0].get()) else: return cmds cmds.append('--windowed') cmds.append('-y') cmds.append('--noconfirm') # cmds.append('--filenames=build.spec') # cmds.append('/usr/local/bin/pyinstaller') if self.cfg_onefile.get() == 1: cmds.append('--onefile') elif self.cfg_onedir.get() == 1: cmds.append('--onedir') if self.cfg_clean.get() == 1: cmds.append('--clean') cmds.append('--noconfirm') if self.cfg_upx.get() == 0: cmds.append('--noupx') if self.cfg_noconsole.get() == 1: cmds.append('--noconsole') if len(self.entry_value_list[1].get()) > 0: cmds.append('--workpath=' + self.entry_value_list[1].get()) if len(self.entry_value_list[2].get()) > 0: cmds.append('--distpath=' + self.entry_value_list[2].get()) if len(self.entry_value_list[3].get()) > 0: cmds.append('--icon=' + self.entry_value_list[3].get()) if self.cfg_rename.get() == 1: if len(self.cfg_exe_name.get()) > 0: cmds.append('--name=' + self.cfg_exe_name.get()) # print(' '.join(cmds)) return cmds
class sa_setting_ui: def __init__(self,net_list_path,isrootwindow = True, root = None): self.net_list_path = net_list_path if(isrootwindow): self.root = tk.Tk() else: self.root = tk.Toplevel(root) self.root.grab_set() self.root.title("Simulated Annealing Properties") self.root.geometry("500x600") self.root.resizable(False, False) vcmd = (self.root.register(self.validate_entry), "%d",'%S') self.alpha_entry = tk.Entry(self.root,width=10,validate="key", validatecommand=vcmd) self.start_temp_entry = tk.Entry(self.root,width=10,validate="key", validatecommand=vcmd) self.end_temp_entry = tk.Entry(self.root,width=10,validate="key", validatecommand=vcmd) self.kb_entry = tk.Entry(self.root,width=10,validate="key", validatecommand=vcmd) text_alpha_entry=tk.StringVar() text_alpha_entry.set("\u03B1(%):") self.label_alpha_entry = tk.Label(self.root, textvariable=text_alpha_entry, height=1) text_start_temp=tk.StringVar() text_start_temp.set("T(start):") self.label_start_temp_entry = tk.Label(self.root, textvariable=text_start_temp, height=1) text_end_temp=tk.StringVar() text_end_temp.set("T(stop):") self.label_end_temp_entry = tk.Label(self.root, textvariable=text_end_temp, height=1) text_kb =tk.StringVar() text_kb.set("k:") self.label_kb_set = tk.Label(self.root, textvariable=text_kb, height=1) text_choice =tk.StringVar() text_choice.set("Problem:") self.label_drop_menu = tk.Label(self.root, textvariable=text_choice, height=1) text_log_path =tk.StringVar() text_log_path.set("Log Path:") self.label_log_path = tk.Label(self.root, textvariable=text_log_path, height=1) self.log_path_entry = tk.Entry(self.root,width=10) self.text_label_error =tk.StringVar() self.text_label_error.set("") self.label_error = tk.Label(self.root, textvariable=self.text_label_error, height=1,fg="red") self.run_sim_btn = tk.Button(self.root,text="Run Solver", command=self.runSolver) self.sel_path_btn = tk.Button(self.root,text="...",command=self.selPath) self.log_path_entry.config(state='disabled') self.kill_sim_btn = tk.Button(self.root,text="Kill Sim", command=self.killSim) self.kill_sim_btn.config(state="disabled") self.description = ScrolledText(self.root,bg='white',relief="groove",height=10,width=50,font='TkFixedFont') self.selected = tk.StringVar(self.root) self.selected.trace("w",self.changeChoice) self.choices = { 'Partitioning','Travelling Salesman'} self.selected.set('Partitioning') # set the default option self.drop_menu = tk.OptionMenu(self.root, self.selected, *self.choices) self.show_sim_active = IntVar() self.show_sim_active.set(1) self.show_sim_btn = tk.Checkbutton(self.root,text = "Show Live Sim", variable = self.show_sim_active, \ onvalue = 1, offvalue = 0, height=1, \ width = 20) self.log_active = IntVar() self.log_active.trace("w",self.saveLog) self.log_active.set(1) self.log_active_btn = tk.Checkbutton(self.root,text = "Save Log", variable = self.log_active, \ onvalue = 1, offvalue = 0, height=1, \ width = 10) self.alpha_entry.place(relx=0.5, rely=0.03, anchor="w") self.label_alpha_entry.place(relx=0.4, rely=0.03, anchor="e") self.start_temp_entry.place(relx=0.5, rely=0.105, anchor="w") self.label_start_temp_entry.place(relx=0.4, rely=0.105, anchor="e") self.end_temp_entry.place(relx=0.5, rely=0.18, anchor="w") self.label_end_temp_entry.place(relx=0.4,rely=0.18,anchor="e") self.kb_entry.place(relx=0.5, rely=0.255, anchor="w") self.label_kb_set.place(relx=0.4, rely=0.255, anchor="e") self.drop_menu.place(relx=0.5,rely=0.33,anchor="w") self.label_drop_menu.place(relx=0.4,rely=0.33,anchor="e") self.sel_path_btn.place(relx=0.62,rely=0.405,anchor="w") self.label_log_path.place(relx=0.4,rely=0.405,anchor="e") self.log_path_entry.place(relx=0.5,rely=0.405,anchor="w") self.log_active_btn.place(relx=0.675,rely=0.405,anchor="w") self.description.place(relx=0.5,rely=0.7,anchor="center") self.label_error.place(relx=0.5,rely=0.875,anchor="center") self.run_sim_btn.place(relx=0.5, rely=0.95, anchor="center") self.kill_sim_btn.place(relx=0.25,rely=0.95,anchor="center") self.show_sim_btn.place(relx=0.675, rely=0.1425, anchor="w") self.alpha_entry.delete(0,"end") self.alpha_entry.insert(0,"95") self.start_temp_entry.delete(0,"end") self.start_temp_entry.insert(0,"100") self.end_temp_entry.delete(0,"end") self.end_temp_entry.insert(0,"1") self.kb_entry.delete(0,"end") self.kb_entry.insert(0,"1") self.kill_sim = False self.root.protocol("WM_DELETE_WINDOW", self.on_closing) self.root.update() def on_closing(self): tmp = "./tmp.dat" if (os.path.isfile(self.net_list_path)): os.remove(self.net_list_path) if (os.path.isfile(tmp)): os.remove(tmp) self.root.destroy() def saveLog(self,*args): self.log_path_entry.config(state='normal') self.log_path_entry.delete(0,tk.END) self.log_path_entry.config(state='disabled') if(self.log_active.get()==1): self.sel_path_btn.config(state='normal') else: self.sel_path_btn.config(state='disabled') def selPath(self): path = filedialog.askdirectory(initialdir="./") self.log_path_entry.config(state='normal') self.log_path_entry.delete(0,tk.END) self.log_path_entry.insert(0,path) self.log_path_entry.config(state='disabled') def killSim(self): self.kill_sim_btn.config(state="disabled") self.kill_sim = True self.sim_sa.stop = True def validate_entry(self,d,S): if(d=='1'): #something inserted for ch in S: if(ch.isdigit()==False): return False return True else: return True def runSolver(self): self.kill_sim = False alpha = float(self.alpha_entry.get()) t_start = float(self.start_temp_entry.get()) t_end = float(self.end_temp_entry.get()) kb = float(self.kb_entry.get()) log_path = self.log_path_entry.get() if(self.log_active.get()): if(os.path.isdir(log_path)==False): self.text_label_error.set("Log Path is Invalid") return else: log_path = None if(alpha >= 100 or alpha <= 0): self.text_label_error.set("\u03B1 invalid, must be between (0,100)") return if(t_end > t_start): self.text_label_error.set("T(start) must be greater than T(end)") return tag = ["UI"] ui_str = utility.returnTagListFromNetlistPath(self.net_list_path,tag) canv_width = 500 canv_height = 500 for row in ui_str: if(row[0]=="UI"): if(row[1]=="cwh"): #canvas width,height canv_width = int(row[2]) canv_height = int(row[3]) self.sim_sa_ui = display_ui(self.root,canv_width,canv_height) self.run_sim_btn.config(state="disabled") self.kill_sim_btn.config(state="normal") self.text_label_error.set("") if(self.selected.get()=="Partitioning"): self.sim_sa = saPartitionSolver(self.net_list_path,(alpha/100),t_start,t_end,kb,log_path) if(self.show_sim_active.get()): self.runSimulatedAnnealingPartitionItr() else: self.runSimulatedAnnealingPartition() else: self.sim_sa_ui.root.destroy() self.runSimulatedAnnealingTS() def runSimulatedAnnealingTS(self): self.run_sim_btn.config(state="normal") self.kill_sim_btn.config(state="disabled") messagebox.showwarning("Warning", "Work in Progress") def runSimulatedAnnealingPartitionItr(self): if(self.kill_sim ==True): self.run_sim_btn.config(state="normal") self.sim_sa_ui.root.destroy() return tmp_file = "./tmp.dat" cost,accepted,fin,reason,set1,set2 = self.sim_sa.runNextIteration(tmp_file) self.sim_sa_ui.importNetlist(tmp_file) self.sim_sa_ui.update() setA = "SetA = {" for _module in set1: setA += _module.name + " , " setA += " }" setB = "SetB = {" for _module in set2: setB += _module.name + " , " setB += " }" if(fin): self.run_sim_btn.config(state="normal") self.sim_sa_ui.changeTxt("Cost: " + str(cost) + "\n" + "Final Solution" + "\n" + setA + "\n" + setB) self.sim_sa_ui.activateMenuBar() self.sim_sa_ui.allow_kill = True self.kill_sim_btn.config(state="disabled") return if(accepted): self.sim_sa_ui.changeTxt("Cost: " + str(cost) + "\n" + "Solution Accepted" + "\n" + "Reason: " + reason + "\n" + setA + "\n" + setB) else: self.sim_sa_ui.changeTxt("Cost: " + str(cost) + "\n" + "Solution Rejected" + "\n" + "Reason: " + reason + "\n" + setA + "\n" + setB ) self.root.after(1000,self.runSimulatedAnnealingPartitionItr) def runSimulatedAnnealingPartition(self): tmp_file = "./tmp.dat" self.sim_sa_ui.changeTxt("SIM RUNNING") cost,set1,set2 = self.sim_sa.runUntilComplete(tmp_file) self.run_sim_btn.config(state="normal") if(self.kill_sim==True): self.sim_sa_ui.root.destroy() return setA = "SetA = {" for _module in set1: setA += _module.name + " , " setA += " }" setB = "SetB = {" for _module in set2: setB += _module.name + " , " setB += " }" self.sim_sa_ui.importNetlist(tmp_file) self.sim_sa_ui.update() self.sim_sa_ui.changeTxt("Cost: " + str(cost) + "\n" + "Final Solution" + "\n" + setA + "\n" + setB) self.sim_sa_ui.activateMenuBar() self.kill_sim_btn.config(state="disabled") self.sim_sa_ui.allow_kill = True def changeChoice(self,*args): self.description.config(state="normal") self.description.delete('1.0',tk.END) sa_str = "P = exp(-\u0394/k*T)" sa_str += "\nT = \u03B1*T'" if(self.selected.get()=="Partitioning"): sa_str += "\nIn Partitioning the solver will attempt to evenly divde the modules in the netlist into two seperatesets (setA and setB) by cutting nets. The sets aredecided by minimzing the total cutting cost required. The cost to cut a net is dictated by it's weight." self.description.insert(tk.INSERT,sa_str) else: sa_str += "\nIn Traveling Salesman the solver will attempt to visit all modules in the netlist in a route that minimizes total cost of travel without repeating a visit. The cost to travel from one module to another is dictated by the net's weight that connects the two." self.description.insert(tk.INSERT,sa_str) self.description.config(state="disabled")
class PricesEditor(Frame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.create_prices_ui() self.initial_values = {} self.table_modified = False def create_prices_ui(self): self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.frm_prices = Frame(self) self.frm_prices.rowconfigure(2, weight=1) self.frm_prices.columnconfigure(0, weight=1) self.frm_prices.grid(padx=10, pady=10, sticky='nsew') # Button Frame frm_btns = Frame(self.frm_prices, relief=SOLID, borderwidth=2) frm_btns.grid(row=0, column=0, pady=(0, 5), sticky='nsew') frm_btns.columnconfigure(10, weight=1) # self.entry_currency = \ # Combobox_Autocomplete(frm, list_of_items=['one of many currencies'], startswith_match=False) self.search_var = StringVar() self.entry_search = PlaceholderEntry(frm_btns, 'Search..', style='Default.TEntry', textvariable=self.search_var) self.search_var.trace_variable( 'w', lambda a, b, c: self.tree.search(self.entry_search.get_value())) self.entry_search.bind( '<Return>', lambda event: self.tree.search(self.entry_search.get_value(), find_next=True)) self.btn_apply = Button(frm_btns, text='Apply', command=self.applyChanges) self.btn_reload = Button( frm_btns, text='Reload', command=lambda: self.loadPrices(force_reload=True)) self.entry_search.grid(row=2, column=0, pady=5, padx=5) self.btn_apply.grid(row=2, column=2, pady=5) # frm.columnconfigure(3, weight=1) self.btn_reload.grid(row=2, column=3, sticky='e', pady=5) self.var_advanced = BooleanVar(False) self.var_advanced.trace_variable( 'w', lambda a, b, c: self._on_view_option_change()) self.cb_advanced = Checkbutton(frm_btns, text='Advanced', variable=self.var_advanced) self.cb_advanced.grid(row=2, column=10, sticky='e', padx=10) frm_border = Frame(self.frm_prices, relief=SOLID, borderwidth=2) frm_border.grid(row=2, column=0, sticky='nsew') frm_border.rowconfigure(2, weight=1) frm_border.columnconfigure(0, weight=1) # Tree Frame self.frm_tree = Frame(frm_border) self.frm_tree.grid(row=2, column=0, sticky='nsew', padx=5, pady=(0, 0)) self.frm_tree.rowconfigure(0, weight=1) self.frm_tree.columnconfigure(0, weight=1) self.tree = EditableTreeview(self.frm_tree, on_cell_update=self.onCellUpdate) scrly = AutoScrollbar(self.frm_tree, command=self.tree.yview) scrlx = AutoScrollbar(self.frm_tree, command=self.tree.xview, orient=HORIZONTAL) self.tree.config(yscrollcommand=scrly.set, xscrollcommand=scrlx.set) self.tree.grid(row=0, column=0, sticky='nsew') scrly.grid(row=0, column=1, sticky='nsew') scrlx.grid(row=1, column=0, sticky='nsew') # Button Frame frm = Frame(frm_border) #, relief=SOLID, borderwidth=1) # frm = Frame(self.frm_prices) frm.grid(row=0, column=0, sticky='nsew') # self.entry_currency = \ # Combobox_Autocomplete(frm, list_of_items=['one of many currencies'], startswith_match=False) lbl = Label(frm, text='Item value threshold:') lbl.grid(row=0, column=0, padx=5, pady=5, sticky='w') self.var_threshold = StringVar() self.entry_threshold = TooltipEntry(frm, textvariable=self.var_threshold) self.entry_threshold.bind( '<FocusOut>', lambda event: self._validate_threshold_entry()) self.entry_threshold.grid(row=0, column=1, padx=5, pady=5) self.var_threshold.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_threshold)) lbl = Label(frm, text='Budget:') lbl.grid(row=0, column=2, padx=5, pady=5) self.var_budget = StringVar() self.entry_budget = TooltipEntry(frm, textvariable=self.var_budget) self.entry_budget.bind('<FocusOut>', lambda event: self._validate_budget_entry()) self.entry_budget.grid(row=0, column=3, padx=5, pady=5) self.var_budget.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_budget)) lbl = Label(frm, text='Minimum price:') lbl.grid(row=0, column=4, padx=5, pady=5) self.var_min_price = StringVar() self.entry_min_price = TooltipEntry(frm, textvariable=self.var_min_price) self.entry_min_price.bind( '<FocusOut>', lambda event: self._validate_min_price_entry()) self.entry_min_price.grid(row=0, column=5, padx=5, pady=5) self.var_min_price.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_min_price)) lbl = Label(frm, text='Default filter override:') lbl.grid(row=0, column=6, padx=5, pady=5) self.lbl_fprice_override = lbl self.var_fprice_override = StringVar() self.entry_fprice_override = TooltipEntry( frm, textvariable=self.var_fprice_override) self.entry_fprice_override.bind( '<FocusOut>', lambda event: self._validate_fprice_override_entry()) self.entry_fprice_override.grid(row=0, column=7, padx=5, pady=5) self.var_fprice_override.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_fprice_override)) # Advanced lbl = Label(frm, text='Default item value override:') lbl.grid(row=1, column=0, padx=5, pady=(2, 5), sticky='w') self.lbl_price_override = lbl self.var_price_override = StringVar() self.entry_price_override = TooltipEntry( frm, textvariable=self.var_price_override) self.entry_price_override.bind( '<FocusOut>', lambda event: self._validate_price_override_entry()) self.entry_price_override.grid(row=1, column=1, padx=5, pady=(2, 5)) self.var_price_override.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_price_override)) # Confidence Level lbl = Label(frm, text="Confidence level:") lbl.grid(row=1, column=2, padx=5, pady=(2, 5), sticky='w') self.lbl_confidence_lvl = lbl self.var_confidence_lvl = IntVar() self.entry_confidence_lvl = ConfidenceScale( frm, variable=self.var_confidence_lvl) self.entry_confidence_lvl.grid(row=1, column=3, padx=5, pady=(2, 5)) self.var_confidence_lvl.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_confidence_lvl)) self.var_5l_filters = BooleanVar(False) self.cb_5l_filters = VarCheckbutton(frm, text='Enable 5L filters', variable=self.var_5l_filters) self.cb_5l_filters.var = self.var_5l_filters self.cb_5l_filters.grid(row=1, column=4, padx=5, pady=(2, 5), columnspan=1) self.var_5l_filters.trace_variable( 'w', lambda a, b, c: self.on_entry_change(self.cb_5l_filters)) # Tree Config tree = self.tree def init_tree_column(col): col_name = pricesColumns[0] if col == '#0' else col tree.heading(col, text=PricesColumn[col_name].value, anchor=W, command=lambda col=col: tree.sort_col(col)) tree.column(col, width=140, stretch=False) # self.tree['columns'] = ('ID', 'Item Price', 'Override', 'Filter Price', 'Filter Override', 'Effective Filter Price', 'Filter State Override', '') self.tree['columns'] = pricesColumns[1:] self.tree.register_column( PricesColumn.Override.name, ColEntry(TooltipEntry(self.tree), func_validate=_validate_price_override)) self.tree.register_column( PricesColumn.FilterOverride.name, ColEntry(TooltipEntry(self.tree), func_validate=_validate_price_override)) self.tree.register_column( PricesColumn.FilterStateOverride.name, ColEntry(Combobox(self.tree, values=filterStateOptions, state=READONLY), accept_events=('<<ComboboxSelected>>', '<Return>'))) for col in (('#0', ) + tree['columns']): init_tree_column(col) tree.heading('#0', anchor=CENTER) tree.column('#0', width=200, stretch=False) tree.column(PricesColumn.Filler.name, stretch=True) tree.heading(PricesColumn.ItemPrice.name, command=lambda col=PricesColumn.ItemPrice.name: tree. sort_col(col, key=self._price_key)) tree.heading(PricesColumn.Override.name, command=lambda col=PricesColumn.Override.name: tree. sort_col(col, key=self._price_key)) tree.heading(PricesColumn.FilterOverride.name, command=lambda col=PricesColumn.FilterOverride.name: tree. sort_col(col, key=self._price_key)) tree.heading(PricesColumn.FilterPrice.name, command=lambda col=PricesColumn.FilterPrice.name: tree. sort_col(col, key=self._rate_key, default=0)) tree.heading(PricesColumn.EffectiveFilterPrice.name, command=lambda col=PricesColumn.EffectiveFilterPrice.name: tree.sort_col(col, key=self._rate_key, default=0)) self.bvar_modified = BooleanVar() self.bvar_modified.trace('w', lambda a, b, c: self._updateApplyState()) self.bvar_modified.set(False) self.var_advanced.set(False) def _rate_key(self, key): if key == 'N/A': return 0 return float(key) def _price_key(self, key): if key == '': return None # this means it will be ignored while sorting try: return cm.compilePrice(key, base_price=0) except Exception: return 0 def on_entry_change(self, entry): val = entry.get() if self.initial_values[entry] != val: self.bvar_modified.set(True) # def on_price_entry_focusout(self, widget): # valid = _validate_price(widget, accept_empty=False) # if valid and not self.bvar_modified.get() and self.initial_values[widget] != widget.get(): # self.bvar_modified.set(True) # return valid # # def on_override_entry_focusout(self, widget): # valid = _validate_price_override(widget, accept_empty=False) # if valid and not self.bvar_modified.get() and self.initial_values[widget] != widget.get(): # self.bvar_modified.set(True) # return valid def _validate_threshold_entry(self): return _validate_price(self.entry_threshold, accept_empty=False) def _validate_budget_entry(self): return _validate_price(self.entry_budget, accept_empty=True) def _validate_min_price_entry(self): return _validate_price(self.entry_min_price, accept_empty=True) def _validate_price_override_entry(self): return _validate_price_override(self.entry_price_override, accept_empty=False) def _validate_fprice_override_entry(self): return _validate_price_override(self.entry_fprice_override, accept_empty=False) def _update_modified(self): modified = any(entry.get() != self.initial_values[entry] for entry in self.initial_values) or self.table_modified self.bvar_modified.set(modified) def _updateApplyState(self): if self.bvar_modified.get(): self.btn_apply.config(state=NORMAL) else: self.btn_apply.config(state=DISABLED) def _validateForm(self): if not self._validate_threshold_entry(): return False if not self._validate_budget_entry(): return False if not self._validate_min_price_entry(): return False if not self._validate_price_override_entry(): return False if not self._validate_fprice_override_entry(): return False return True def applyChanges(self, event=None): if not self.bvar_modified.get() or not fm.initialized: return if not self._validateForm(): return price_threshold = self.entry_threshold.get() default_price_override = self.entry_price_override.get() default_fprice_override = self.entry_fprice_override.get() budget = self.entry_budget.get() min_price = self.entry_min_price.get() confidence_lvl = self.entry_confidence_lvl.get( ) or fm.DEFAULT_CONFIDENCE_LEVEL enable_5l_filters = self.var_5l_filters.get() price_overrides = {} filter_price_overrides = {} filter_state_overrides = {} for iid in self.tree.get_children(): id = self.tree.set(iid, PricesColumn.ID.name) iprice = self.tree.set(iid, PricesColumn.Override.name) if iprice: price_overrides[id] = iprice fprice = self.tree.set(iid, PricesColumn.FilterOverride.name) if fprice: filter_price_overrides[id] = fprice fstate = self.tree.set(iid, PricesColumn.FilterStateOverride.name) try: filter_state_overrides[id] = FilterStateOption[fstate].value except KeyError: pass ids = set([ self.tree.set(iid, PricesColumn.ID.name) for iid in self.tree.get_children() ]) # preserve unhandled ids configuration for key in (set(fm.price_overrides) - ids): price_overrides[key] = fm.price_overrides[key] for key in (set(fm.filter_price_overrides) - ids): filter_price_overrides[key] = fm.filter_price_overrides[key] for key in (set(fm.filter_state_overrides) - ids): filter_state_overrides[key] = fm.filter_state_overrides[key] try: fm.updateConfig(default_price_override, default_fprice_override, price_threshold, budget, min_price, price_overrides, filter_price_overrides, filter_state_overrides, int(confidence_lvl), enable_5l_filters) except AppException as e: messagebox.showerror( 'Validation error', 'Failed to update configuration:\n{}'.format(e), parent=self.winfo_toplevel()) except Exception as e: logexception() messagebox.showerror( 'Update error', 'Failed to apply changes, unexpected error:\n{}'.format(e), parent=self.winfo_toplevel()) else: # SHOULD always work since config is valid, main console will report any failures # background thread because schema validating takes a bit of time threading.Thread(target=fm.compileFilters).start() self._initFormState() def loadPrices(self, force_reload=False): if not cm.initialized or not fm.initialized: return if not force_reload: self._update_modified() # in case of reverted changes if self.bvar_modified.get(): # dont interrupt user changes return tree = self.tree tree.clear() table = {} for fltr in fm.autoFilters: # effective_rate = cm.crates.get(curr, '') # if effective_rate != '': # effective_rate = round(effective_rate, 3) fid = fltr.id fstate_override = fm.filter_state_overrides.get(fid, '') try: fstate_override = FilterStateOption(fstate_override).name except ValueError: fstate_override = '' table[fid] = (fltr.title, fid, fm.item_prices[fid], fm.price_overrides.get(fid, ''), _to_display_rate( fm.compiled_item_prices.get(fid, 'N/A')), fm.filter_price_overrides.get(fid, ''), _to_display_rate( fm.compiled_filter_prices.get(fid, 'N/A')), fstate_override) for fid in table: tree.insert('', END, '', text=table[fid][0], values=table[fid][1:]) # tree.sort_by('#0', descending=True) tree.sort_col('#0', reverse=False) self._initFormState() # def onItemPriceUpdate(self, iid, col, old, new): # print('IPrice update: iid {}, col {}'.format(iid, col)) def onCellUpdate(self, iid, col, old, new): if old != new: self.table_modified = True self.bvar_modified.set(True) # self._update_modified() def _initFormState(self): self.table_modified = False self.initial_values[self.entry_threshold] = fm.price_threshold self.initial_values[self.entry_budget] = fm.budget self.initial_values[self.entry_min_price] = fm.default_min_price self.initial_values[ self.entry_price_override] = fm.default_price_override self.initial_values[ self.entry_fprice_override] = fm.default_fprice_override self.initial_values[self.entry_confidence_lvl] = fm.confidence_level self.initial_values[self.cb_5l_filters] = fm.enable_5l_filters self.var_threshold.set(fm.price_threshold) self.var_budget.set(fm.budget) self.var_min_price.set(fm.default_min_price) self.var_price_override.set(fm.default_price_override) self.var_fprice_override.set(fm.default_fprice_override) self.var_confidence_lvl.set(fm.confidence_level) self.var_5l_filters.set(fm.enable_5l_filters) self.bvar_modified.set(False) def _on_view_option_change(self): advanced_widgets = [ self.entry_price_override, self.lbl_price_override, self.lbl_confidence_lvl, self.entry_confidence_lvl, self.cb_5l_filters ] if not self.var_advanced.get(): for w in advanced_widgets: w.grid_remove() self.tree.config(displaycolumn=[ PricesColumn.FilterPrice.name, PricesColumn.FilterOverride. name, PricesColumn.EffectiveFilterPrice.name, PricesColumn.Filler.name ]) else: for w in advanced_widgets: w.grid() self.tree.config(displaycolumn='#all') self.tree.on_entry_close()
def __init__(self, parent, fixNum, mode_): global loaded, devicesLoaded, device # self.communicationThread = threading.Thread(target = self.testMessages) # completeIndSend = IntVar() # completeIndSend.set(0) # completeIndSend.trace('w', self.updateComVar) loaded = IntVar() loaded.set(getNumDevicesLoaded()) loaded.trace("w", updateDevicesLoaded) device = StringVar() device.set(None) s = ttk.Style() s.theme_use('default') s.configure("red.Horizontal.TProgressbar", foreground='red', background='red') s.configure("green.Horizontal.TProgressbar", foreground='green', background='green') self.parent = parent self.fixNum = fixNum self.parent.title("WROOM-xx Programmer") self.stations = [] self.frame = tk.Frame(self.parent) self.configureMenu() self.titleLabel = tk.Label(self.frame, text='Details/Instructions', font=10) self.instructions = tk.Label(self.frame, text='- Programming stations \ are labelled with both COM ports listed in cfg.txt\n \ - Click START to begin the upload', pady=5) devices = getCOMPorts(int(self.fixNum) - 1) self.mode = mode_ ### Get screen resolution metrics user32 = ctypes.windll.user32 screenWidth = user32.GetSystemMetrics(0) screenHeight = user32.GetSystemMetrics(1) height = screenHeight if self.mode == "prod": height /= 2 else: height /= 1.5 xpos = (self.fixNum - 1) * (screenWidth / 2) self.parent.geometry( str(int(screenWidth / 2)) + "x" + str(int(height)) + "+" + str(int(xpos)) + "+0") devicesLoaded = tk.Label(self.frame, text=("Devices Loaded: " + str(loaded.get())).ljust(10), pady=10) self.buttonFrame = tk.Frame(self.frame) self.clearCounter = tk.Button(self.buttonFrame, text="Clear Counter", width=15, bg=gridColor, height=2, command=clearDevCounter) # self.start = tk.Button(self.buttonFrame, text = "START", width = 22, bg = gridColor, height = 3, command = self.startUpload, state = tk.DISABLED) self.configureFirmwareSelection() self.createDeviceOptions() self.packObjects() # d[0] is common port; begin Station initalization at 1, passing in unique station id for d in range(0, len(devices)): self.stations.append(Station(parent, devices[d], d))
class CurrencyEditor(Frame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) self.bvar_modified = BooleanVar() self.create_currency_ui() def create_currency_ui(self): self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.frm_currency = Frame(self) self.frm_currency.rowconfigure(2, weight=1) self.frm_currency.columnconfigure(0, weight=1) self.frm_currency.grid(padx=10, pady=10, sticky='nsew') # Tree Frame self.frm_tree = Frame(self.frm_currency) self.frm_tree.grid(row=2, sticky='nsew') self.frm_tree.rowconfigure(0, weight=1) self.frm_tree.columnconfigure(0, weight=1) self.tree = EditableTreeview(self.frm_tree, on_cell_update=self.onCellUpdate) scrly = AutoScrollbar(self.frm_tree, command=self.tree.yview) scrlx = AutoScrollbar(self.frm_tree, command=self.tree.xview, orient=HORIZONTAL) self.tree.config(yscrollcommand=scrly.set, xscrollcommand=scrlx.set) self.tree.grid(row=0, column=0, sticky='nsew') scrly.grid(row=0, column=1, sticky='nsew') scrlx.grid(row=1, column=0, sticky='nsew') self.tree.insert('', 0, text='Exalted Orb', values=('90', '85')) frm = Frame(self.frm_currency, relief=SOLID, borderwidth=2) frm.columnconfigure(10, weight=1) frm.grid(row=1, column=0, pady=(0, 5), sticky='nsew') # self.entry_currency = \ # Combobox_Autocomplete(frm, list_of_items=['one of many currencies'], startswith_match=False) self.search_var = StringVar() self.entry_search = PlaceholderEntry(frm, 'Search..', style='Default.TEntry', textvariable=self.search_var) self.search_var.trace_variable( 'w', lambda a, b, c: self.tree.search(self.entry_search.get_value())) self.entry_search.bind( '<Return>', lambda event: self.tree.search(self.entry_search.get_value(), find_next=True)) # self.btn_currency_search = Button(frm, text='Search', command=lambda event: self.tree_currency.search(self.entry_currency_search.get_value(), find_next=True)) self.btn_apply = Button(frm, text='Apply', command=self.applyChanges) self.btn_reload = Button( frm, text='Reload', command=lambda: self.loadCurrency(force_reload=True)) self.entry_search.grid(row=2, column=0, pady=5, padx=5) # self.btn_currency_search.grid(row=2, column=1, pady=5) self.btn_apply.grid(row=2, column=2, pady=5) # frm.columnconfigure(3, weight=1) self.btn_reload.grid(row=2, column=3, sticky='e', pady=5) # Confidence Level lbl = Label(frm, text="Confidence level:") lbl.grid(row=2, column=10, padx=5, sticky='nse', pady=(3, 5)) self.lbl_confidence_lvl = lbl self.var_confidence_lvl = IntVar() self.entry_confidence_lvl = ConfidenceScale( frm, variable=self.var_confidence_lvl) self.entry_confidence_lvl.grid(row=2, column=11, padx=5, pady=5) self.var_confidence_lvl.trace( 'w', lambda a, b, c: self.on_entry_change(self.entry_confidence_lvl)) # Tree Config tree = self.tree tree['columns'] = currencyColumns[1:] tree.register_column( 'Override', ColEntry(TooltipEntry(tree), func_validate=_validate_price_override)) def init_tree_column(col): col_name = currencyColumns[0] if col == '#0' else col tree.heading(col, text=CurrencyColumn[col_name].value, anchor=W, command=lambda col=col: tree.sort_col(col)) tree.column(col, width=140, stretch=False) for col in ('#0', ) + tree['columns']: init_tree_column(col) tree.heading('#0', anchor=CENTER) tree.column('#0', width=250, stretch=False) tree.column(CurrencyColumn.Filler.name, stretch=True) tree.heading(CurrencyColumn.Rate.name, command=lambda col=CurrencyColumn.Rate.name: tree. sort_col(col, key=float, default=0)) tree.heading(CurrencyColumn.EffectiveRate.name, command=lambda col=CurrencyColumn.EffectiveRate.name: tree .sort_col(col, key=float, default=0)) tree.heading(CurrencyColumn.Override.name, command=lambda col=CurrencyColumn.Override.name: tree. sort_col(col, key=self._price_key)) self.bvar_modified.trace('w', lambda a, b, c: self._updateApplyState()) def _price_key(self, key): if key == '': return None # this means it will be ignored while sorting try: return cm.compilePrice(key, base_price=0) except Exception: return 0 def _updateApplyState(self): if self.bvar_modified.get(): self.btn_apply.config(state=NORMAL) else: self.btn_apply.config(state=DISABLED) def loadCurrency(self, force_reload=False): if not cm.initialized: return if not force_reload and self.bvar_modified.get(): return self.var_confidence_lvl.set(cm.confidence_level) tree = self.tree tree.clear() table = {} for curr in cm.shorts: effective_rate = cm.crates.get(curr, '0') table[curr] = (_to_display_rate(cm.rates.get(curr, '')), cm.overrides.get(curr, ''), _to_display_rate(effective_rate)) for curr in table: tree.insert('', END, '', text=curr, values=table[curr]) tree.sort_col(CurrencyColumn.EffectiveRate.name, key=float, default=0) self.bvar_modified.set(False) def applyChanges(self, event=None): if not self.bvar_modified.get() or not cm.initialized: return overrides = {} for iid in self.tree.get_children(): #TODO: hide #0 col and move names to a value column currency_name_col = '#0' # CurrencyColumn.Currency.name # id = self.tree.set(iid, currency_name_col) id = self.tree.item(iid, 'text') override = self.tree.set(iid, CurrencyColumn.Override.name) if override: overrides[id] = override # ids = set([self.tree.set(iid, currency_name_col) for iid in self.tree.get_children()]) ids = set( [self.tree.item(iid, 'text') for iid in self.tree.get_children()]) # preserve unhandled ids configuration for key in (set(cm.overrides) - ids): overrides[key] = cm.overrides[key] cm.confidence_level = self.entry_confidence_lvl.get() try: cm.compile(overrides=overrides) if fm.initialized: threading.Thread(target=fm.compileFilters).start() self.bvar_modified.set(False) except AppException as e: messagebox.showerror('Update error', e, parent=self.winfo_toplevel()) except Exception as e: logexception() messagebox.showerror( 'Update error', 'Failed to apply changes, unexpected error:\n{}'.format(e), parent=self.winfo_toplevel()) def onCellUpdate(self, iid, col, old, new): if not self.bvar_modified.get() and old != new: self.bvar_modified.set(True) def on_entry_change(self, entry): self.bvar_modified.set(True)
class ImageCropper(Frame): def __init__(self, parent, image, cropsize, returntype='bboxscale', *args, **kw): Frame.__init__(self, parent, *args, **kw) self.original = PILImage.open(open(image, 'rb')) if self.original.size[0] > 800 or self.original.size[1] > 800: self.original.thumbnail((800, 800), PILImage.LANCZOS) self.cropsize = cropsize self.returntype = returntype self.previewlabel = Label(self) self.previewlabel.pack() self.canvas = Canvas(self, width=self.original.size[0], height=self.original.size[1]) self.img = ImageTk.PhotoImage(self.original) self.image = self.canvas.create_image(self.original.size[0] // 2, self.original.size[1] // 2, image=self.img) self.canvas.pack(padx=5, pady=10) self._drag_data = {} self.cropregion = self.canvas.create_rectangle(2, 2, cropsize[0], cropsize[1], width=2) def _handcursor(event): self.canvas['cursor'] = 'hand2' def _arrowcursor(event): self.canvas['cursor'] = 'arrow' self.canvas.tag_bind(self.cropregion, '<Enter>', _handcursor) self.canvas.tag_bind(self.cropregion, '<Leave>', _arrowcursor) self.canvas.tag_bind(self.cropregion, "<ButtonPress-1>", self.OnTokenButtonPress) self.canvas.tag_bind(self.cropregion, "<ButtonRelease-1>", self.OnTokenButtonRelease) self.canvas.tag_bind(self.cropregion, "<B1-Motion>", self.OnTokenMotion) self.scalevar = IntVar() maxcrop = min(self.original.size[0] / cropsize[0] * 100, self.original.size[1] / cropsize[1] * 100) self.scale = Scale(self, from_=1, to=maxcrop, orient='horizontal', variable=self.scalevar) self.scale.set(100) self.scalevar.trace('w', self.scalebbox) self.scale.pack() self.bf = Frame(self, bg=self['bg']) self.bf.pack() self.updatepreview() def gather(self): if self.returntype == 'croppedimage': return self.getboundimage() else: return (self.canvas.bbox(self.cropregion), self.scalevar.get() / 100) def getboundimage(self): img = self.original.crop(self.canvas.bbox(self.cropregion)) if img.size[0] < self.cropsize[0]: img = img.resize(self.cropsize, PILImage.LANCZOS) else: img.thumbnail(self.cropsize, PILImage.LANCZOS) return img def updatepreview(self): self.preview = self.getboundimage() self.preview = ImageTk.PhotoImage(self.preview) self.previewlabel['image'] = self.preview def scalebbox(self, *event): x1, y1, x2, y2 = self.canvas.coords(self.cropregion) centerpoint = (x1 + (x2 - x1) // 2, y1 + (y2 - y1) // 2) width, height = self.cropsize[0] * self.scalevar.get( ) / 100, self.cropsize[1] * self.scalevar.get() / 100 self.canvas.coords( self.cropregion, (centerpoint[0] - width // 2, centerpoint[1] - height // 2, centerpoint[0] + width // 2, centerpoint[1] + height // 2)) self.updatepreview() def OnTokenButtonPress(self, event): '''Being drag of an object''' # record the item and its location self._drag_data["x"] = event.x self._drag_data["y"] = event.y def OnTokenButtonRelease(self, event): '''End drag of an object''' # reset the drag information self._drag_data["x"] = 0 self._drag_data["y"] = 0 def OnTokenMotion(self, event): '''Handle dragging of an object''' # compute how much this object has moved delta_x = event.x - self._drag_data["x"] delta_y = event.y - self._drag_data["y"] ## Keep in screen x1, y1, x2, y2 = self.canvas.coords(self.cropregion) height, width = int(self.canvas.cget("height")), int( self.canvas.cget("width")) if x1 + delta_x < 0: delta_x = -x1 elif x2 + delta_x > width: delta_x = width - x2 if y1 + delta_y < 0: delta_y = -y1 elif y2 + delta_y > height: delta_y = height - y2 # move the object the appropriate amount self.canvas.move(self.cropregion, delta_x, delta_y) # record the new position self._drag_data["x"] = event.x self._drag_data["y"] = event.y self.updatepreview()
class SettingsPopup(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent, background="#bbb", bd=1) self.controller = controller self.place(anchor="ne", relx=1, y=50) # self.geometry(str(400) + "x" + str(400)) whiteframe = Frame(self) whiteframe.pack(fill="both", expand=2, padx=1, pady=1) self.closeBtn = ImageTk.PhotoImage( PILImage.open("./close_btn.png").resize((8, 8))) buttonClose = Button(whiteframe, image=self.closeBtn, command=self.closeSettings) buttonClose.pack(anchor="w") # buttonClose.place(anchor="nw") bottomframe1 = Frame(whiteframe) bottomframe1.pack(side=BOTTOM) CameraLabel = Label(bottomframe1, text='Camera Number') CameraLabel.grid(row=1, column=0) self.camNumber = IntVar() entryCam = Entry(bottomframe1, textvariable=self.camNumber) entryCam.grid(row=1, column=1) self.camNumber.set(self.controller.get("camera")) self.camNumber.trace("w", self.setCamera) ComLabel = Label(bottomframe1, text='COM Port') ComLabel.grid(row=2, column=0) self.comNumber = IntVar() entryCom = Entry(bottomframe1, textvariable=self.comNumber) entryCom.grid(row=2, column=1) self.comNumber.set(self.controller.get("comPort")) self.comNumber.trace("w", self.setComPort) labelLat = Label(bottomframe1, text='Latitude (N+)') labelLat.grid(row=3, column=0) self.latVal = DoubleVar() self.latVal.set(self.controller.get("Lat")) self.latVal.trace("w", self.setLat) entryLat = Entry(bottomframe1, textvariable=self.latVal) entryLat.grid(row=3, column=1) labelLon = Label(bottomframe1, text='Longitude (E+)') labelLon.grid(row=4, column=0) self.lonVal = DoubleVar() self.lonVal.set(self.controller.get("Lon")) self.lonVal.trace("w", self.setLon) entryLon = Entry(bottomframe1, textvariable=self.lonVal) entryLon.grid(row=4, column=1) rotationLabel = Label(bottomframe1, text='Rotation') rotationLabel.grid(row=5, column=0) self.rotationAngle = IntVar() self.rotationAngle.set(self.controller.get("rotate")) self.rotationAngle.trace("w", self.setRot) entryRot = Entry(bottomframe1, textvariable=self.rotationAngle) entryRot.grid(row=5, column=1) horFlip = Button(bottomframe1, text='Horizontal Flip', command=self.setHorFlip) horFlip.grid(row=6, column=0) verFlip = Button(bottomframe1, text='Vertical Flip', command=self.setVerFlip) verFlip.grid(row=6, column=1) def getExposureStr(strValue): value = float(strValue) if value > 0: return "{:.3f}".format(pow(2, value)) else: return "1/{:.3f}".format(pow(2, abs(value))) def setExposureValue(strValue): value = float(strValue) self.controller.set("exposure", value) self.labelExposureVal.config(text=getExposureStr(value)) labelExposure = Label(bottomframe1, text="Exposure (s)") labelExposure.grid(row=7, column=0) self.labelExposureVal = Label(bottomframe1, text=getExposureStr( self.controller.get("exposure"))) self.labelExposureVal.grid(row=7, column=1) exposure = Scale(bottomframe1, from_=-15, to=5, resolution=.1, orient="horizontal", showvalue=0, command=setExposureValue) exposure.grid(row=8, column=0, columnspan=2, sticky="nesw") exposure.set(self.controller.get("exposure")) def setGainValue(strValue): value = int(strValue) self.controller.set("gain", value) self.labelGainVal.config(text=str(value)) labelGain = Label(bottomframe1, text="Gain") labelGain.grid(row=9, column=0) self.labelGainVal = Label(bottomframe1, text=str(self.controller.get("gain"))) self.labelGainVal.grid(row=9, column=1) gain = Scale(bottomframe1, from_=0, to=300, orient="horizontal", showvalue=0, command=setGainValue) gain.grid(row=10, column=0, columnspan=2, sticky="nesw") gain.set(self.controller.get("gain")) def setRefreshRate(strValue): value = int(strValue) self.controller.set("refreshRate", value) self.labelRefreshRateVal.config(text=str(value)) labelRefresh = Label(bottomframe1, text="Refresh Rate (FPS)") labelRefresh.grid(row=11, column=0) self.labelRefreshRateVal = Label( bottomframe1, text=str(self.controller.get("refreshRate"))) self.labelRefreshRateVal.grid(row=11, column=1) refreshRate = Scale(bottomframe1, from_=1, to=60, orient="horizontal", showvalue=0, command=setRefreshRate) refreshRate.grid(row=12, column=0, columnspan=2, sticky="nesw") refreshRate.set(self.controller.get("refreshRate")) def closeSettings(self): self.destroy() # noinspection PyUnusedLocal def setLat(self, *args): self.controller.set("Lat", varGetOrDefault(self.latVal, 0.0)) # noinspection PyUnusedLocal def setLon(self, *args): self.controller.set("Lon", varGetOrDefault(self.lonVal, 0.0)) # noinspection PyUnusedLocal def setComPort(self, *args): self.controller.set("comPort", varGetOrDefault(self.comNumber, 0)) # noinspection PyUnusedLocal def setCamera(self, *args): self.controller.set("camera", varGetOrDefault(self.camNumber, 0)) # noinspection PyUnusedLocal def setRot(self, *args): self.controller.set("rotate", varGetOrDefault(self.rotationAngle, 0)) # noinspection PyUnusedLocal def setHorFlip(self, *args): self.controller.set("flipHorizontal", not self.controller.get("flipHorizontal")) # noinspection PyUnusedLocal def setVerFlip(self, *args): self.controller.set("flipVertical", not self.controller.get("flipVertical"))
class InstructorGUI(tk.Frame): """Instructor GUI frame to be used in the main GUI This class contains multiple input widgets for the GUI, as well as the Client class used to connect with the socket server. """ # Settings header_1_style = "TkDefaultFont 18 bold" header_2_style = "TkDefaultFont 16 bold" default_style = "TkDefaultFont 14" def __init__(self, parent, *args, **kwargs): """Constructor Args: parent (tk.widget): parent widget to make the frame a child of *args: Variable length argument list **kwargs: Arbitrary keyword argument list """ ttk.Frame.__init__(self, parent, *args, **kwargs) self.parent = parent # Socket client self.client = Client(port=25565) # ============ GUI Variables ============ self.host = StringVar(self, value=self.client.get_hostname()) # Instructor realtime setting variables self.hr = IntVar(self, value=80) self.threshold = StringVar(self, value=20) self.hr_paced = IntVar(self, value=80) self.pathway_1 = IntVar(self, value=0) self.pathway_2 = IntVar(self, value=0) # Manual Override variables self.position = IntVar(self, value=0) self.is_pacing = BooleanVar(self, value=False) self.is_pos_overriding = BooleanVar(self, value=False) # ============ Main Frame Sides =========== # Left side frame frame_left = Frame(self, bd=1, relief=tk.SUNKEN) frame_left.pack(side=tk.LEFT, padx=10, pady=10) Label(frame_left, text="Override Settings", font=self.header_1_style).pack() # Middle frame frame_mid = Frame(self, bd=1, relief=tk.SUNKEN) frame_mid.pack(side=tk.LEFT, padx=10, pady=10) Label(frame_mid, text="Real-Time Settings", font=self.header_1_style).pack() # Right side frame frame_right = Frame(self, bd=1, relief=tk.SUNKEN) frame_right.pack(side=tk.RIGHT, padx=10, pady=10) Label(frame_right, text="Display Preview", font=self.header_1_style).pack() # ============ Position Selection =============== frame_position = Frame(frame_left) frame_position.pack(pady=5) # Sets the position variable to invoke a callback self.position.trace('w', self.callback_manual_pos) # Radiobutton options for the override POSITIONS = [ ("Superior Vena Cava", 1), ("High Right Atrium", 2), ("Mid Right Atrium", 3), ("Low Right Atrium", 4), ("Right Ventricle", 5), ("Right Ventricular Wall", 6), ("Asystole", 0), ] Label(frame_position, text="Show Manual Position", font=self.default_style).pack() # Creates each radiobutton item for button_text, position_value in POSITIONS: Radiobutton(frame_position, text=button_text, value=position_value, variable=self.position, font=self.default_style).pack() # Creates a toggle button to start/stop the manual override self.btn_pos_override = Button(frame_position, text="Start Override", command=self.toggle_pos_override, fg="green", font=self.default_style) self.btn_pos_override.pack() # ============ Command Sends ============= frame_command = Frame(frame_left) frame_command.pack(pady=5) Label(frame_command, text="Commands", font=self.default_style).pack() # Button to make the microcontroller recalibrate its sensor values btn_recalibrate = Button(frame_command, text="Calibrate Sensors", command=lambda: self.send_command('cal'), fg="green", font=self.default_style) btn_recalibrate.pack(side=tk.LEFT) # Button to make the student GUI restart the signal at asystole in case it gets stuck btn_reset_signal = Button(frame_command, text="Reset Signal (Asystole)", command=lambda: self.send_command('ressig'), fg="green", font=self.default_style) btn_reset_signal.pack(side=tk.LEFT) # ============ Connection Space =============== frame_connection = Frame(frame_mid) frame_connection.pack(pady=5) # Displays the host machine's IP address for use with the other GUI ip_label = "Device IP: {}".format(self.client.get_ip()) Label(frame_connection, text=ip_label, font=self.default_style).pack() Label(frame_connection, text="Hostname", font=self.default_style).pack(side=tk.LEFT) # Area to enter the hostname to connect to entry_hostname = Entry(frame_connection, textvariable=self.host, font=self.default_style) entry_hostname.pack(side=tk.LEFT) # Button to start the TCP/IP connection btn_connect = Button(frame_connection, text="Connect", command=self.connect, fg="green", font=self.default_style) btn_connect.pack(side=tk.LEFT) # ============ Customisation Space =============== frame_signal = Frame(frame_mid) frame_signal.pack(pady=5) # Intrinsic heart rate entry area Label(frame_signal, text="Heart Rate", font=self.default_style).grid(row=0, column=0) scale_hr = Scale(frame_signal, from_=0, to=100, length=150, variable=self.hr, orient=tk.HORIZONTAL) scale_hr.grid(row=0, column=1) entry_hr = Entry(frame_signal, textvariable=self.hr, font=self.default_style, width=4) entry_hr.grid(row=0, column=2) # Pacing threshold entry area Label(frame_signal, text="Pacing Threshold", font=self.default_style).grid(row=1, column=0) scale_threshold = Scale(frame_signal, from_=0, to=50, length=150, variable=self.threshold, orient=tk.HORIZONTAL) scale_threshold.grid(row=1, column=1) entry_threshold = Entry(frame_signal, textvariable=self.threshold, font=self.default_style, width=4) entry_threshold.grid(row=1, column=2) # Paced heart rate entry area Label(frame_signal, text="Paced Heart Rate", font=self.default_style).grid(row=2, column=0) scale_hr_paced = Scale(frame_signal, from_=0, to=100, length=150, variable=self.hr_paced, orient=tk.HORIZONTAL) scale_hr_paced.grid(row=2, column=1) entry_hr_paced = Entry(frame_signal, textvariable=self.hr_paced, font=self.default_style, width=4) entry_hr_paced.grid(row=2, column=2) # Buttons for this area frame_signal_buttons = Frame(frame_signal) frame_signal_buttons.grid(row=3, columnspan=3) # Sends the updated settings (heart rate, pacing threshold, paced heart rate) to the student GUI btn_send_customisations = Button(frame_signal_buttons, text="Update ECG", command=self.send_customisations, fg="green", font=self.default_style, pady=5) btn_send_customisations.pack(side=tk.LEFT, fill=tk.X) # Starts a simulated pacer signal self.btn_pacing = Button(frame_signal_buttons, text="Start Pacing", command=self.toggle_pacing, fg="green", font=self.default_style, pady=5) self.btn_pacing.pack(side=tk.RIGHT, fill=tk.X) # ========== Pathway Selection ============== frame_pathway = Frame(frame_mid) frame_pathway.pack(pady=5) # Sets both pathway variables to invoke a callback self.pathway_1.trace('w', self.callback_pathway_1) self.pathway_2.trace('w', self.callback_pathway_2) # Alternate pathway options PATHWAYS_1 = [ ("Low Right Atrium", 0), ("Inferior Vena Cava", 10) ] PATHWAYS_2 = [ ("Right Ventricular Wall", 0), ("Pulmonary Artery", 10) ] Label(frame_pathway, text="Pathway Selection 1", font=self.header_2_style).pack(pady=5) # Create each radiobutton for the first pathway option for button_text, pathway_value in PATHWAYS_1: Radiobutton(frame_pathway, text=button_text, value=pathway_value, variable=self.pathway_1, font=self.default_style).pack() Label(frame_pathway, text="Pathway Selection 2", font=self.header_2_style).pack(pady=5) # Create each radiobutton for the second pathway option for button_text, pathway_value in PATHWAYS_2: Radiobutton(frame_pathway, text=button_text, value=pathway_value, variable=self.pathway_2, font=self.default_style).pack() # ======== Display Preview ========= # Instantiated signals class to generate signals self.ecg_signals = Signals() self.new_x = [0.0] self.new_y = [0.0] self.last_x = 0 self.last_x_lim = 0 self.position_to_show = 0 self.variation = 0 self.flat_span = False self.end_flat = 0 self.flat_span_y = 0 self.plot_point = 0 # Creates plotting canvas self.fig = plt.Figure(figsize=(10, 4.5), dpi=100,facecolor='k',edgecolor='k') canvas = FigureCanvasTkAgg(self.fig, master=frame_right) canvas.get_tk_widget().pack() # Sets plot customisations self.ax = self.fig.add_subplot(111) self.ax.set_xlim(self.last_x_lim, 4) self.ax.set_ylim(-3.0, 3.0) self.ax.set_yticklabels([]) self.ax.set_xticklabels([]) self.ax.xaxis.set_tick_params(width=1, top=True) self.ax.set_facecolor('black') self.line, = self.ax.plot(0, 0) self.ax.get_lines()[0].set_color("xkcd:lime") # Starts an animated plot for the ECG signal self.ani = animation.FuncAnimation(self.fig, self.animate, interval=24, blit=True) def animate(self, i): """Animation function that is called periodically Args: i (int): the current frame value (not used) Returns: line (matplotlib.line): The line to plot with the next value """ # If currently overriding the student GUI, show the display preview if self.is_pos_overriding.get(): # Set the position index value based on which source is responsible for the signal position_index = self.position.get() # Set initial heart rate to use hr_to_use = self.hr.get() # Adjust position and heart rate based on alternative pathways and pacer setting if position_index == 4: position_index = position_index + self.pathway_1.get() elif position_index == 6: position_index = position_index + self.pathway_2.get() # Show the paced signal if pacer override is active if not position_index == 16 and self.is_pacing.get(): position_index = 26 hr_to_use = self.hr_paced.get() else: # If no overrides or special settings, just keep the position the same position_index = position_index # Get the ECG signal values for the corresponding settings [x, y] = self.ecg_signals.get_signal(self.ecg_signals.signal_index[position_index], hr_to_use) # If not currently traveling between beats if not self.flat_span: # Set a variable to the potential next value x_val = self.last_x + x[self.plot_point] # If the potential new value is not going backwards if x_val > self.new_x[-1]: # Add the new x and y values to the axis lists self.new_x.append(x_val) self.new_y.append(y[self.plot_point]) # Update the line self.line.set_data(self.new_x, self.new_y) # update the data # If at the end of the beat if self.plot_point== 29: # Update where the last x value to build from is self.last_x = self.new_x[-1] # Start plotting for a flat area self.end_flat = (x[-1] - x[-2]) + self.new_x[-1] self.flat_span_y = y[-1] self.flat_span = True # Go back to the start of the heart beat if at the end of the beat if self.plot_point == 29: self.plot_point = 0 # Go to the next beat value otherwise else: self.plot_point = self.plot_point + 1 # If current traveling between beats else: # Add the new x and y values to the axis lists self.new_x.append(self.new_x[-1] + 0.05) self.new_y.append(self.flat_span_y) # Update the line self.line.set_data(self.new_x, self.new_y) # update the data # If reached the end of the flat line area between beats if self.new_x[-1] >= self.end_flat: # Stop plotting flat self.flat_span = False self.last_x = self.new_x[-1] # If at the end of the plotting window if self.new_x[-1] >= self.last_x_lim + 5: # Shift the plotting window (this is used instead of a reset to allow for future ECG output options) self.last_x_lim += 5 self.ax.set_xlim(self.last_x_lim, self.last_x_lim + 5) # Returns the new line to the plot return self.line, def connect(self): """Connects the instructor GUI to the student GUI""" # Update the hostname self.client.set_hostname(self.host.get()) # Actually connect self.client.start() def send_command(self, message): """Sends a message from the instructor GUI to the student GUI Args: message (str): Message to send through the socket connection """ self.client.send_data(message) def send_customisations(self): """Sends updated customisation data from instructor GUI to the student GUI""" # Command code self.client.send_data("update") # Data self.client.send_data("{},{},{}".format(self.hr.get(), self.threshold.get(), self.hr_paced.get())) def toggle_pos_override(self): """Sends position override data from the instructor to the student GUI""" # Toggle if we are overriding self.is_pos_overriding.set(not self.is_pos_overriding.get()) # If we are now overriding if self.is_pos_overriding.get(): # Start command code self.client.send_data("start-pos") # Data self.client.send_data("%d" % self.position.get()) # Switch the toggle button self.btn_pos_override.config(fg="red", text="Stop Override") self.ani.event_source.start() # If we are now not overriding else: # Stop command code self.client.send_data("stop-pos") # Switch the toggle button self.btn_pos_override.config(fg="green", text="Start Override") # Stop the preview plotting self.ani.event_source.stop() def toggle_pacing(self): """Toggles whether to be pacing""" # Toggles if we are pacing self.is_pacing.set(not self.is_pacing.get()) # If we are now pacing if self.is_pacing.get(): # Start pacing command code self.client.send_data("start-pace") # Send customisation network update self.send_customisations() # Switch the toggle button self.btn_pacing.config(fg="red", text="Stop Pacing") else: # Stop pacing command code self.client.send_data("stop-pace") # Switch the toggle button self.btn_pacing.config(fg="green", text="Start Pacing") def callback_pathway_1(self, *args): """Callback function for when the pathway is switched. This will automatically send an updated pathway. Args: *args: Variable length argument list """ # Command code self.client.send_data("chpa1") # Data self.client.send_data("%d" % self.pathway_1.get()) def callback_pathway_2(self, *args): """Callback function for when the pathway is switched. This will automatically send an updated pathway. Args: *args: Variable length argument list """ # Command code self.client.send_data("chpa2") # Data self.client.send_data("%d" % self.pathway_2.get()) def callback_manual_pos(self, *args): """Callback function for when the pathway is switched. This will automatically send an updated pathway. Args: *args: Variable length argument list """ # If we are actively overriding if self.is_pos_overriding.get(): # Command code self.client.send_data("manual-pos") # Data self.client.send_data("%d" % self.position.get()) def stop_gui(self): """Stops the instructor GUI client""" self.client.stop()
class MainFrame(Frame): MIN_ARCHIVE_SIZE = 100 * 1024 MAX_ARCHIVE_SIZE = 2.5 * 1024 * 1024 def __init__(self, master, **kwargs): super(MainFrame, self).__init__(master, **kwargs) self.master = master # Configurazione griglia self.grid_columnconfigure(0, weight=1, pad=10) self.grid_columnconfigure(1, weight=5, pad=10) self.grid_columnconfigure(2, weight=1, pad=10) # for i in range(0, 10): # self.grid_rowconfigure(i, pad=0, weight=1) # Titolo # Label(self, text="Pigroman", font=("Segoe UI", 16), image=icons.get_icon("icon.png"), # compound="left").grid(row=0, column=0, padx=(0, 30), sticky="w") self.data_path = StringVar() self.data_path.trace( "w", lambda *_: self.subfolders_list_frame.reevaluate_statuses()) self.output_path = StringVar() self.output_name = StringVar() self.max_block_size = IntVar() self.max_block_size.trace( "w", lambda *_: self.max_archive_size_label.configure( text=conversions.number_to_readable_size(self.max_block_size. get()))) self.compress = BooleanVar() self.create_esl = BooleanVar() self.file_types = defaultdict(BooleanVar) Label(self, text="Data path").grid(row=1, column=0, sticky="w") BrowseFrame(self, self.data_path).grid(row=1, column=1, sticky="we", columnspan=4) Label(self, text="Output path").grid(row=2, column=0, sticky="w") BrowseFrame(self, self.output_path).grid(row=2, column=1, sticky="we", columnspan=4) Label(self, text="Output name").grid(row=3, column=0, sticky="w") Entry(self, textvariable=self.output_name).grid(row=3, column=1, sticky="we", columnspan=2) Label(self, text="Max archive size").grid(row=4, column=0, sticky="w") Scale(self, from_=self.MIN_ARCHIVE_SIZE, to=self.MAX_ARCHIVE_SIZE, variable=self.max_block_size).grid(row=4, column=1, sticky="we") self.max_archive_size_label = Label(self) self.max_archive_size_label.grid(row=4, column=2, sticky="e") self.folders_group = LabelFrame(self, text="Subfolders") self.folders_group.grid(row=5, column=0, columnspan=5, sticky="nswe") self.subfolders_list_frame = SubfoldersListFrame( self.folders_group, self.data_path) self.subfolders_list_frame.pack(fill="both") self.options_group = LabelFrame(self, text="Options") self.options_group.grid(row=6, column=0, sticky="nswe", columnspan=3) Checkbutton(self.options_group, text="Compress", variable=self.compress).pack(side="left") Checkbutton(self.options_group, text="Create ESLs", variable=self.create_esl).pack(side="left") self.file_types_group = LabelFrame(self, text="File types (coming soon)") self.file_types_group.grid(row=7, column=0, sticky="nswe", columnspan=4) r = 0 c = 0 for i, x in enumerate(("Meshes", "Textures", "Menus", "Sounds", "Voices", "Shaders", "Trees", "Fonts", "Misc")): Checkbutton(self.file_types_group, text=x, variable=self.file_types[x.lower()], state="disabled").grid(row=r, column=c, sticky="we") c += 1 if c == 3: c = 0 r += 1 self.build_button = Button(self, text="Create packages!", image=icons.get_icon("save.png"), compound="left", command=self.build) self.build_button.grid(row=8, column=0, columnspan=4, sticky="we") self.max_block_size.set(1.5 * 1024 * 1024) def build(self): try: self.master.check_archive() self.check_settings() self.build_button.config(state="disabled") except ValueError as e: messagebox.showerror("Error", str(e)) finally: self.build_button.config(state="enabled") def check_settings(self): if not self.data_path.get().lower().strip().endswith("data"): raise ValueError("The data path must be a folder named 'data'.") if not os.path.isdir(self.data_path.get()): raise ValueError("The data path does not exist.") if not os.path.isdir(self.output_path.get()): raise ValueError("The output path does not exist.") if not self.MIN_ARCHIVE_SIZE < self.max_block_size.get( ) < self.MAX_ARCHIVE_SIZE: raise ValueError( "The archive size must be between 100MB and 2.5GB") if not self.output_name.get().strip(): raise ValueError("Invalid output name") if not [ x for x in self.subfolders_list_frame.subfolders if bool(x.var.get().strip()) ]: raise ValueError("No subfolders specified") for subfolder in self.subfolders_list_frame.subfolders: path = subfolder.var.get() if not self.subfolders_list_frame.is_subfolder(path): raise ValueError( f"{path} is not a data subfolder or does not exist!")
class Hangman: """Hangman class, made in tkinter GUInterface""" def __init__(self, master=None): """Constructor""" # Screens init self.master = master self.screen() self.build_frame() self.build_grid() # All displayed labels self.banner_text = StringVar() self.banner_text.set('') self.banner_text.trace('w', self.build_title_label) self.counter = StringVar() self.counter.trace('w', self.build_countdown) self.clock_text = StringVar() self.clock_text.set('Clock') self.clock_text.trace('w', self.build_clock_label) self.word_text = StringVar() self.word_text.set('Choose your category') self.word_text.trace('w', self.build_word_label) self.secret_word = StringVar() self.prompt = StringVar() self.prompt.set('random') self.timer_text = StringVar() self.timer_text.set(strftime("%H:%M")) self.timer_text.trace('w', self.build_timer) self.time_left = IntVar() self.time_left.set(st.DEFAULT_GAP) self.time_left.trace('w', self.alert) self.score_text = IntVar() self.score_text.set('0\n0') self.score_text.trace('w', self.build_score_label) # Predefined variables self.sorted = '' self.char = '' self.level_status = 1 self.total = 0 self.abc = [] self.category = [] self.level = [] self.misses = [] self.guesses = [] self.s_w_list = [] self.first_last = [] self.a = {} self.running = False self.rem = self.master.winfo_screenwidth() self.w = self.master.winfo_screenwidth() / 5 self.h = self.master.winfo_screenheight() * 2 / 7 # Methods call in __init__() self.build_title_label() self.build_word_label() self.build_countdown() self.build_welcome_label() self.build_score_label() self.build_timer() self.build_clock_label() self.buttons() self.category_buttons() self.abc_buttons() # Update time self.update() def screen(self): """Main window Minimal size 1024 / 600 The window goes full screen if the width it's lower than 1440""" self.master.minsize(1024, 600) if self.master.winfo_screenwidth() <= 1440: # and self.master.winfo_screenheight() <= 720: self.master.overrideredirect(True) self.master.geometry('{0}x{1}+0+0'.format( self.master.winfo_screenwidth(), self.master.winfo_screenheight())) # elif 1024 < self.master.winfo_screenwidth() < 1920 \ # and 720 < self.master.winfo_screenheight() < 1080: # a = int(float(70) * float(self.master.winfo_screenwidth()) / 100) # b = int(float(70) * float(self.master.winfo_screenheight()) / 100) # self.master.overrideredirect(True) # self.master.geometry('{}x{}+{}+{}'.format( # a, b, (self.master.winfo_screenwidth() // 2 - a // 2), # (self.master.winfo_screenheight() // 2 - b // 2))) else: self.master.overrideredirect(True) x = int(float(65) * float(self.master.winfo_screenwidth()) / 100) y = int(float(75) * float(self.master.winfo_screenheight()) / 100) self.master.maxsize(x, y) self.master.geometry('{}x{}+{}+{}'.format( x, y, (self.master.winfo_screenwidth() // 2 - x // 2), (self.master.winfo_screenheight() // 2 - y // 2))) self.master.update_idletasks() def mini_screen(self): """Secondary window for result information""" # noinspection PyAttributeOutsideInit self.master_2 = Tk() # noinspection PyAttributeOutsideInit frame = Frame(self.master_2, bg=st.color['fg'], highlightbackground=st.color['fg_enter'], highlightcolor=st.color['fg_enter'], highlightthickness=3) if self.rem < 1440: x, y = 400, 500 else: x, y = 700, 700 self.master_2.geometry('{}x{}+{}+{}'.format( x, y, int(self.master.winfo_screenwidth() // 2 - x / 2), int(self.master.winfo_screenheight() // 2 - y / 2))) self.master_2.overrideredirect(True) self.master_2.update_idletasks() frame.pack(fill=BOTH, expand=True) niv = None if self.level_status == 1: niv = st.L_EN[2] if self.level_status == 2: niv = st.L_EN[1] if self.level_status == 3: niv = st.L_EN[0] text = st.P_EN['won'].format(niv.capitalize(), self.secret_word.get(), self.total, '') fg = 'green' bg = st.color['fg'] if len(self.misses) == 7 or not self.time_left.get(): text = st.P_EN['lose'] fg = 'red' # noinspection PyAttributeOutsideInit label = Label(frame, text=text, bg=bg, fg=fg, justify=LEFT, font=st.font(self.rem, 5)) ok = Button(frame, bg=st.color['fg'], bd=0, fg=st.color['fg_enter'], font=st.font(self.rem, 3), text='Ok', command=lambda: self.master_2.destroy(), activeforeground='black', activebackground=st.color['fg'], width=2) label.pack(fill=BOTH, expand=True) ok.place(relx=0.5, rely=0.96, anchor='s') def score_screen(self): """Score screen""" # noinspection PyAttributeOutsideInit self.master_3 = Tk() # noinspection PyAttributeOutsideInit self.frame = Frame(self.master_3, bg=st.color['fg'], highlightbackground=st.color['fg_enter'], highlightcolor=st.color['fg_enter'], highlightthickness=3) if self.rem < 1440: x, y = 450, 500 else: x, y = 600, 700 self.master_3.geometry('{}x{}+{}+{}'.format( x, y, int(self.master.winfo_screenwidth() // 2 - x / 2), int(self.master.winfo_screenheight() // 2 - y / 2))) self.master_3.overrideredirect(True) self.master_3.update_idletasks() self.frame.pack(fill=BOTH, expand=True) text = 'Level \t Points\t\tTime\n' + 37 * '_' + '\n' for item in rc.search(): text += '{}\t {} {}\n'.format( item.level, item.points, item.timestamp.strftime(' %B %d, %Y %I:%M %p')) label = Label(self.frame, text=text, bg=st.color['bg'], fg=st.color['fg'], justify=LEFT, font=st.font(self.rem, 0)) ok = Button(self.frame, bg=st.color['bg'], bd=0, fg=st.color['fg_enter'], font=st.font(self.rem, 3), text='Ok', command=lambda: self.master_3.destroy(), activeforeground='black', activebackground=st.color['fg'], width=2) label.pack(fill=BOTH, expand=True) ok.place(relx=0.5, rely=0.96, anchor='s') def create_frame(self, frame, code): """Creates frames for the main window""" wa, wb, ha, hb = None, None, None, None if code is 'm': wa, wb, ha, hb = 1, 1, 1, 1 elif code is 'r2': wa, wb, ha, hb = 1, 1, 3, 5 elif code in ['r0', 'r1', 'r3']: wa, wb, ha, hb = 1, 1, 1, 5 return Frame(frame, bg=st.color['bg'], width=self.master.winfo_width() * wa // wb, height=self.master.winfo_height() * ha // hb) def create_button(self, frame, text): """General buttons creator""" font = None command = self.set_command(text) state = None bg, fg, abg, afg, dfg = st.set_buttons_color(text) button = Button(frame, text=text.capitalize(), bg=bg, fg=fg, font=font, bd=0, command=command, justify='center', overrelief=SUNKEN, anchor=CENTER, state=state, disabledforeground=dfg, activeforeground=afg, activebackground=abg, image=None) return button def build_frame(self): """All the frames for the main window""" # noinspection PyAttributeOutsideInit self.welcome = self.create_frame(self.master, 'm') self.welcome.config(highlightbackground=st.color['fg'], highlightcolor=st.color['fg'], highlightthickness=2) self.welcome.pack(fill=BOTH, expand=True) # noinspection PyAttributeOutsideInit self.mainframe = self.create_frame(self.master, 'm') self.mainframe.config(highlightbackground='black', highlightcolor='black', highlightthickness=2) self.mainframe.pack(fill=BOTH, expand=True) self.mainframe.pack_forget() # Row 0 # noinspection PyAttributeOutsideInit self.row_0_grid = self.create_frame(self.mainframe, 'r0') self.row_0_grid.grid(row=0, column=0, sticky='news', pady=10) # Row 0 Column 1 # noinspection PyAttributeOutsideInit self.row_0_column_1 = Frame(self.row_0_grid, bg=st.color['bg']) self.row_0_column_1.config(highlightbackground=st.color['fg'], highlightcolor=st.color['bg_start'], highlightthickness=2) self.row_0_column_1.grid(row=0, column=1, rowspan=2, sticky='news', pady=7) # Row 0 Column 2 # noinspection PyAttributeOutsideInit self.row_0_column_2 = Frame(self.row_0_grid, bg=st.color['bg']) self.row_0_column_2.config(highlightbackground=st.color['fg'], highlightcolor=st.color['bg_start'], highlightthickness=2) self.row_0_column_2.grid(row=0, column=2, rowspan=2, sticky='news', padx=20, pady=6) # Row 0 Column 3 # noinspection PyAttributeOutsideInit self.row_0_column_3 = Frame(self.row_0_grid, bg=st.color['bg']) self.row_0_column_3.grid(row=0, column=3, rowspan=2, columnspan=2, sticky='news', padx=3, pady=4) # Row 1 # noinspection PyAttributeOutsideInit self.row_1_grid = self.create_frame(self.mainframe, 'r1') self.row_1_grid.grid(row=1, column=0, sticky='news', padx=13) # Row 2 # noinspection PyAttributeOutsideInit self.row_2_grid = self.create_frame(self.mainframe, 'r2') self.row_2_grid.grid(row=2, column=0, sticky='news') # Row 3 # noinspection PyAttributeOutsideInit self.row_3_grid = self.create_frame(self.mainframe, 'r3') self.row_3_grid.grid(row=3, column=0, sticky='news', padx=5, pady=5) def build_grid(self): """Grid layout for all the frames""" u, u2 = None, None # Main Frame self.mainframe.columnconfigure(0, weight=1, uniform=u) for m in range(0, 4): self.mainframe.rowconfigure(m, weight=1, uniform=u2) # Row 0 for y in range(15): self.row_0_grid.columnconfigure(y, weight=1, uniform=u) self.row_0_grid.rowconfigure(0, weight=1, uniform=u2) self.row_0_grid.rowconfigure(1, weight=1, uniform=u2) # Row 0 Column 1 self.row_0_column_1.columnconfigure(0, weight=1, uniform=u) for c in range(6): self.row_0_column_1.rowconfigure(c, weight=1, uniform=u2) # Row 0 Column 2 self.row_0_column_2.columnconfigure(0, weight=1, uniform=u) for c2 in range(3): self.row_0_column_2.rowconfigure(c2, weight=1, uniform=u2) # Row 0 Column 3 self.row_0_column_3.columnconfigure(0, weight=1, uniform=u) for c3 in range(3): self.row_0_column_3.rowconfigure(c3, weight=1, uniform=u2) # Row 1 for x in range(13): self.row_1_grid.columnconfigure(x, weight=1, uniform=u) self.row_1_grid.rowconfigure(0, weight=1, uniform=u2) self.row_1_grid.rowconfigure(1, weight=1, uniform=u2) # Row 2 self.row_2_grid.columnconfigure(0, weight=1, uniform=u) self.row_2_grid.columnconfigure(1, weight=1, uniform=u) self.row_2_grid.rowconfigure(0, weight=1, uniform=u2) # Row 3 for n in range(0, 4): self.row_3_grid.columnconfigure(n, weight=1, uniform=u) self.row_3_grid.rowconfigure(0, weight=1, uniform=u2) self.row_3_grid.rowconfigure(1, weight=1, uniform=u2) # noinspection PyUnusedLocal def build_score_label(self, *args): """Word categories label""" bg, fg = st.set_buttons_color('points', 1) points = Label(self.row_0_column_1, text='Points:', bg=bg, fg=fg, font=st.font(self.rem, -4, style='normal'), bd=0, width=2) points.grid(row=0, column=0, sticky='news', padx=0, pady=0) b, f = st.set_buttons_color('score', 1) score = Label(self.row_0_column_1, textvariable=self.score_text, bg=b, fg=f, font=st.font(self.rem, 0), justify=CENTER, bd=0, width=2) score.grid(row=1, column=0, sticky='news', padx=0, pady=0) # noinspection PyUnusedLocal def build_welcome_label(self, *args): """Word categories label""" bg, fg = st.set_buttons_color('title', 1) title = Label(self.welcome, text='Guess Letters', bg=bg, fg=fg, font=st.font(self.rem, 24), justify=CENTER) title.pack(side=TOP, padx=20, pady=50) # noinspection PyUnusedLocal def build_title_label(self, *args): """Word categories label""" bg, fg = st.set_buttons_color('title', 1) title = Label(self.row_0_grid, text=self.banner_text.get(), bg=bg, fg=fg, font=st.font(self.rem, 10), width=6) title.grid(row=0, column=5, rowspan=2, columnspan=10, sticky='ew', padx=5, pady=2) # noinspection PyUnusedLocal def build_countdown(self, *args): """Countdown label""" em = self.master.winfo_width() // 50 # noinspection PyAttributeOutsideInit self.count = Label( self.row_2_grid, textvariable=self.counter, bg=st.color['bg'], fg=st.color['7'], font=('Times new Roman', int(4.5 * em), 'bold'), ) self.count.grid(row=0, column=0, sticky='nws', padx=2 * em, pady=5) # noinspection PyUnusedLocal def build_clock_label(self, *args): """Main clock label""" bg, fg = st.set_buttons_color('points', 1) # noinspection PyAttributeOutsideInit self.clock = Label(self.row_0_column_2, textvariable=self.clock_text, bg=bg, fg=fg, font=st.font(self.rem, 0), bd=0, width=2) self.clock.grid(row=0, column=0, sticky='news', padx=0, pady=0) # noinspection PyUnusedLocal def build_timer(self, *args): """Timer label""" b, f = st.set_buttons_color('timer', 1) # noinspection PyAttributeOutsideInit self.timer = Label(self.row_0_column_2, text=self.timer_text.get(), bg=b, fg=f, font=st.font(self.rem, 14)) self.timer.grid(row=1, column=0, rowspan=2, sticky='nsew') # noinspection PyUnusedLocal def build_word_label(self, *args): """Secret word label""" bg, fg = st.set_buttons_color('word', 1) # noinspection PyAttributeOutsideInit self.secret_word_label = Label(self.row_2_grid, textvariable=self.word_text, bg=bg, fg=fg, justify=RIGHT, font=st.font(self.rem, 16), anchor='e') self.secret_word_label.grid(row=0, column=1, sticky='nse', padx=20, pady=5) # noinspection PyUnusedLocal def alert(self, *args): """Timer alert for the hard level""" if not self.time_left.get(): self.mini_screen() self.word_text.set('Choose your category') self.counter.set('') self.start_stop_action('stop') self.banner_text.set('Random') self.quit.config(state=NORMAL) self.back.config(state=NORMAL) self.timer_text.set(strftime("%H:%M")) def draw_word(self): """Drawing loop for the secret word label""" output = [] index = 1 # Draws the displayed word after each letter choice for x in self.secret_word.get(): if self.level_status == 1: if x in self.first_last \ or x in self.guesses \ or x in [' ', '-']: output.append(x) elif x == self.char: output.append(self.char) else: output.append('_') index += 1 elif self.level_status >= 2: if x in self.guesses or x in [' ', '-']: output.append(x) elif x == self.char: output.append(self.char) else: output.append('_') # Finally sets the label for display self.word_text.set(' '.join(output)) def scoring(self): """Scoring method for each level""" new = self.char total = 'Total' xp = 7 - len(self.misses) n = 0 t = 0 # Scoring points are defined by the input letter # if vowels score are lower in each difficulty level # if console, score are higher in each difficulty level if self.char in self.secret_word.get() and self.char in 'AEIOU': if self.level_status == 1: n = 4 * xp if self.level_status == 2: n = 5 * xp if self.level_status == 3: n = 7 * xp elif self.char in self.secret_word.get() and self.char not in 'AEIOU': if self.level_status == 1: n = 5 * xp if self.level_status == 2: n = 6 * xp if self.level_status == 3: n = 8 * xp self.total += n # Finally sets up the scoring window self.score_text.set(f'{new}' + (len(total) + 4 + len(str(t)) - 1) * ' ' + f'{n}\n' f'{total}' + 6 * ' ' + f'{self.total}') def game_status(self): """Checks if it's a win or a loss Also changes the countdown label foreground color depending to the misses""" if len(self.misses) == 7: self.mini_screen() self.word_text.set('Choose your category') self.counter.set('') self.start_stop_action('stop') self.banner_text.set('Random') self.quit.config(state=NORMAL) self.back.config(state=NORMAL) self.timer_text.set(strftime("%H:%M")) if sorted(self.guesses) == sorted(self.sorted): # Add a score entry to database if entries are less than 13 if len(rc.search()) < 13: rc.add_entry(self.level_status, self.total) # Checks if last score in database is less than new score # if is than delete the last entry and the new higher score elif len(rc.search()) == 13 \ and rc.search()[12].points < self.total: rc.delete() rc.add_entry(self.level_status, self.total) self.mini_screen() self.word_text.set('Choose your category') self.counter.set('') self.start_stop_action('stop') self.banner_text.set('Random') self.quit.config(state=NORMAL) self.back.config(state=NORMAL) self.s_w_list.append(self.secret_word.get()) self.timer_text.set(strftime("%H:%M")) def abc_buttons(self): """Creates the alphabet buttons""" # noinspection PyAttributeOutsideInit r, c = 0, 0 for item in st.ALPHABET: b = Button( self.row_1_grid, text='%s' % item, bg=st.color['bg'], fg=st.color['fg_abc'], font=st.font(self.rem, 1), command=lambda i=item: self.set_abc(i), justify='center', overrelief=SUNKEN, anchor=CENTER, bd=0, state=DISABLED, disabledforeground=st.color['dfg_abc'], activeforeground=st.color['afg_abc'], activebackground=st.color['abg_abc'], ) if c == 13: r += 1 c = 0 b.grid(row=r, column=c, sticky='news', padx=7, pady=6) self.abc.append(b) c += 1 def category_buttons(self): """Word category buttons""" r, c, bg, s = 0, 0, st.color['bg_cat_a'], NORMAL for item in st.EN: if item == 'random': bg = st.color['fg'] s = DISABLED b = Button(self.row_3_grid, text='%s' % item.capitalize(), bg=bg, fg=st.color['fg_cat'], font=st.font(self.rem, 8), command=lambda i=item: self.set_category(i), overrelief=SUNKEN, anchor=CENTER, bd=0, state=s, disabledforeground=st.color['bg'], activeforeground=st.color['fg_cat'], activebackground=st.color['bg_cat_a'], width=1) if c == 4: r += 1 c = 0 b.grid(row=r, column=c, sticky='news', padx=15, pady=10) self.category.append(b) c += 1 def buttons(self): """Info, check buttons""" close = st.image('quit') info = st.image('info') rule = st.image('rule') # noinspection PyAttributeOutsideInit self.start = self.create_button(self.row_0_grid, 'start') self.start.config(width=2, font=st.font(self.rem, -2)) self.start.grid(row=0, column=0, sticky='news', padx=20, pady=7) # noinspection PyAttributeOutsideInit self.stop = self.create_button(self.row_0_grid, 'stop') self.stop.config(state=DISABLED, width=2, font=st.font(self.rem, -2)) self.stop.grid(row=1, column=0, sticky='news', padx=20, pady=7) # noinspection PyAttributeOutsideInit self.quit = self.create_button(self.master, 'exit') self.quit.config(font=st.font(self.rem, 1), image=close) self.quit.image = close self.quit.place(relx=0.99, rely=0.01, anchor='ne') # noinspection PyAttributeOutsideInit self.score = self.create_button(self.row_0_column_1, 'high score') self.score.config(font=st.font(self.rem, -2, style='normal'), overrelief=None, relief=SOLID, bd=0, command=lambda: self.score_screen()) self.score.grid(row=5, column=0, sticky='news') # noinspection PyAttributeOutsideInit self.info = self.create_button(self.welcome, 'info') self.info.config( font=st.font(self.rem, 0), command=lambda: st.set_rules('Game Info', st.prompt['Game Info']), image=info) self.info.image = info self.info.place(relx=0.01, rely=0.01, anchor='nw') # noinspection PyAttributeOutsideInit self.rule = self.create_button(self.welcome, 'rules') self.rule.config(font=st.font(self.rem, 0), command=lambda: st.set_rules('Game Rules', st.prompt[ 'Game Rules']), image=rule) self.rule.image = rule self.rule.place(relx=0.01, rely=0.1, anchor='nw') # noinspection PyAttributeOutsideInit self.go = self.create_button(self.welcome, 'ENTER') self.go.config(font=st.font(self.rem, 16, family='Verdana'), text='ENTER') self.go.pack(side=BOTTOM, expand=False, padx=5, pady=60) back = st.image('back') # noinspection PyAttributeOutsideInit self.back = self.create_button(self.row_0_grid, 'Back') self.back.config(font=st.font(self.rem, 1), image=back) self.back.image = back self.back.place(relx=0.99, rely=0.42, x=0, y=0, anchor='se') r, s, bg = 0, NORMAL, st.color['bg_level'] for item in st.L_EN: b = self.create_button(self.row_0_column_3, item) if item == 'easy': s = DISABLED bg = st.color['fg'] b.config(state=s, font=st.font(self.rem, -4, style='bold'), command=lambda i=item: self.set_level(i), bg=bg) b.grid(row=r, column=0, sticky='news', pady=3) self.level.append(b) r += 1 def destroy_all(self): """Close all windows""" st.set_rules('Bye', st.prompt['Bye']) sleep(0.6) # noinspection PyBroadException try: self.master.destroy() # self.master_2.destroy() except NotImplementedError: pass def set_abc(self, item): """Sets the alphabet buttons to the desired state depending to guesses and misses. calls the draw_word and game_status methods """ self.char = item self.scoring() bg, dfg, s = st.color['bg'], st.color['dfg_abc_b'], DISABLED if item in self.secret_word.get(): bg, dfg, s = st.color['bg'], st.color['dfg_abc_g'], \ DISABLED self.guesses.append(item) else: self.misses.append(item) index = 0 for x in st.ALPHABET: self.a.update({x: index}) index += 1 self.abc[self.a[item]].config(state=s, bg=bg, disabledforeground=dfg) c = 7 - len(self.misses) if c == 0: c = 7 self.counter.set(f'{c}') self.count.config(fg=st.color[f'{c}']) self.draw_word() self.game_status() def set_welcome(self): self.welcome.pack_forget() sleep(0.6) self.mainframe.pack(fill=BOTH, expand=True) def set_back(self): self.mainframe.pack_forget() sleep(0.4) self.welcome.pack(fill=BOTH, expand=True) # noinspection PyBroadException # try: # self.master_2.destroy() # except NotImplementedError: # pass self.level[0].config(state=NORMAL) self.level[1].config(state=NORMAL) self.level[2].config(state=DISABLED) self.first_last.clear() def set_secret_word(self): """Sets the secret word by the user choice""" self.guesses.clear() self.misses.clear() self.char = '' search = self.prompt.get() lang = st.C_EN if search.lower() == 'random': from random import choice search_query = choice(lang) else: search_query = search.lower() # Opens available words from csv file try: word = st.open_csv(search_query, self.level_status).upper() if word in self.s_w_list: word = st.open_csv(search_query, self.level_status).upper() self.secret_word.set(word) for x in word: if x == word[0] or x == word[len(word) - 1]: if x.upper() in self.first_last: continue self.first_last.append(x.upper()) if self.level_status == 1: self.sorted = st.sort(word) else: self.sorted = st.sort(word, True) self.draw_word() self.banner_text.set(search_query.capitalize()) except NotImplementedError: pass def set_command(self, text): """Sets command for buttons""" command = None if text == 'start': command = self.set_start_button elif text == 'stop': command = self.set_stop_button elif text == 'exit': command = self.destroy_all elif text == 'ENTER': command = self.set_welcome # elif text == 'english': # command = self.set_language elif text == 'Back': command = self.set_back return command # def set_language(self): # """Method for change the categories between english and french""" # if self.choose.cget('text').lower() == 'english': # self.choose.config(text='Francais') # self.lang = 'ENG' # elif self.choose.cget('text').lower() == 'francais': # self.choose.config(text='English') # self.lang = 'FRA' def start_stop_action(self, text): """Start and stop buttons common actions""" bc, ba, bb, dfg, s, s_2, s_3 = None, None, None, None, None, None, None sbg, stbg = None, None if text == 'start': if self.level_status == 3: self.clock_text.set('Timer') for x in range(3): if self.level[x].cget('state') == 'disabled': continue else: self.level[x].grid_forget() bc = st.color['fg'] ba = st.color['fg'] bb = st.color['bg_abc_a'] dfg = st.color['bg'] s = DISABLED s_2 = NORMAL s_3 = NORMAL sbg = st.color['fg'] stbg = st.color['bg_stop'] if text == 'stop': self.first_last.clear() self.sorted = '' self.banner_text.set('') self.clock_text.set('Clock') self.running = False # self.choose.place(relx=0.67, rely=0.23, x=0, y=0, anchor='se') r = 0 for x in range(3): self.level[x].grid(row=r, column=0, sticky='news', pady=3) r += 1 bc = st.color['bg_cat_a'] ba = st.color['fg'] bb = st.color['bg'] dfg = st.color['fg'] s = NORMAL s_2 = DISABLED s_3 = DISABLED sbg = st.color['bg_start'] stbg = st.color['fg'] self.start.config(state=s, bg=sbg) self.stop.config(state=s_2, bg=stbg) self.total = 0 self.score_text.set('0\n0') for a in range(8): if self.category[a].cget('text').lower() == self.prompt.get(): self.category[a].config(state=DISABLED, bg=ba) else: self.category[a].config(state=s, bg=bc) for i in range(0, 26): if self.level_status == 1: if self.abc[i].cget('text') in self.first_last: self.abc[i].config( bg=st.color['bg'], state=DISABLED, disabledforeground=st.color['dfg_abc_g']) else: self.abc[i].config(bg=bb, disabledforeground=dfg, state=s_3) else: self.abc[i].config(bg=bb, disabledforeground=dfg, state=s_3) def set_start_button(self): """Sets start button action""" print("This is working") self.time_left.set(st.DEFAULT_GAP) self.running = True self.counter.set('7') self.set_secret_word() self.quit.config(state=DISABLED) self.back.config(state=DISABLED) self.start_stop_action('start') # self.choose.place_forget() # noinspection PyBroadException # try: # if self.master_2: # self.master_2.destroy() # except NotImplementedError: # pass def set_stop_button(self): """Sets stop button action""" self.word_text.set('Choose your category') self.counter.set('') self.quit.config(state=NORMAL) self.back.config(state=NORMAL) self.start_stop_action('stop') self.timer_text.set(strftime("%H:%M")) def set_category(self, text): """Category buttons function""" self.prompt.set(text) for a in range(8): if self.category[a].cget('text').lower() == text: self.category[a].config(state=DISABLED, bg=st.color['fg']) else: self.category[a].config(state=NORMAL, bg=st.color['bg_cat_a']) def set_level(self, text): """Method for difficulty level""" if text == 'hard': self.level_status = 3 if text == 'medium': self.level_status = 2 if text == 'easy': self.level_status = 1 for x in range(3): if self.level[x].cget('text').lower() == text: self.level[x].config(state=DISABLED, bg=st.color['fg']) else: self.level[x].config(state=NORMAL, bg=st.color['bg_level']) def update(self): """Master window refresh rate, 1 second""" time_left = self.time_left.get() if self.running and time_left and self.level_status == 3: minutes, seconds = st.minutes_seconds(time_left) self.timer_text.set('{:0>2}:{:0>2}'.format(minutes, seconds)) self.time_left.set(time_left - 1) self.master.after(1000, self.update)
class KarelWindow(Frame): def geometry(self, height): # print "gemo " + str(self._oldHeight) + ' ' + str(height) self._oldHeight = self._height self._height = height self.__bottom = height - self._inset self.__left = self._inset self.__top = self._inset self.__right = height # self.__scaleFactor = ((self.__bottom - self.__top)*1.0/self.__streets) def __init__(self, streets, avenues, size=800, callback=None): # avenues is ignored in this version # self.__configControl = threading.Condition() self.__root = root = Tk( className=" Karel's World ") # , geometry='800x600+60+10' global _windowBottom _windowBottom = size geometryString = '820x' + str(_windowBottom + 65) + "+55+25" root.geometry(newGeometry=geometryString ) #'820x865+55+25') # placement of window on desktop # print str(root.tk_menuBar()) Frame.__init__(self, master=root, cnf={}) bar = Menu() def endProgram(menu): exit() fil = Menu() fil.add_command(label='Quit ^Q', command=lambda x='Quit': endProgram(x)) bar.add_cascade(label='File', menu=fil) root.config(menu=bar) self.bind_all('<Command-q>', exit) # Mac standard self.bind_all('<Control-q>', exit) # Windows self.__streets = streets self.__avenues = streets # sic Avenues ignored self.__gBeepers = {} #locations of the beeper imagess self.__contents = [] # , walls, beepers that need to move on a rescale self.__robots = [] self.__beeperControl = threading.Condition( ) # helps multi threaded programs avoid anomalies self.__walls = [ ] # all the basic visual elements (boundary, streets, street labels, etc. top = self.winfo_toplevel() top.rowconfigure(2, weight=1) top.columnconfigure(0, weight=1) self.rowconfigure(2, weight=1) self.columnconfigure(0, weight=1) root.rowconfigure(2, weight=1) root.columnconfigure(0, weight=1) speedLabel = Label(text="Speed") speedLabel.grid(row=0, column=0, sticky=N + W + E + S) if callback != None: # this makes the speed slider work. from tkinter import IntVar self.iv = IntVar() self.iv.trace('r', callback) self.scale = Scale(orient=HORIZONTAL, variable=self.iv) self.scale.set(20) self.scale.grid(row=1, column=0, sticky=N + S) # self.__callback = callback # global _windowRight global _inset # root.minsize(_windowBottom, _windowRight) self._height = self._oldHeight = _windowBottom self.__bottom = _windowBottom - _inset #770 self.__left = _inset #30 self.__top = _inset #30 self.__right = self._height #_windowRight - _inset #770 self._inset = _inset # print str(speedLabel.config()) # print str(self.scale.config()) self._canvas = Canvas(root, height=_windowBottom, width=_windowBottom, bg='white') self._canvas.grid(row=2, column=0, sticky=N + E + W + S) self.geometry(self._height) self.setSize(streets) # self._canvas.bind_all('<Expose>', self.expose) # self._canvas.bind('<Configure>', self.configure) # def expose(self, event): ## print 'expose ' + str(event.width)+ ' ' + str(event.height) # pass # def configure(self, event): ## print str(self._canvas.config()) ## print "config " + str(event.height) ## self.__configControl.acquire() # self.geometry(event.height) # delta = (self._oldHeight - self._height)*1.0/self._oldHeight # scale = self._height*1.0/self._oldHeight # self._canvas.scale('all', 0, 0, scale, scale) # self._canvas.move('all', delta, delta) ## print "config " + str(event.widget)+ ' ' +str(event.x)+ ' ' + str(event.y)+' ' + str(event.width)+ ' ' + str(event.height) ## self.__configControl.notify() ## self.__configControl.release() # pass def clear(self): for item in self.__contents + self.__robots: item.deleteAll() def setSize(self, streets): #streets can change self.__streets = streets for x in self.__walls: # boundary walls and street lines self._canvas.delete(x) self.makeStreetsAndAvenues() self.makeBoundaryWalls() self.labelStreetsAvenues() for item in self.__contents + self.__robots: #rebuild the contents of the world item.moveScale() def scaleFactor(self): self.geometry(self._height) # print "in scaler " + str(self.__bottom) + " " + str(self.__top) + ' ' + str(self.__streets) return ((self.__bottom - self.__top) * 1.0 / self.__streets ) #self.__scaleFactor class Beeper: bNumber = 0 def __init__(self, street, avenue, number, window): self._street = street self._avenue = avenue self._number = number self._scaler = window._scaleToPixels self.scaleFactor = window.scaleFactor self._canvas = window._canvas self.tag = "b" + str(KarelWindow.Beeper.bNumber) KarelWindow.Beeper.bNumber += 1 def place(self): sizeFactor = .5 #Change this to change beeper size. The others scale from it. placeFactor = .5 * sizeFactor val = str(self._number) if self._number < 0: val = "oo" (x, y) = self._scaler(self._street + placeFactor, self._avenue - placeFactor) # print 'beeper ' + str(x) + ' ' + str(y) # print 'factor ' + str(self.scaleFactor()) # # circular beepers # self._canvas.create_oval(x, y, x + self.__scaleFactor*sizeFactor, y + self.__scaleFactor*sizeFactor, fill= 'black', tags = self.tag) # triangular beepers where = [] where.append(self._scaler(self._street + sizeFactor, self._avenue)) where.append( self._scaler(self._street - placeFactor, self._avenue - placeFactor)) where.append( self._scaler(self._street - placeFactor, self._avenue + placeFactor)) self._canvas.create_polygon(where, fill="black", smooth=False, tags=self.tag) self._canvas.create_text(x + self.scaleFactor() * placeFactor, y + self.scaleFactor() * placeFactor, text=val, font=Font(size=int(-self.scaleFactor() * placeFactor)), fill='white', tags=self.tag) def deleteAll(self): self._canvas.delete(self.tag) def moveScale(self): self._canvas.delete(self.tag) self.place() class Wall: def __init__(self, street, avenue, isVertical, window): self._street = street self._avenue = avenue self._isVertical = isVertical self.scaleFactor = window.scaleFactor self._scaler = window._scaleToPixels self._canvas = window._canvas if self._isVertical: (x, y) = self._scaler(street - .5, avenue + .5) self._code = self._canvas.create_line(x, y, x, y - self.scaleFactor(), width=2) else: (x, y) = self._scaler(street + .5, avenue - .5) self._code = self._canvas.create_line(x, y, x + self.scaleFactor(), y, width=2) # _code identifies the wall segment image in the tk layer def moveScale(self): self._canvas.delete( self._code ) #erase the current figure in prep to draw a new one if self._isVertical: (x, y) = self._scaler(self._street - .5, self._avenue + .5) self._code = self._canvas.create_line(x, y, x, y - self.scaleFactor(), width=2) else: (x, y) = self._scaler(self._street + .5, self._avenue - .5) self._code = self._canvas.create_line(x, y, x + self.scaleFactor(), y, width=2) def deleteAll(self): self._canvas.delete(self._code) def placeBeeper(self, street, avenue, number): # self.__beeperControl.acquire() # sync was moved to tkworldadapter beeper = self.Beeper(street, avenue, number, self) beeper.place() self.__gBeepers[(street, avenue)] = beeper self.__contents.append(beeper) # self.__beeperControl.notify() # self.__beeperControl.release() # return beeper def deleteBeeper(self, beeperlocation): # self.__beeperControl.acquire() beeper = self.__gBeepers.get(beeperlocation, None) if beeper != None: beeper.deleteAll() self.__gBeepers.pop(beeperlocation) i = 0 for b in self.__contents: if b == beeper: break i += 1 self.__contents.pop(i) # self.__beeperControl.notify() # self.__beeperControl.release() def placeWallNorthOf(self, street, avenue): self.__contents.append(self.Wall(street, avenue, False, self)) def removeWallNorthOf(self, street, avenue): i = 0 for wall in self.__contents: if wall.__class__ is self.Wall and wall._street == street and wall._avenue == avenue and not wall._isVertical: wall.deleteAll() self.__contents.pop(i) # print 'h gone' break i += 1 def placeWallEastOf(self, street, avenue): self.__contents.append(self.Wall(street, avenue, True, self)) def removeWallEastOf(self, street, avenue): i = 0 for wall in self.__contents: if wall.__class__ is self.Wall and wall._street == street and wall._avenue == avenue and wall._isVertical: wall.deleteAll() self.__contents.pop(i) # print 'v gone' break i += 1 def makeBoundaryWalls(self): (x, y) = self._scaleToPixels(.5, .5) # hardcode ok. Half way between streets self.__walls.append(self._canvas.create_line( x, 0, x, y, width=2)) # should width depend on number of streets? global _inset self.__walls.append( self._canvas.create_line(x, y, self.__right + _inset, y, width=2)) def makeStreetsAndAvenues(self): for i in range(0, self.__streets): (x, y) = self._scaleToPixels(i + 1, .5) (tx, ty) = self._scaleToPixels(i + 1, self.__streets + .5) self.__walls.append( self._canvas.create_line(x, y, tx, ty, fill="red")) (x, y) = self._scaleToPixels(.5, i + 1) (tx, ty) = self._scaleToPixels(self.__streets + .5, i + 1) self.__walls.append( self._canvas.create_line(x, y, tx, ty, fill="red")) def labelStreetsAvenues(self): for i in range(self.__streets): (x, y) = self._scaleToPixels(i + 1, .25) self.__walls.append( self._canvas.create_text(x, y, fill='black', text=str(i + 1))) (x, y) = self._scaleToPixels(.25, i + 1) self.__walls.append( self._canvas.create_text(x, y, fill='black', text=str(i + 1))) def addRobot(self, street, avenue, direction, fill, outline): # fill and outline are colors, default to blue, black robot = RobotImage(street, avenue, direction, self, fill, outline) self.__robots.append(robot) return robot # the world matches these with the actual robot objects in the model. def moveRobot(self, robot, amount=-1): #If no amount is specified then it moves one block, Otherwise amount pixels, not blocks if amount < 0: amount = self.scaleFactor() robot.move(amount) def _scaleToPixels(self, street, avenue): # origin is at corner (0,0) outside the world scale = self.scaleFactor() return (self.__left + avenue * scale, self.__bottom - street * scale) def _scaleFromPixels(self, x, y): scale = self.scaleFactor() return (int(round( (self.__bottom - y) / scale)), int(round( (x - self.__left) / scale))) def _downScaleFromPixels(self, x, y): scale = self.scaleFactor() return (int((self.__bottom - y) / scale), int( (x - self.__left) / scale)) def run(self, task, *pargs): # this is the actual graphic main. mainThread = threading.Thread(target=task, args=pargs) mainThread.start() self.mainloop() def _test(self): pass
class GraphyInspector: def __init__(self, parent): self.parent = parent self.width = self.parent.right_frame_width self.padding = self.parent.right_frame_padding self.frame = Frame(master=self.parent.right_frame) self.frame.pack(side='top', fill='y', ) # "Inspector" title bar self.title_frame = Frame(master=self.frame) self.title_frame.pack(side='top') self.title_label = Label(master=self.title_frame, text="Inspector", width=self.width, bg='lightgray') self.title_label.pack() # identifier for type of object selected self.type_frame = Frame(master=self.frame, relief='sunken') self.type_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.type_label1 = Label(master=self.type_frame, width=int(self.width/2)-self.padding, text='Object:') self.type_label1.pack(side='left', padx=self.padding, pady=self.padding) self.type_label2 = Label(master=self.type_frame, width=int(self.width / 2) - self.padding, text='', bg='white') self.type_label2.pack(side='right', padx=self.padding, pady=self.padding) # label of selected object (i.e. name user gives them, no canvas IDs here) self.label_frame = Frame(master=self.frame, relief='sunken') self.label_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_label = Label(master=self.label_frame, width=int(self.width/2)-self.padding, text="Label:") self.label_label.pack(side='left', padx=self.padding, pady=self.padding) self.label_var = StringVar() self.label_var.set('') self.label_entry = Entry(self.label_frame, width=int(self.width/2)-self.padding, textvariable=self.label_var) self.label_entry.pack(side='right', padx=self.padding, pady=self.padding) self.label_entry.bind('<Button-1>', self.select_label_text) self.label_entry.bind('<Return>', self.drop_widget_focus) # status identifier (for vertices and layers) self.status_frame = Frame(master=self.frame, relief='sunken') self.status_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.status_label1 = Label(master=self.status_frame, width=int(self.width/2)-self.padding, text='Status:') self.status_label1.pack(side='left', padx=self.padding, pady=self.padding) self.status_label2 = Label(master=self.status_frame, width=int(self.width/2)-self.padding, text='', bg='white') self.status_label2.pack(side='right', padx=self.padding, pady=self.padding) self.activation_var = StringVar() self.activation_var.set('') self.activation_menu = OptionMenu(self.status_frame, self.activation_var, "Identity", "Sigmoid", "ReLU", "Logarithmic", "Exponential") self.activation_menu.pack(side='right', padx=self.padding, pady=self.padding) # weight identifier (for edges only) self.weight_frame = Frame(master=self.frame, relief='sunken') self.weight_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.weight_label = Label(master=self.weight_frame, width=int(self.width/2)-self.padding, text="Weight:") self.weight_label.pack(side='left', padx=self.padding, pady=self.padding) self.weight_var = DoubleVar() self.weight_entry = Entry(self.weight_frame, width=int(self.width / 2) - self.padding, textvariable=self.weight_var) self.weight_entry.pack(side='right', padx=self.padding, pady=self.padding) self.weight_entry.bind('<Button-1>', self.select_weight_text) self.weight_entry.bind('<Return>', self.drop_widget_focus) # node count identifier (for layers only) self.node_frame = Frame(master=self.frame, relief='sunken') self.node_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.node_label = Label(master=self.node_frame, width=int(self.width/2)-self.padding, text="Node Count:") self.node_label.pack(side='left', padx=self.padding, pady=self.padding) self.node_var = IntVar() self.node_entry = Entry(self.node_frame, width=int(self.width / 2) - self.padding, textvariable=self.node_var) self.node_entry.pack(side='right', padx=self.padding, pady=self.padding) self.node_entry.bind('<Button-1>', self.select_node_text) self.node_entry.bind('<Return>', self.drop_widget_focus) # leakiness self.leakiness_frame = Frame(master=self.frame, relief='sunken') self.leakiness_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.leakiness_label = Label(master=self.leakiness_frame, width=int(self.width/2)-self.padding, text="Leakiness") self.leakiness_label.pack(side='left', padx=self.padding, pady=self.padding) self.leakiness_var = DoubleVar() self.leakiness_entry = Entry(self.leakiness_frame, width=int(self.width / 2) - self.padding, textvariable=self.leakiness_var) self.leakiness_entry.pack(side='right', padx=self.padding, pady=self.padding) self.leakiness_entry.bind('<Button-1>', self.select_leakiness_text) self.leakiness_entry.bind('<Return>', self.drop_widget_focus) # bias self.bias_frame = Frame(master=self.frame, relief='sunken') self.bias_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.bias_label = Label(master=self.bias_frame, width=int(self.width/2)-self.padding, text="Bias:") self.bias_label.pack(side='left', padx=self.padding, pady=self.padding) self.bias_var = DoubleVar() self.bias_entry = Entry(self.bias_frame, width=int(self.width / 2) - self.padding, textvariable=self.bias_var) self.bias_entry.pack(side='right', padx=self.padding, pady=self.padding) self.bias_entry.bind('<Button-1>', self.select_bias_text) self.bias_entry.bind('<Return>', self.drop_widget_focus) # output bound self.bound_frame = Frame(master=self.frame, relief='sunken') self.bound_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.bound_label = Label(master=self.bound_frame, width=int(self.width/2)-self.padding, text="Output Bound:") self.bound_label.pack(side='left', padx=self.padding, pady=self.padding) self.bound_var = DoubleVar() self.bound_entry = Entry(self.bound_frame, width=int(self.width / 2) - self.padding, textvariable=self.bound_var) self.bound_entry.pack(side='right', padx=self.padding, pady=self.padding) self.bound_entry.bind('<Button-1>', self.select_bound_text) self.bound_entry.bind('<Return>', self.drop_widget_focus) # noise self.noise_frame = Frame(master=self.frame, relief='sunken') self.noise_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.noise_label = Label(master=self.noise_frame, width=int(self.width/2)-self.padding, text="Weight Noise:") self.noise_label.pack(side='left', padx=self.padding, pady=self.padding) self.noise_var = DoubleVar() self.noise_entry = Entry(self.noise_frame, width=int(self.width / 2) - self.padding, textvariable=self.noise_var) self.noise_entry.pack(side='right', padx=self.padding, pady=self.padding) self.noise_entry.bind('<Button-1>', self.select_noise_text) self.noise_entry.bind('<Return>', self.drop_widget_focus) # input / output self.input_output_frame = Frame(master=self.frame, relief='sunken') self.input_output_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.input_var = BooleanVar() self.input_var.set(False) self.output_var = BooleanVar() self.output_var.set(False) self.input_toggle = Checkbutton(master=self.input_output_frame, text="Is Input", variable=self.input_var) self.output_toggle = Checkbutton(master=self.input_output_frame, text="Is Output", variable=self.output_var) self.input_toggle.pack(side='left', padx=self.padding, pady=self.padding) self.output_toggle.pack(side='left', padx=self.padding, pady=self.padding) self.selected = None self.selected_type = None self.set_unselected() self.label_var.trace('w', self.set_selected_label) self.weight_var.trace('w', self.set_selected_weight) self.activation_var.trace('w', self.set_selected_activation) self.leakiness_var.trace('w', self.set_selected_leakiness) self.node_var.trace('w', self.set_selected_node_count) self.bias_var.trace('w', self.set_selected_bias) self.bound_var.trace('w', self.set_selected_bound) self.noise_var.trace('w', self.set_selected_noise) self.input_var.trace('w', self.set_input) self.output_var.trace('w', self.set_output) # mode self.mode = parent.mode self.set_mode(parent.mode) # object is a vertex or edge, type is 'vertex' or 'edge'... def set_selected(self, selected_object, selected_object_type): self.selected = selected_object self.selected_type = selected_object_type if self.mode == "Graph": if selected_object_type == 'vertex': self.type_label2.config(text="Vertex") self.status_label2.config(text=selected_object.status) self.type_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.status_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_var.set(selected_object.label) elif selected_object_type == 'edge': self.type_label2.config(text="Edge") self.type_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.weight_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_var.set(selected_object.label) self.weight_var.set(selected_object.weight) else: print('dafuq is going on') elif self.mode == "Net": if selected_object_type == 'vertex': self.type_label2.config(text="Layer") self.status_label2.config(text=selected_object.status) self.type_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.status_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.node_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.leakiness_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.bias_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.bound_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.input_output_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_var.set(selected_object.label) self.node_var.set(selected_object.node_count) self.activation_var.set(selected_object.status) self.leakiness_var.set(selected_object.leakiness) self.bias_var.set(selected_object.bias) self.bound_var.set(selected_object.bound) self.input_var.set(selected_object.is_input_layer) self.output_var.set(selected_object.is_output_layer) elif selected_object_type == 'edge': self.type_label2.config(text="Weights") self.type_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.weight_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.noise_frame.pack(side='top', fill='x', pady=self.padding, padx=self.padding) self.label_var.set(selected_object.label) self.weight_var.set(selected_object.weight) self.noise_var.set(selected_object.noise) else: print('This will never happen.') # nothing is selected def set_unselected(self): self.type_frame.pack_forget() self.label_frame.pack_forget() self.status_frame.pack_forget() self.weight_frame.pack_forget() self.node_frame.pack_forget() self.bias_frame.pack_forget() self.bound_frame.pack_forget() self.noise_frame.pack_forget() self.input_output_frame.pack_forget() self.leakiness_frame.pack_forget() self.selected = None self.selected_type = None # set label of selected object def set_selected_label(self, *args): self.selected.set_label(self.label_var.get()) # set weight of selected object def set_selected_weight(self, *args): self.selected.set_weight(self.weight_var.get()) def set_selected_activation(self, *args): self.selected.set_status(self.activation_var.get()) def set_selected_node_count(self, *args): self.selected.set_node_count(self.node_var.get()) def set_selected_bias(self, *args): self.selected.set_bias(self.bias_var.get()) def set_selected_bound(self, *args): self.selected.set_bound(self.bound_var.get()) def set_selected_noise(self, *args): self.selected.set_noise(self.noise_var.get()) def set_input(self, *args): self.selected.set_input_layer(self.input_var.get()) def set_output(self, *args): self.selected.set_output_layer(self.output_var.get()) def set_selected_leakiness(self, *args): self.selected.set_leakiness(self.leakiness_var.get()) def update(self): if self.selected: selected = self.selected type = self.selected_type self.set_unselected() self.set_selected(selected, type) def select_label_text(self, event): if event: # delay so the default click doesn't undo selection, then recall and fall through to "else" self.parent.tk.after(50, self.select_label_text, False) else: self.label_entry.select_range(0, 'end') self.label_entry.icursor(0) def select_weight_text(self, event): if event: # delay so the default click doesn't undo selection, then recall and fall through to "else" self.parent.tk.after(50, self.select_weight_text, False) else: self.weight_entry.select_range(0, 'end') self.weight_entry.icursor(0) def select_node_text(self, event): if event: self.parent.tk.after(50, self.select_node_text, False) else: self.node_entry.select_range(0, 'end') self.node_entry.icursor(0) def select_bias_text(self, event): if event: self.parent.tk.after(50, self.select_bias_text, False) else: self.bias_entry.select_range(0, 'end') self.bias_entry.icursor(0) def select_noise_text(self, event): if event: self.parent.tk.after(50, self.select_noise_text, False) else: self.noise_entry.select_range(0, 'end') self.noise_entry.icursor(0) def select_bound_text(self, event): if event: self.parent.tk.after(50, self.select_bound_text, False) else: self.bound_entry.select_range(0, 'end') self.bound_entry.icursor(0) def select_leakiness_text(self, event): if event: self.parent.tk.after(50, self.select_leakiness_text, False) else: self.leakiness_entry.select_range(0, 'end') self.leakiness_entry.icursor(0) def drop_widget_focus(self, event): self.frame.focus() def set_mode(self, mode): if mode == "Graph": self.mode = mode self.weight_label.config(text="Weight:") self.status_label1.config(text="Status:") self.activation_menu.pack_forget() self.input_output_frame.pack_forget() self.status_label2.pack(side='right', padx=self.padding, pady=self.padding) elif mode == "Net": self.mode = mode self.weight_label.config(text="Start Weight:") self.status_label1.config(text="Activation:") self.status_label2.pack_forget() self.activation_menu.pack(side='right', padx=self.padding, pady=self.padding) else: print("This will never happen.")
activeforeground=BUTTON_ACTIVE_FOREGROUND, bg=BACKGROUND_COLOUR, fg=FOREGROUNG_COLOUR, font=TEXT_OPTIONS) btn_restore.place(x=610, y=10) btn_report = tk.Button(window, width=BUTTON_WIDTH, text='Отчет', command=lambda: report(df), activebackground=FOREGROUNG_COLOUR, activeforeground=BUTTON_ACTIVE_FOREGROUND, bg=BACKGROUND_COLOUR, fg=FOREGROUNG_COLOUR, font=TEXT_OPTIONS) btn_report.place(x=760, y=10) scrollbar_style = ttk.Style() scrollbar_style.configure("My.Horizontal.TScrollbar", troughcolor="red") tree = ttk.Treeview(window, show='headings') selected_database = IntVar(window) selected_database.set(OPTIONS[1]) options_menu = ttk.OptionMenu(window, selected_database, *OPTIONS) options_menu.place(x=910, y=15) selected_database.trace('w', update_table) update_table() window.mainloop()
class SettingsFrame(Frame): """ Frame inheritance class for application settings and controls. """ def __init__(self, app, *args, **kwargs): """ Constructor """ self.__app = app # Reference to main application class self.__master = self.__app.get_master() # Reference to root class (Tk) Frame.__init__(self, self.__master, *args, **kwargs) # Initialise up key variables self._image_num = 0 self._image_name = "image" self._settype = StringVar() self._zoom = DoubleVar() self._radius = DoubleVar() self._exponent = IntVar() self._zx_off = DoubleVar() self._zy_off = DoubleVar() self._cx_off = DoubleVar() self._cy_off = DoubleVar() self._maxiter = IntVar() self._zx_coord = DoubleVar() self._zy_coord = DoubleVar() self._theme = StringVar() self._shift = IntVar() self._themes = None self._filename = StringVar() self._filepath = None self._frames = IntVar() self._zoominc = DoubleVar() self._autoiter = IntVar() self._autosave = IntVar() self._validsettings = True self.body() def body(self): """ Set up frame and widgets. """ # Create settings panel widgets # pylint: disable=W0108 self.lbl_settype = Label(self, text=LBLMODE) self.spn_settype = Spinbox( self, values=("BurningShip", "Tricorn", "Julia", "Mandelbrot"), width=8, bg=GOOD, wrap=True, textvariable=self._settype, ) self.lbl_zoom = Label(self, text=LBLZOOM) self.ent_zoom = Entry( self, border=2, relief="sunken", width=12, bg=GOOD, justify=RIGHT, textvariable=self._zoom, ) self.lbl_zoominc = Label(self, text=LBLZOOMINC, justify=LEFT) self.ent_zoominc = Entry(self, width=5, border=2, bg=GOOD, justify=RIGHT, textvariable=self._zoominc) self.lbl_zx_off = Label(self, text=LBLZXOFF) self.ent_zx_off = Entry( self, border=2, relief="sunken", width=12, bg=GOOD, justify=RIGHT, textvariable=self._zx_off, ) self.lbl_zy_off = Label(self, text=LBLZYOFF) self.ent_zy_off = Entry( self, border=2, relief="sunken", width=12, bg=GOOD, justify=RIGHT, textvariable=self._zy_off, ) self.lbl_cx_off = Label(self, text=LBLCX) self.ent_cx_off = Entry( self, border=2, relief="sunken", width=12, bg=GOOD, justify=RIGHT, textvariable=self._cx_off, state=DISABLED, ) self.lbl_cy_off = Label(self, text=LBLCY) self.ent_cy_off = Entry( self, border=2, relief="sunken", width=12, bg=GOOD, justify=RIGHT, textvariable=self._cy_off, state=DISABLED, ) self.lbl_niter = Label(self, text=LBLITER, justify=LEFT) self.ent_maxiter = Entry( self, border=2, relief="sunken", bg=GOOD, width=8, justify=RIGHT, textvariable=self._maxiter, ) self.chk_autoiter = Checkbutton(self, text="Auto", variable=self._autoiter, onvalue=1, offvalue=0) self.lbl_theme = Label(self, text=LBLTHEME, justify=LEFT) self.lbl_radius = Label(self, text=LBLRAD, justify=LEFT) self.ent_radius = Entry( self, border=2, relief="sunken", bg=GOOD, width=8, justify=RIGHT, textvariable=self._radius, ) self.lbl_exp = Label(self, text=LBLEXP) self.spn_exp = Spinbox( self, border=2, relief="sunken", bg=GOOD, width=4, from_=2, to=20, wrap=True, textvariable=self._exponent, ) self.sep_1 = ttk.Separator( self, orient=HORIZONTAL, ) self.lbx_theme = Listbox( self, border=2, relief="sunken", bg=GOOD, width=6, height=5, justify=LEFT, exportselection=False, ) self.lbl_shift = Label(self, text=LBLSHIFT, justify=LEFT) self.scl_shift = Scale( self, from_=0, to=100, orient=HORIZONTAL, variable=self._shift, border=2, relief="sunken", sliderlength=20, troughcolor=GOOD, ) self.scrollbar = Scrollbar(self, orient=VERTICAL) self.lbx_theme.config(yscrollcommand=self.scrollbar.set) self.scrollbar.config(command=self.lbx_theme.yview) self.lbx_theme.select_set(0) self.lbx_theme.event_generate("<<ListboxSelect>>") self.lbl_coords = Label(self, text="Re, Im", fg="grey") self.btn_plot = Button( self, text=BTNPLOT, width=8, fg="green", command=lambda: self.__app.frm_fractal.plot(), ) self.btn_cancel = Button( self, text=BTNCAN, width=8, command=lambda: self.__app.frm_fractal.cancel_press(), ) self.btn_reset = Button(self, text=BTNRST, width=8, command=self.reset) self.ent_save = Entry( self, textvariable=self._filename, width=6, border=2, relief="sunken", bg=GOOD, justify=LEFT, ) self._filename.set(self._image_name + str(self._image_num)) self.btn_save = Button(self, text=BTNSAVE, width=8, command=self.save_image) self.lbl_auto = Label(self, text=LBLAUTO, justify=LEFT) self.btn_autozoom = Button( self, text=BTNZOOM, width=8, command=lambda: self.__app.frm_fractal.animate_zoom(), ) self.btn_autospin = Button( self, text=BTNSPIN, width=8, command=lambda: self.__app.frm_fractal.animate_spin(), state=DISABLED, ) self.chk_autosave = Checkbutton(self, text=BTNSAVE, variable=self._autosave, onvalue=1, offvalue=0) self.lbl_frames = Label(self, text=FRMSTXT) self.ent_frames = Entry(self, width=5, border=2, bg=GOOD, justify=RIGHT, textvariable=self._frames) # Get list of available themes for idx, theme in enumerate(THEMES): self.lbx_theme.insert(idx, theme) self.body_arrange() # Position all widgets in frame self.reset() # Reset all settings to their defaults self.set_traces( ) # Trace entry variables for validation and event handling def body_arrange(self): """ Position widgets in frame """ # Position all widgets in their parent frames self.btn_plot.grid(column=0, row=1, ipadx=3, ipady=3, sticky=(W), padx=3, pady=3) self.btn_cancel.grid(column=1, row=1, ipadx=3, ipady=3, sticky=(W), padx=3, pady=3) self.btn_reset.grid(column=2, row=1, ipadx=3, ipady=3, sticky=(W), padx=3, pady=3) self.ent_save.grid(column=0, row=2, columnspan=2, sticky=(W, E), padx=3, pady=3) self.btn_save.grid(column=2, row=2, ipadx=3, ipady=3, sticky=(W), padx=3, pady=3) self.lbl_auto.grid(column=0, row=3, sticky=(W)) self.btn_autozoom.grid(column=1, row=3, ipadx=3, ipady=3, sticky=(W), padx=3, pady=3) self.btn_autospin.grid(column=2, row=3, ipadx=3, ipady=3, sticky=(W), padx=3, pady=3) self.lbl_frames.grid(column=0, row=4, sticky=(W)) self.ent_frames.grid(column=1, row=4, sticky=(W), padx=3, pady=3) self.chk_autosave.grid(column=2, row=4, sticky=(W), padx=3, pady=3) self.sep_1.grid(column=0, row=5, columnspan=3, pady=5, sticky=(W, E)) self.lbl_settype.grid(column=0, row=6, sticky=(W)) self.spn_settype.grid(column=1, row=6, columnspan=2, sticky=(W, E), padx=3, pady=3) self.lbl_zoom.grid(column=0, row=7, sticky=(W)) self.ent_zoom.grid(column=1, row=7, columnspan=2, sticky=(W, E), padx=3, pady=3) self.lbl_zoominc.grid(column=0, row=8, sticky=(W)) self.ent_zoominc.grid(column=1, row=8, sticky=(W), padx=3, pady=3) self.lbl_zx_off.grid(column=0, row=9, sticky=(W)) self.ent_zx_off.grid(column=1, row=9, columnspan=2, sticky=(W, E), padx=3, pady=3) self.lbl_zy_off.grid(column=0, row=10, sticky=(W)) self.ent_zy_off.grid(column=1, row=10, columnspan=2, sticky=(W, E), padx=3, pady=3) self.lbl_cx_off.grid(column=0, row=11, sticky=(W)) self.ent_cx_off.grid(column=1, row=11, columnspan=2, sticky=(W, E), padx=3, pady=3) self.lbl_cy_off.grid(column=0, row=12, sticky=(W)) self.ent_cy_off.grid(column=1, row=12, columnspan=2, sticky=(W, E), padx=3, pady=3) self.lbl_niter.grid(column=0, row=13, sticky=(W)) self.ent_maxiter.grid(column=1, row=13, sticky=(W), padx=3, pady=3) self.chk_autoiter.grid(column=2, row=13, sticky=(W), padx=3, pady=3) self.lbl_radius.grid(column=0, row=14, sticky=(W)) self.ent_radius.grid(column=1, row=14, sticky=(W), padx=3, pady=3) self.lbl_exp.grid(column=0, row=15, sticky=(W)) self.spn_exp.grid(column=1, row=15, sticky=(W), padx=3, pady=3) self.lbl_theme.grid(column=0, row=16, sticky=(W)) self.lbx_theme.grid(column=1, row=16, padx=3, pady=3, columnspan=2, sticky=(N, S, W, E)) self.scrollbar.grid(column=2, row=16, sticky=(N, S, E)) self.lbl_shift.grid(column=0, row=17, sticky=(W)) self.scl_shift.grid(column=1, row=17, columnspan=2, padx=3, pady=3, sticky=(W, E)) self.lbx_theme.bind("<<ListboxSelect>>", self.get_sel_theme) def set_traces(self): """ Set up entry variable traces for validation and event handling """ self._validsettings = True self._settype.trace("w", self.val_settings) self._zoom.trace("w", self.val_settings) self._zx_off.trace("w", self.val_settings) self._zy_off.trace("w", self.val_settings) self._cx_off.trace("w", self.val_settings) self._cy_off.trace("w", self.val_settings) self._maxiter.trace("w", self.val_settings) self._radius.trace("w", self.val_settings) self._exponent.trace("w", self.val_settings) self._filename.trace("w", self.val_settings) self._frames.trace("w", self.val_settings) self._zoominc.trace("w", self.val_settings) def val_settings(self, *args, **kwargs): """ Validate all user-entered settings. (A personal choice but I find this user experience more intuitive than the standard validatecommand method for Entry widgets) """ self._validsettings = True self.__app.set_status("") if self.is_float(self.ent_zoom.get()) and self._zoom.get() > 0: flg = GOOD else: flg = BAD self.flag_entry(self.ent_zoom, flg) if self.is_float(self.ent_zx_off.get()): flg = GOOD else: flg = BAD self.flag_entry(self.ent_zx_off, flg) if self.is_float(self.ent_zy_off.get()): flg = GOOD else: flg = BAD self.flag_entry(self.ent_zy_off, flg) if self.is_float(self.ent_cx_off.get()): flg = GOOD else: flg = BAD self.flag_entry(self.ent_cx_off, flg) if self.is_float(self.ent_cy_off.get()): flg = GOOD else: flg = BAD self.flag_entry(self.ent_cy_off, flg) if self.is_integer(self.ent_maxiter.get()) and self._maxiter.get() > 0: flg = GOOD else: flg = BAD self.flag_entry(self.ent_maxiter, flg) if self.is_float(self.ent_radius.get()) and self._radius.get() > 0: flg = GOOD else: flg = BAD self.flag_entry(self.ent_radius, flg) if self.is_integer(self.spn_exp.get()) and self._exponent.get() > 1: flg = GOOD else: flg = BAD self.flag_entry(self.spn_exp, flg) if self.is_integer(self.ent_frames.get()) and self._frames.get() > 0: flg = GOOD else: flg = BAD self.flag_entry(self.ent_frames, flg) if self.is_float(self.ent_zoominc.get()) and self._zoominc.get() > 0: flg = GOOD else: flg = BAD self.flag_entry(self.ent_zoominc, flg) if self.is_filename(self.ent_save.get()): flg = GOOD else: flg = BAD self.flag_entry(self.ent_save, flg) if self.spn_settype.get() in {"Mandelbrot", "Tricorn", "BurningShip"}: self.btn_autospin.config(state=DISABLED) self.ent_cx_off.config(state=DISABLED) self.ent_cy_off.config(state=DISABLED) self._cx_off.set(0) self._cy_off.set(0) flg = GOOD elif self.spn_settype.get() == "Julia": self.btn_autospin.config(state=NORMAL) self.ent_cx_off.config(state=NORMAL) self.ent_cy_off.config(state=NORMAL) flg = GOOD else: flg = BAD self.flag_entry(self.spn_settype, flg) def flag_entry(self, ent, flag): """ Flag entry field as valid or invalid and set global validity status flag. This flag is used throughout to determine whether functions can proceed or not. """ ent.config(bg=flag) if flag == BAD: self._validsettings = False self.__app.set_status(VALERROR, "red") def is_float(self, flag): """ Validate if entry is a float. """ try: float(flag) return True except ValueError: return False def is_integer(self, flag): """ Validate if entry is a positive integer. """ try: int(flag) if int(flag) > 0: return True return False except ValueError: return False def is_filename(self, flag): """ Validate if entry represents a valid filename using a regexp. """ return match("^[\w\-. ]+$", flag) and flag != "" def reset(self): """ Reset settings to defaults. """ self._settype.set("Mandelbrot") self._zoom.set(0.75) self._zx_off.set(-0.5) self._zy_off.set(0.0) self._cx_off.set(0.0) self._cy_off.set(0.0) self._maxiter.set(128) self._radius.set(2.0) self._exponent.set(2) self._frames.set(10) self._zoominc.set(2.0) self._autoiter.set(1) self._autosave.set(0) self._theme.set("Default") self._filename.set("image0") self._shift.set(0) self.set_sel_theme() self.__app.set_status(SETINITTXT) def get_sel_theme(self, *args, **kwargs): """ Get selected theme from listbox and set global variable. """ idx = self.lbx_theme.curselection() if idx == "": idx = 0 self._theme.set(self.lbx_theme.get(idx)) def set_sel_theme(self): """ Lookup index of selected theme and highlight that listbox position. NB: this requires 'exportselection=False' option to be set on listbox to work properly. """ for idx, theme in enumerate(THEMES): if theme == self._theme.get(): self.lbx_theme.activate(idx) self.lbx_theme.see(idx) break def get_settings(self): """ Return all current settings as a dict. """ if not self._validsettings: settings = {"valid": self._validsettings} return settings settings = { "settype": self._settype.get(), "zoom": self._zoom.get(), "zxoffset": self._zx_off.get(), "zyoffset": self._zy_off.get(), "cxoffset": self._cx_off.get(), "cyoffset": self._cy_off.get(), "maxiter": self._maxiter.get(), "autoiter": self._autoiter.get(), "autosave": self._autosave.get(), "radius": self._radius.get(), "exponent": self._exponent.get(), "theme": self._theme.get(), "shift": self._shift.get(), "filepath": self._filepath, "filename": self._filename.get(), "frames": self._frames.get(), "zoominc": self._zoominc.get(), "valid": self._validsettings, } return settings def update_settings(self, **kwargs): """ Update settings from keyword parms. """ if "settype" in kwargs: self._settype.set(kwargs["settype"]) if "zoom" in kwargs: self._zoom.set(kwargs["zoom"]) if "zxoffset" in kwargs: self._zx_off.set(kwargs["zxoffset"]) if "zyoffset" in kwargs: self._zy_off.set(kwargs["zyoffset"]) if "cxoffset" in kwargs: self._cx_off.set(kwargs["cxoffset"]) if "cyoffset" in kwargs: self._cy_off.set(kwargs["cyoffset"]) if "maxiter" in kwargs: self._maxiter.set(kwargs["maxiter"]) if "autoiter" in kwargs: self._autoiter.set(kwargs["autoiter"]) if "autosave" in kwargs: self._autosave.set(kwargs["autosave"]) if "radius" in kwargs: self._radius.set(kwargs["radius"]) if "exponent" in kwargs: self._exponent.set(kwargs["exponent"]) if "filepath" in kwargs: self._filepath.set(kwargs["filepath"]) if "filename" in kwargs: self._filename.set(kwargs["filename"]) if "frames" in kwargs: self._frames.set(kwargs["frames"]) if "zoominc" in kwargs: self._zoominc.set(kwargs["zoominc"]) if "theme" in kwargs: self._theme.set(kwargs["theme"]) self.set_sel_theme() if "shift" in kwargs: self._shift.set(kwargs["shift"]) def set_filepath(self): """ Sets filepath for saved files for the duration of this session. """ default = os.getcwd() # Default _filepath is current working directory if self._filepath is None: self._filepath = filedialog.askdirectory(title=SAVETITLE, initialdir=default, mustexist=True) if self._filepath == "": self._filepath = None # User cancelled return self._filepath def save_image(self): """ Save image as PNG file to selected filepath and automatically increment default image name. NB: currently this will overwrite any existing file of the same name without warning. """ # Bug out if the settings are invalid settings = self.__app.frm_settings.get_settings() if not settings["valid"]: return # Check if image has been created image = self.__app.frm_fractal.mandelbrot.get_image() if image is None: self.__app.set_status(NOIMGERROR, "red") return # Set _filename and path if self.set_filepath() is None: # User cancelled return fname = self._filename.get() fqname = self._filepath + "/" + fname # Save the image along with its metadata try: # image.write(fqname + ".png", format="png") image.save(fqname + ".png", format="png") self.save_metadata() except OSError: self.__app.set_status(SAVEERROR, "red") self._filepath = None return self._image_num += 1 self._filename.set(self._image_name + str(self._image_num)) self.__app.set_status(IMGSAVETXT + fqname + ".png", "green") # Return focus to image frame self.__app.frm_fractal.focus_set() def save_metadata(self): """ Save json file containing meta data associated with image, allowing it to be imported and reproduced. """ if self._filepath is None: if self.set_filepath() is None: # User cancelled return fname = self._filename.get() fqname = self._filepath + "/" + fname filename = fqname + ".json" createtime = strftime("%b %d %Y %H:%M:%S %Z", gmtime()) jsondata = { MODULENAME: { "filename": fqname + ".png", "created": createtime, "settype": self._settype.get(), "zoom": self._zoom.get(), "zoominc": self._zoominc.get(), "frames": self._frames.get(), "escradius": self._radius.get(), "exponent": self._exponent.get(), "maxiter": self._maxiter.get(), "zxoffset": self._zx_off.get(), "zyoffset": self._zy_off.get(), "cxoffset": self._cx_off.get(), "cyoffset": self._cy_off.get(), "theme": self._theme.get(), "shift": self._shift.get(), } } try: with open(filename, "w") as outfile: dump(jsondata, outfile) except OSError: self.__app.set_status(METASAVEERROR, "red") self._filepath = None # Return focus to image frame self.__app.frm_fractal.focus_set() def import_metadata(self): """ Update settings from imported json metadata file. """ # Select and read file try: default = os.getcwd() filepath = filedialog.askopenfilename( initialdir=default, title=SELTITLE, filetypes=(("json files", "*.json"), ("all files", "*.*")), ) if filepath == "": # User cancelled return with open(filepath, "r") as infile: jsondata = infile.read() except OSError: self.__app.set_status(OPENFILEERROR, "red") return # Parse file try: settings = loads(jsondata).get(MODULENAME) # Set plot parameters self._settype.set(settings.get("settype", "Mandelbrot")) self._zoom.set(settings.get("zoom", 1)) self._zoominc.set(settings.get("zoominc", 2.0)) self._frames.set(settings.get("frames", 10)) self._radius.set(settings.get("escradius", 2.0)) self._exponent.set(settings.get("exponent", 2)) self._maxiter.set(settings.get("maxiter", 256)) self._zx_off.set(settings.get("zxoffset", 0)) self._zy_off.set(settings.get("zyoffset", 0)) self._cx_off.set(settings.get("cxoffset", 0)) self._cy_off.set(settings.get("cyoffset", 0)) self._theme.set(settings.get("theme", "Default")) self._shift.set(settings.get("shift", 0)) except OSError: self.__app.set_status(BADJSONERROR, "red") return self.set_sel_theme() fbase = os.path.basename(filepath) filename, fileext = os.path.splitext(fbase) self.__app.set_status( "Metadata file " + filename + fileext + METAPROMPTTXT, "green") # Return focus to image frame self.__app.frm_fractal.focus_set()
class PatternTab(Tab): def __init__(self, master): self._parameters = {} super().__init__(master) self.name = None # Setting dropdown menu for selecting pattern type patterns = [ 'layeredflowers', 'radialangular', 'sinespiral', 'spirals', 'iterativerotation' ] self._patternselection = StringVar(self) self._patternselection.trace('w', self._setpattern) self._patternselection.set(patterns[0]) self._patternmenu = OptionMenu(self, self._patternselection, *patterns) dropdownlabel = Label(self, text="Select a Pattern") dropdownlabel.grid(row=0, column=400, pady=(20, 0)) self._patternmenu.grid(row=1, column=400) self._n_angles = None def _setpattern(self, *args): self.clear() # clear tab of parameters from any previous pattern # get selected pattern type and run the setup method for that type patterntype = self._patternselection.get() if patterntype == 'layeredflowers': self._set_layered_flowers() elif patterntype == 'radialangular': self._set_radial_angular() elif patterntype == 'sinespiral': self.set_sin_spiral() elif patterntype == 'spirals': self.set_spirals() elif patterntype == 'iterativerotation': self.set_iterative_rotation() @property def angleparam(self): val1 = self._parameters['rotate'].get() val2 = self._parameters['rotationfactor'].get() return val1 * val2 def _set_layered_flowers(self): # create, set, and grid each parameter: layers = Parameter(self, label="layers", from_=10, to=200, row=3) layers.set(100) angle1 = Parameter(self, label="rotation angle", from_=-18.0, to=18.0, resolution=0.1, bigincrement=0.1, row=5) angle2 = Parameter(self, label="Rotation Multiplier", from_=0, to=10, resolution=0.1, row=10) angle2.set(1) npetals = Parameter(self, label="petals", from_=1.0, to=80, resolution=1, tickinterval=9, row=15) npetals.set(2) innerdepth = Parameter(self, label="Petal Depth", from_=0, to=6, resolution=0.1, bigincrement=0.1, row=20) innerdepth.set(1) size = Parameter(self, label="size", from_=1, to=10, row=25, resolution=0.1) pensize = Parameter(self, label="pen size", from_=1, to=40, row=30) # add all parameters to the patterntab's master list. self._parameters = { 'layers': layers, "npetals": npetals, "innerdepth": innerdepth, "rotate": angle1, "rotationfactor": angle2, "sizefactor": size, "pensize": pensize } def _set_radial_angular(self): # creating, adding, & setting parameters: size = Parameter(self, label="Size", from_=10, to=1000, row=3) size.set(500) pensize = Parameter(self, label="Pen Size", from_=1, to=40, row=10) self._n_angles = IntVar(self) # variable for the angle number menu self._spacedarea.grid( row=6, column=0, columnspan=800 ) # adding the frame from the superclass that allows for even spacing self._parameters = { "size": size, 'pensize': pensize } # for the parameters that feed into the pattern function self._progparams = { 'n_angles': self._n_angles } # for the parameters that help create function parameters, but dont feed in directly options = [1, 2, 3, 4] # number of possible angles self._n_angles.trace( 'w', self._make_angle_boxes ) # Making sure that _make_angle_boxes runs every time this control is moved self._n_angles.set( options[0]) # setting the default number of angles to 1 # making, labeling, and adding dropdown menu self.n_angles_menu = OptionMenu(self, self._n_angles, *options) dropdownlabel = Label(self, text="Number of Angles:") dropdownlabel.grid(row=4, column=400, pady=(10, 0)) self.n_angles_menu.grid(row=5, column=400) self._progparams['n_angles'] = self._n_angles self._progparams['n_angles_menu'] = self.n_angles_menu self._progparams['n_angle_label'] = dropdownlabel def _make_angle_boxes(self, *args): menu = self._progparams['n_angles'] n = menu.get() # this is the value chosen for number of angles prevparams = [ ] # making an empty array for previous options, so you don't lose your settings on re-render if 'angleparams' in self._progparams.keys( ): # if there are user entered angle settings for box in self._progparams[ 'angleparams']: # for angle box in previous settings entry = [] # create entry tosave those settings to for i, widget in enumerate( box): # for each widget in previous settings if i == 0 or i == 2: # these are the indicies for the angle and curve amount variables entry.append( widget.get()) # add the values to the entry widget.grid_forget() # remove the old box from the frame prevparams.append( entry) # add the entry to the list of previous parameters # doing some cleanup from the last run of this method self._progparams['angleparams'] = [] if 'turncycle' in self._parameters.keys(): self._parameters['turncycle'].grid_forget() if 'jank' in self._parameters.keys(): self._parameters['jank'].grid_forget() self._progparams['anglevariables'] = [] for i in range(n): # n is the number of angles we are setting anglevar = StringVar() anglevar.trace('w', self.set_angles) anglebox = Entry(self._spacedarea, width=5, textvariable=anglevar) label1 = Label(self._spacedarea, text=f"angle {str(i + 1)}") curvevar = StringVar() curvevar.trace('w', self.set_angles) curvebox = Entry(self._spacedarea, width=5, textvariable=curvevar) label2 = Label(self._spacedarea, text=f"curve {str(i + 1)}") if len(prevparams) > i: anglevar.set(prevparams[i][0]) curvevar.set(prevparams[i][1]) else: if i == 0: anglevar.set(125) curvevar.set(5) else: anglevar.set(0) curvevar.set(0) if i == 1: turncycle = Scale(self._spacedarea, orient='horizontal', from_=0, to=5, label='turn cycle') turncycle.grid(row=9, column=100, rowspan=3) jank = Scale(self._spacedarea, orient='horizontal', from_=0, to=600, label="jank") jank.grid(row=12, column=100, rowspan=3) self._parameters['turncycle'] = turncycle self._parameters['jank'] = jank col = 20 * ( i + 1 ) # just so that I have flexibility in positioning things later if I make changes label1.grid(row=9, column=col, pady=10) anglebox.grid(row=10, column=col, padx=20) label2.grid(row=12, column=col, padx=20) curvebox.grid(row=14, column=col) self._progparams['angleparams'].append( [anglebox, label1, curvebox, label2]) self._progparams['anglevariables'].append([anglevar, curvevar]) self.set_angles() def set_angles(self, *args): angleparams = self._progparams['anglevariables'] # angles = [[i[0].get(), i[2].get()] for i in angleparams] angles = [[i[0].get(), i[1].get()] for i in angleparams] for i in range(len(angles)): angle = angles[i] for j in range(len(angle)): val = angle[j] try: angles[i][j] = float(val) except ValueError: angles[i][j] = len(val) # print("angle values should be numerical. Using length of " # "input as angle") self._parameters['angles'] = [i for i in angles if i[0] != 0] def set_sin_spiral(self): pady = 3 # the y spacing needed for this particular pattern type n_strands = Parameter(self, label="Number of Waves", from_=1, to=300, row=10, pady=pady) length = Parameter(self, label="Length", from_=0, to=50, row=12, pady=pady) x_shift = Parameter(self, label="Shift X", from_=0, to=50, row=14, pady=pady, resolution=0.1, bigincrement=0.1) y_shift = Parameter(self, label="Shift Y", from_=0, to=50, row=18, pady=pady, resolution=0.1, bigincrement=0.1) rotation = Parameter(self, label="Rotation", from_=-18.0, to=18.0, row=22, pady=pady) rotaterate = Parameter(self, label="Rotation Multiplier", from_=0, to=10, row=26, resolution=0.1, bigincrement=0.1, pady=pady) wavelen = Parameter(self, label="Wavelength", from_=0, to=500, row=30, pady=pady) wl_shift = Parameter(self, label="Wavelength Shift", from_=0, to=10, row=34, pady=pady, resolution=0.1, bigincrement=0.1) amp = Parameter(self, label="Ampitude", from_=0, to=500, row=38, pady=pady) amp_shift = Parameter(self, label="Amplitude Shift", from_=0, to=20, row=42, pady=pady, resolution=0.1, bigincrement=0.1) pensize = Parameter(self, label="Pen Size", from_=1, to=40, row=46, pady=pady) cosine = BooleanVar() sinebtn = Radiobutton(self, text='Sine', width=5, indicatoron=False, value=False, variable=cosine) cosinebtn = Radiobutton(self, text='Cosine', width=5, indicatoron=False, value=True, variable=cosine) sinebtn.grid(row=50, column=50, columnspan=100, pady=20) cosinebtn.grid(row=50, column=180, columnspan=100) n_strands.set(100) length.set(30) x_shift.set(1) rotaterate.set(1) wavelen.set(50) amp.set(100) self._progparams['cosinebuttons'] = [sinebtn, cosinebtn] self._parameters = { 'strands': n_strands, 'xshift': x_shift, 'yshift': y_shift, "rotate": rotation, 'rotaterate': rotaterate, 'wavelength': wavelen, 'amplitude': amp, 'wlshift': wl_shift, 'ampshift': amp_shift, 'length': length, 'pensize': pensize, 'cosine': cosine } def set_spirals(self): reps = Parameter(self, label="Number of Spirals", from_=1, to=600, row=10) rotation = Parameter(self, label="Rotation", from_=-180, to=180, row=20, resolution=0.1, bigincrement=0.1) curve = Parameter(self, label="Scale", from_=1, to=50, row=22) diameter = Parameter(self, label="Curve Length", from_=1, to=30, row=25) scale = Parameter(self, label="Spiral Tightness (Size)", from_=5, to=50, row=27) poly = Parameter(self, label="Poly", from_=2, to=400, row=30) centerdist = Parameter(self, label="Distance from Center", from_=0, to=50, row=32) pensize = Parameter(self, label="Pen Size", from_=1, to=60, row=36) reps.set(60) rotation.set(5) curve.set(10) diameter.set(10) scale.set(20) poly.set(400) centerdist.set(0) self._parameters = { 'reps': reps, 'rotation': rotation, 'curve': curve, 'diameter': diameter, 'scale': scale, 'poly': poly, 'centerdist': centerdist, 'pensize': pensize } def set_iterative_rotation(self): pady = 0 shapeoptions = ['Wave', 'Rectangle', 'Circle'] shape = StringVar() shapemenulabel = Label(self, text="Shape") shapemenu = OptionMenu(self, shape, *shapeoptions) shapemenulabel.grid(column=10, row=23, columnspan=200) shapemenu.grid(column=10, row=25, columnspan=200) branches = Parameter(self, label="Number of Branches", from_=2, to=60, pady=pady, row=27) repetitions = Parameter(self, label='Repetitions', from_=4, to=80, pady=pady, row=30) shiftx = Parameter(self, label='Shift X', from_=-10, to=10, resolution=0.1, pady=pady, row=35) shifty = Parameter(self, label='Shift Y', from_=-10, to=10, resolution=0.1, pady=pady, row=40) rotation = Parameter(self, label='Rotation', from_=-30, to=30, resolution=0.1, pady=pady, row=42) stretch = Parameter(self, label='Stretch (Wave Only)', from_=0, to=80, pady=pady, row=45) length = Parameter(self, label='Length/Width', from_=1, to=150, pady=pady, row=50) depth = Parameter(self, label='Amplitude/Height', from_=0, to=150, pady=pady, row=55) stretchshift = Parameter(self, label="Stretch Shift (Wave Only)", from_=-3, to=3, pady=pady, row=60, resolution=0.1) lenshift = Parameter(self, label="Length/Width Shift", from_=-3, to=3, pady=pady, row=65, resolution=0.1) depthshift = Parameter(self, label="Amplitude/Height Shift", from_=-3, to=3, pady=pady, row=70, resolution=0.1) distshift = Parameter(self, label="Distance Shift", from_=0, to=0.5, pady=pady, row=75, resolution=0.01) cosine = BooleanVar() sinebtn = Radiobutton(self, text='Sine', width=5, indicatoron=False, value=False, variable=cosine) cosinebtn = Radiobutton(self, text='Cosine', width=5, indicatoron=False, value=True, variable=cosine) sinebtn.grid(row=80, column=50, columnspan=100, pady=20) cosinebtn.grid(row=80, column=180, columnspan=100) shape.set('Rectangle') repetitions.set(30) rotation.set(2) stretch.set(20) length.set(30) depth.set(30) branches.set(8) self._progparams['shapemenu'] = shapemenu self._progparams['shapemenulabel'] = shapemenulabel self._progparams['cosinebuttons'] = [cosinebtn, sinebtn] self._parameters = { "function": shape, "reps": repetitions, "xshift": shiftx, "yshift": shifty, 'stretch': stretch, "length": length, "depth": depth, "stretchshift": stretchshift, "lenshift": lenshift, "depthshift": depthshift, "cosine": cosine, "distshift": distshift, "individualrotation": rotation, "branches": branches } def clear(self): """ This method is used to remove all Widgets from the frame when switching pattern types """ for p in self._parameters.values(): if isinstance(p, Widget): p.grid_forget() self._spacedarea.grid_forget() for item in self._progparams.values(): if isinstance(item, Widget): item.grid_forget() elif isinstance(item, list): for i in item: if isinstance(i, Widget): i.grid_forget() else: for j in i: if isinstance(j, (Widget, Parameter)): j.grid_forget() def save(self, mode, name): if mode == 'patterns': self.name = name params = {} # converting all widget parameters to their values for save: for k, v in self._parameters.items(): if isinstance(v, (Widget, BooleanVar, IntVar, StringVar)): params[k] = v.get() else: params[k] = v # Create new object with all necessary values for save: output = { 'patterntype': self._patternselection.get(), 'parameters': params } return self.name, output def load(self, name, data): """ Sets parameters to the values in the data retrieved Args: data: a Dictionary with patterntype, parameters, and progparams if the retrieved pattern is of radialangular type Returns: None """ # Set patternselection to retrieved value, which is bound to the _setpattern method: self._patternselection.set(data['patterntype']) params = data['parameters'] # Set the angle boxes if it's a radialangular pattern type if data['patterntype'] == 'radialangular': angles = data['parameters']['angles'] # get list of angles self._n_angles.set( len(params['angles'] )) # set number of angle boxes to number of angles in list angleparams = self._progparams[ 'anglevariables'] # retrieves the variables for the angle boxes for i in range(len(angleparams)): # for each index in angleparams boxes = angleparams[ i] # get the 2 boxes (angle, curve) for each angle anglebox, curvebox = boxes[0], boxes[ 1] # separate them from eachother anglebox.set( angles[i][0]) # set the angle to the retrieved value curvebox.set( angles[i][1]) # set the curve to the retrieeved value for k in params: # for each key in the parameter dictionary: if k in self._parameters: # if that parameter already exists in the master parameter dictionary: if not isinstance(self._parameters[k], (list, bool)): self._parameters[k].set( params[k] ) # set that parameter to the retrieved value for that param else: # if that parameter isn't already in the list: self._parameters[k] = params[k] # add it self.name = name def run(self, colorscheme): """ This method is called from the the master Application. Args: colorscheme: a SpiroGen ColorScheme object Returns: None. Draws pattern """ parameters = {} # convert parameter widgets/variables to their values for param in self._parameters.items(): label, value = param[0], param[1] if not isinstance(value, (int, float, str, list, tuple)): parameters[label] = value.get() else: parameters[label] = value # This is where the patterns are actually drawn based on selection: if self._patternselection.get() == "layeredflowers": parameters['rotate'] = self.angleparam parameters.pop('rotationfactor') LVL2.layered_flowers(**parameters, colors=colorscheme) elif self._patternselection.get() == "radialangular": self.set_angles() RadialAngularPattern(**parameters, colors=colorscheme).drawpath() elif self._patternselection.get() == 'sinespiral': pensize = parameters.pop('pensize') DrawPath( LVL2.sin_spiral(**parameters), colors=colorscheme, pensize=pensize, ) elif self._patternselection.get() == 'spirals': LVL2.spiral_spiral(**parameters, colors=colorscheme) elif self._patternselection.get() == 'iterativerotation': LVL2.random_iterative_rotation(**parameters, colors=colorscheme, rotationcenter=(0, 0)) # LVL2.iterative_rotation(**parameters, colors=colorscheme) spiro.wait( ) # This keeps the pattern window from closing as soon as it's done drawing
def __init__(self, master, par=False): """ GUI for selecting default parameters - will write parameters to file \ of users choosing. :type master: Tk :param master: Tkinter window :type par: EQcorrscanParameters :param par: Default parameters to start-up with. """ from tkinter import Label, Button, Entry, DoubleVar, StringVar, IntVar from tkinter import BooleanVar, OptionMenu, Checkbutton import tkMessageBox from eqcorrscan.utils import parameters from obspy import UTCDateTime import warnings # Set the default par, only if they don't already exist. if not par: par = parameters.EQcorrscanParameters([''], 2, 10, 4, 100, 2, '1900-01-01', '2300-01-01', '', 'seishub', 4, False, '', 'jpg', False, 8, 'MAD', 6) # Callback functions for all variables (ugly) def update_template_names(*args): par.template_names = [ name.strip() for name in template_names.get().split(',') ] template_names.set(', '.join(par.template_names)) def update_lowcut(*args): par.lowcut = lowcut.get() lowcut.set(par.lowcut) def update_highcut(*args): par.highcut = highcut.get() if par.highcut >= 0.5 * par.samp_rate: msg = ('Highcut must be less than the Nyquist, setting to ' + str((par.samp_rate / 2.0) - 1)) tkMessageBox.showwarning(title="Nyquist error", message=msg) par.highcut = (par.samp_rate / 2.0) - 1 highcut.set(par.highcut) def update_filt_order(*args): par.filt_order = filt_order.get() filt_order.set(par.filt_order) def update_samp_rate(*args): par.samp_rate = samp_rate.get() if par.highcut >= 0.5 * par.samp_rate: msg = ('Highcut must be less than the Nyquist, setting to ' + str((par.samp_rate / 2.0) - 1)) tkMessageBox.showwarning(title="Nyquist error", message=msg) par.highcut = (par.samp_rate / 2.0) - 1 highcut.set(par.highcut) samp_rate.set(par.samp_rate) def update_debug(*args): par.debug = debug.get() debug.set(par.debug) def update_startdate(*args): par.startdate = UTCDateTime(startdate.get()) startdate.set(str(par.startdate)) def update_enddate(*args): par.enddate = UTCDateTime(enddate.get()) enddate.set(str(par.enddate)) def update_archive(*args): par.archive = archive.get() archive.set(par.archive) def update_arc_type(*args): par.arc_type = arc_type.get() arc_type.set(par.arc_type) def update_cores(*args): par.cores = cores.get() cores.set(par.cores) def update_plotvar(*args): par.plotvar = plotvar.get() plotvar.set(par.plotvar) def update_plot_format(*args): par.plot_format = plot_format.get() plot_format.set(par.plot_format) def update_tempdir(*args): par.tempdir = tempdir.get() tempdir.set(par.tempdir) def update_threshold(*args): par.threshold = threshold.get() threshold.set(par.threshold) def update_threshold_type(*args): par.threshold_type = threshold_type.get() threshold_type.set(par.threshold_type) def update_plotdir(*args): par.plotdir = plotdir.get() plotdir.set(par.plotdir) def update_trigger_interval(*args): par.trigger_interval = trigger_interval.get() trigger_interval.set(par.trigger_interval) # Set some grid parameters nrows = 25 ncolumns = 3 self.master = master master.title("EQcorrscan parameter setup") self.label = Label(master, text="Alpha GUI for default setup") self.label.grid(column=0, columnspan=ncolumns, row=0) # Set up parameter input self.t_names_label = Label(master, text="Template names", anchor='e') self.t_names_label.grid(column=0, row=1, sticky='e') template_names = StringVar() template_names.set(', '.join(par.template_names)) self.t_names_box = Entry(master, bd=2, textvariable=template_names) self.t_names_box.grid(column=1, row=1) template_names.trace("w", update_template_names) self.t_names_lookup = Button( master, text="Lookup", command=lambda: self.get_template_names(par)) self.t_names_lookup.grid(column=2, row=1) self.lowcut_label = Label(master, text="Lowcut (Hz)", anchor='e') self.lowcut_label.grid(column=0, row=2, sticky='e') lowcut = DoubleVar() lowcut.set(par.lowcut) self.lowcut_box = Entry(master, bd=2, textvariable=lowcut) self.lowcut_box.grid(column=1, row=2) lowcut.trace("w", update_lowcut) self.highcut_label = Label(master, text="Highcut (Hz)", anchor='e') self.highcut_label.grid(column=0, row=3, sticky='e') highcut = DoubleVar() highcut.set(par.highcut) self.highcut_box = Entry(master, bd=2, textvariable=highcut) self.highcut_box.grid(column=1, row=3) highcut.trace("w", update_highcut) self.filt_order_label = Label(master, text="Filter order") self.filt_order_label.grid(column=0, row=4, sticky='e') filt_order = DoubleVar() filt_order.set(par.filt_order) self.filt_order_box = Entry(master, bd=2, textvariable=filt_order) self.filt_order_box.grid(column=1, row=4) filt_order.trace("w", update_filt_order) self.samp_rate_label = Label(master, text="Sample rate (Hz)") self.samp_rate_label.grid(column=0, row=5, sticky='e') samp_rate = DoubleVar() samp_rate.set(par.samp_rate) self.samp_rate_box = Entry(master, bd=2, textvariable=samp_rate) self.samp_rate_box.grid(column=1, row=5) samp_rate.trace("w", update_samp_rate) self.debug_label = Label(master, text="Debug") self.debug_label.grid(column=0, row=6, sticky='e') debug = IntVar() debug.set(par.debug) self.debug_box = Entry(master, bd=2, textvariable=debug) self.debug_box.grid(column=1, row=6) debug.trace("w", update_debug) self.startdate_label = Label(master, text="Start date (yyyy-mm-dd)") self.startdate_label.grid(column=0, row=6, sticky='e') startdate = StringVar() startdate.set(par.startdate) self.startdate_box = Entry(master, bd=2, textvariable=startdate) self.startdate_box.grid(column=1, row=6) startdate.trace("w", update_startdate) self.enddate_label = Label(master, text="End date (yyyy-mm-dd)") self.enddate_label.grid(column=0, row=8, sticky='e') enddate = StringVar() enddate.set(par.enddate) self.enddate_box = Entry(master, bd=2, textvariable=enddate) self.enddate_box.grid(column=1, row=8) enddate.trace("w", update_enddate) self.archive_label = Label(master, text="Archive") self.archive_label.grid(column=0, row=9, sticky='e') archive = StringVar() archive.set(par.archive) self.archive_box = Entry(master, bd=2, textvariable=archive) self.archive_box.grid(column=1, row=9) archive.trace("w", update_archive) self.archive_lookup = Button(master, text="Lookup", command=lambda: self.get_archive(par)) self.archive_lookup.grid(column=2, row=9) self.arc_type_label = Label(master, text="Archive type") self.arc_type_label.grid(column=0, row=10, sticky='e') arc_type = StringVar() arc_type.set(par.arc_type) self.arc_type_box = OptionMenu(master, arc_type, "seishub", "fdsn", "day_vols") self.arc_type_box.grid(column=1, row=10, sticky='w,e') arc_type.trace("w", update_arc_type) self.cores_label = Label(master, text="Number of cores") self.cores_label.grid(column=0, row=11, sticky='e') cores = IntVar() cores.set(par.cores) self.cores_box = Entry(master, bd=2, textvariable=cores) self.cores_box.grid(column=1, row=11) cores.trace("w", update_cores) self.plotvar_label = Label(master, text="Plotting on/off") self.plotvar_label.grid(column=0, row=12, sticky='e') plotvar = BooleanVar() plotvar.set(par.plotvar) self.plotvar_box = Checkbutton(master, text='Plot on', var=plotvar, onvalue=True, offvalue=False) self.plotvar_box.grid(column=1, row=12) plotvar.trace("w", update_plotvar) self.plotdir_label = Label(master, text="Plot directory") self.plotdir_label.grid(column=0, row=13, sticky='e') plotdir = StringVar() plotdir.set(par.plotdir) self.plotdir_box = Entry(master, bd=2, textvariable=plotdir) self.plotdir_box.grid(column=1, row=13) plotdir.trace("w", update_plotdir) self.plotdir_lookup = Button(master, text="Lookup", command=lambda: self.get_plotdir(par)) self.plotdir_lookup.grid(column=2, row=13) self.plot_format_label = Label(master, text="Plot format") self.plot_format_label.grid(column=0, row=14, sticky='e') plot_format = StringVar() plot_format.set(par.plot_format) self.plot_format_box = OptionMenu(master, plot_format, "jpg", "eps", "pdf", "png") self.plot_format_box.grid(column=1, row=14, sticky='w,e') plot_format.trace("w", update_plot_format) self.tempdir_label = Label(master, text="Temporary directory") self.tempdir_label.grid(column=0, row=15, sticky='e') tempdir = StringVar() tempdir.set(par.tempdir) self.tempdir_box = Entry(master, bd=2, textvariable=tempdir) self.tempdir_box.grid(column=1, row=15) tempdir.trace("w", update_tempdir) self.tempdir_lookup = Button(master, text="Lookup", command=lambda: self.get_tempdir(par)) self.tempdir_lookup.grid(column=2, row=15) self.threshold_label = Label(master, text="Threshold") self.threshold_label.grid(column=0, row=16, sticky='e') threshold = DoubleVar() threshold.set(par.threshold) self.threshold_box = Entry(master, bd=2, textvariable=threshold) self.threshold_box.grid(column=1, row=16) threshold.trace("w", update_threshold) self.threshold_type_label = Label(master, text="Threshold type") self.threshold_type_label.grid(column=0, row=17, sticky='e') threshold_type = StringVar() threshold_type.set(par.threshold_type) self.threshold_type_box = OptionMenu(master, threshold_type, "MAD", "absolute", "av_chan_corr") self.threshold_type_box.grid(column=1, row=17, sticky='w,e') threshold_type.trace("w", update_threshold_type) self.trigger_interval_label = Label(master, text="Minimum trigger " + "interval (s)") self.trigger_interval_label.grid(column=0, row=18, sticky='e') trigger_interval = DoubleVar() trigger_interval.set(par.trigger_interval) self.trigger_interval_box = Entry(master, bd=2, textvariable=trigger_interval) self.trigger_interval_box.grid(column=1, row=18) trigger_interval.trace("w", update_trigger_interval) # End of user editable section, now we have read/write buttons self.read_button = Button(master, text="Read parameters", command=lambda: self.read_par(master)) self.read_button.grid(column=0, row=nrows - 2, sticky='w,e') self.write_button = Button(master, text="Write parameters", command=lambda: self.write_par(par)) self.write_button.grid(column=1, row=nrows - 2, sticky='w,e')
class GUI(object): def __init__(self): self.classifier = "" # checks whether the files exist in the given folder and are not empty def check_files_exist(self, path): return os.path.isfile(path + "/Structure.txt") and os.path.isfile( path + "/train.csv" ) and os.path.isfile(path + "/test.csv") and os.path.getsize( path + "/Structure.txt") > 0 and os.path.getsize( path + "/train.csv") > 0 and os.path.getsize(path + "/test.csv") > 0 # gets the path for the folder def get_path(self, root): try: path = filedialog.askdirectory(parent=root, title='Naive Bayes Classifier') if path is None: messagebox.showerror("Error", "Couldn't get the path!") else: if self.check_files_exist(path): self.folder_path.set(path) else: messagebox.showerror("Error", "Missing / Empty Files!") except: messagebox.showerror("Error", "Couldn't get the path!") # builds the model from the given structure and training files def build(self): try: data_structure = {} structure_file = open(self.folder_path.get() + "/Structure.txt", "r") structure_content = structure_file.readlines() structure_file.close() # get the structure of the model from the structure file for line in structure_content: initial_split = line.split(" ") classifiers = initial_split[2] if len(initial_split) > 3: i = 3 while i < len(initial_split): classifiers = classifiers + " " + initial_split[i] i = i + 1 if '{' in classifiers: classifiers = classifiers.replace("\n", "") classifiers = classifiers.replace("{", "") classifiers = classifiers.replace("}", "") classifiers = classifiers.split(",") else: classifiers = ['NUMERIC'] # add a new entry to the structure data_structure[line.split(" ")[1]] = { 'attributes': classifiers } # get the raw data from the train file train_data = pd.read_csv( filepath_or_buffer=self.folder_path.get() + "/train.csv") # create the classifier from the training file self.classifier = Classifier.Classifier(self.folder_path.get(), data_structure, int(self.bins.get())) self.classifier.build_model(train_data) # enable the "Classify" button to be pressed self.classify_button.config(state='normal') messagebox.showinfo( "Information", "Building classifier using train-set is done!") except IOError: messagebox.showerror("Error", "There was a problem reading the files!") # classify the given test file by using the NB model generated earlier def classify(self): # get the raw data from the train file test_data = pd.read_csv(filepath_or_buffer=self.folder_path.get() + "/test.csv") # get the classifications for the test file self.classifier.classify_input(test_data) answered_ok = messagebox.showinfo("Information", "Classification completed!") if answered_ok == 'OK': self.root.destroy() # builds and shows the GUI def show_gui(self): # create the main window self.root = Tk() self.root.title('Naive Bayes Classifier') self.root.geometry('500x300') # create the frame frame = Frame(self.root) frame.pack(side='top', fill='both', expand=True) # initialize the 2 global input variables self.bins = IntVar(self.root, value=2) self.folder_path = StringVar(self.root) # validates the input for enabling the "Build" button to be pressed def validate_input(*args): dir_ok = False bin_ok = False # check if the directory and its contents are ok if self.folder_path.get() is not None and os.path.isdir( self.folder_path.get()): if self.check_files_exist(self.folder_path.get()): dir_ok = True # checks if the a given string is a positive integer def represents_int(s): try: int(s) return True except ValueError: return False # check if the entered bins are ok if represents_int(bins_text_box.get()): if int(bins_text_box.get()) > 0: bin_ok = True # enable the Build button if both are ok if dir_ok and bin_ok: build_button.config(state='normal') else: build_button.config(state='disabled') x = browse_text_box.get() y = bins_text_box.get() # initialize labels and buttons browse_label = Label(frame, text="Directory Path:") browse_label.grid(column=0, row=1, padx=4, pady=4) browse_text_box = Entry(frame, width=40, textvariable=self.folder_path) browse_text_box.grid(column=1, row=1, padx=4, pady=4) browse_button = Button(frame, text="Browse", command=lambda: self.get_path(self.root)) browse_button.grid(column=2, row=1, padx=4, pady=4) self.folder_path.trace("w", validate_input) bins_label = Label(frame, text="Discretization Bins:") bins_label.grid(column=0, row=2, padx=4, pady=4) self.bins.trace("w", validate_input) bins_text_box = Entry(frame, width=40, textvariable=self.bins) bins_text_box.grid(column=1, row=2, padx=4, pady=4) build_button = Button(frame, text="Build", command=lambda: self.build()) build_button.grid(column=1, row=3, padx=5, pady=8) build_button.config(state='disabled') self.classify_button = Button(frame, text="Classify", command=lambda: self.classify()) self.classify_button.grid(column=1, row=4, padx=5, pady=8) self.classify_button.config(state='disabled') self.root.mainloop()
class TkContourEditor(FigureCanvasTkAgg): def __init__(self, parent, **kwargs): FigureCanvasTkAgg.__init__(self, Figure(), master=parent, **kwargs) self.plt = ContourEditor(self.figure, renderer=self) self.cell = IntVar() self.step = IntVar() self.variable = StringVar() self.integral = DoubleVar() self.cell.trace('w', self._cell) self.step.trace('w', self._step) self.variable.trace('w', self._variable) self.figure.canvas.mpl_connect('button_press_event', self.onclick) def _pass(*args, **kwargs): pass self.cell._report_exception = _pass self.step._report_exception = _pass self.plt.delaunay = True self.plt.callback = self.integral.set self.label = None def _cell(self, *args): c = self.cell.get() try: self.plt.cell = c except ValueError: self.cell.set(-1) raise except: print(traceback.format_exc()) raise def _step(self, *args): s = self.step.get() if s < 1: self.step.set(1) else: try: self.plt.step = s except: print(traceback.format_exc()) raise def _variable(self, *args): try: self.plt.variable = self.variable.get() if self.label is not None: if self.plt._variables[self.plt.variable][1:]: self.label['text'] = 'Curl:' else: self.label['text'] = 'Mean:' except: print(traceback.format_exc()) raise def onclick(self, event): x, y = event.xdata, event.ydata if x is None or y is None: return self.cell.set(self.plt.find_cell((x, y))) def toggle_delaunay(self, *args): self.plt.delaunay = not self.plt._delaunay @property def cells(self): return self.plt.cells @cells.setter def cells(self, cs): try: self.plt.cells = cs except: print(traceback.format_exc()) raise @property def map(self): return self.plt.map @map.setter def map(self, m): try: self.plt.map = m except: print(traceback.format_exc()) raise @property def variables(self): return self.plt.variables @property def debug(self): return self.plt.debug @debug.setter def debug(self, d): self.plt.debug = d
class NewMorphLineWindow(Toplevel): def __init__(self, master=None): super().__init__(master=master) self.set_basic() self.set_widgets() def set_basic(self): self.minsize(600, 400) self.maxsize(600, 400) self.title("Ekstrakcja linii") self.protocol("WM_DELETE_WINDOW", lambda: self.cancel()) self.handleBorder = { "Bez zmian (isolated)": 0, "Odbicie lustrzane (reflect)": 1, "Powielenie skrajnego piksela (replicate)": 2 } def set_widgets(self): self.horizontalSizeW = StringVar(self, value="3") self.horizontalSizeH = StringVar(self, value="1") self.verticalSizeW = StringVar(self, value="3") self.verticalSizeH = StringVar(self, value="1") self.borderType = StringVar(self, list(self.handleBorder.keys())[0]) self.cbVarHorizontal = IntVar(value=1) self.cbVarVertical = IntVar(value=1) self.cbVarOuter = IntVar(value=1) self.cbVarNegate = IntVar(value=0) self.sizeHorizontalWSpin = Spinbox(self, justify='center', font=("Helvetica", 15), from_=1, to=9999, textvariable=self.horizontalSizeW, command=self.update_preview, state='readonly', increment=2) self.sizeHorizontalHSpin = Spinbox(self, justify='center', font=("Helvetica", 15), from_=1, to=9999, textvariable=self.horizontalSizeH, command=self.update_preview, state='readonly', increment=2) self.sizeVerticalWSpin = Spinbox(self, justify='center', font=("Helvetica", 15), from_=1, to=9999, textvariable=self.verticalSizeW, command=self.update_preview, state='readonly', increment=2) self.sizeVerticalHSpin = Spinbox(self, justify='center', font=("Helvetica", 15), from_=1, to=9999, textvariable=self.verticalSizeH, command=self.update_preview, state='readonly', increment=2) self.horizontalSizeW.trace("w", self.update_preview) self.horizontalSizeH.trace("w", self.update_preview) self.verticalSizeW.trace("w", self.update_preview) self.verticalSizeH.trace("w", self.update_preview) self.borderType.trace("w", self.update_preview) self.cbVarHorizontal.trace("w", self.update_preview) self.cbVarVertical.trace("w", self.update_preview) self.cbVarOuter.trace("w", self.update_preview) self.cbVarNegate.trace("w", self.update_preview) self.cbHorizontal = Checkbutton(self, width=0, variable=self.cbVarHorizontal) self.cbVertical = Checkbutton(self, width=0, variable=self.cbVarVertical) self.cbOuterOnly = Checkbutton(self, width=0, variable=self.cbVarOuter) self.cbNegateFirst = Checkbutton(self, width=0, variable=self.cbVarNegate) self.borderList = OptionMenu(self, self.borderType) for border in self.handleBorder: self.borderList['menu'].add_command( label=border, command=lambda v=border: self.borderType.set(v)) self.saveButton = Button(self, image=saveIcon, command=self.update_image) self.cancelButton = Button(self, image=closeIcon, command=self.cancel) self.update_preview() self.place_widgets() def update_image(self): self.master.image.cv2Image = copy.deepcopy(self.master.image.copy) self.master.image.morph_line(int(self.horizontalSizeW.get()), int(self.horizontalSizeH.get()), int(self.verticalSizeW.get()), int(self.verticalSizeH.get()), self.cbVarHorizontal.get(), self.cbVarVertical.get(), self.handleBorder[self.borderType.get()], self.cbVarOuter.get(), self.cbVarNegate.get()) self.master.image.copy = copy.deepcopy(self.master.image.cv2Image) self.master.manager.new_state(self.master.image.cv2Image) self.master.update_visible_image() self.master.update_child_windows() self.destroy() def update_preview(self, *args): self.sizeHorizontalWSpin.config(from_=int(self.horizontalSizeH.get()) + 2) self.sizeHorizontalHSpin.config(to=int(self.horizontalSizeW.get()) - 2) self.sizeVerticalWSpin.config(from_=int(self.verticalSizeH.get()) + 2) self.sizeVerticalHSpin.config(to=int(self.verticalSizeW.get()) - 2) self.master.image.cv2Image = copy.deepcopy(self.master.image.copy) self.master.image.morph_line(int(self.horizontalSizeW.get()), int(self.horizontalSizeH.get()), int(self.verticalSizeW.get()), int(self.verticalSizeH.get()), self.cbVarHorizontal.get(), self.cbVarVertical.get(), self.handleBorder[self.borderType.get()], self.cbVarOuter.get(), self.cbVarNegate.get()) self.master.update_visible_image() self.master.update_child_windows() def place_widgets(self): Label(self, text="Poziome linie", font=("Helvetica", 15)).place(x=85, y=15) Label(self, text="Pionowe linie", font=("Helvetica", 15)).place(x=395, y=15) self.sizeHorizontalWSpin.place(width=100, height=50, x=150, y=60) self.sizeHorizontalHSpin.place(width=100, height=50, x=150, y=120) self.sizeVerticalWSpin.place(width=100, height=50, x=450, y=60) self.sizeVerticalHSpin.place(width=100, height=50, x=450, y=120) Label(self, text="Min. długość", font=("Helvetica", 15)).place(x=30, y=70) Label(self, text="Min. grubość", font=("Helvetica", 15)).place(x=30, y=130) Label(self, text="Min. długość", font=("Helvetica", 15)).place(x=330, y=70) Label(self, text="Min. grubość", font=("Helvetica", 15)).place(x=330, y=130) Label(self, text="Szukać poziomych?", font=("Helvetica", 9)).place(x=70, y=175) Label(self, text="Szukać pionowych?", font=("Helvetica", 9)).place(x=380, y=175) self.cbHorizontal.place(x=180, y=175) self.cbVertical.place(x=500, y=175) Label(self, text="Szukać tylko zewnętrznych?", font=("Helvetica", 11)).place(x=190, y=225) Label(self, text="Wstępnie zanegować?", font=("Helvetica", 11)).place(x=190, y=255) self.cbOuterOnly.place(x=390, y=225) self.cbNegateFirst.place(x=390, y=255) self.borderList.place(width=200, height=50, x=200, y=300) self.saveButton.place(width=40, height=40, x=220, y=355) self.cancelButton.place(width=40, height=40, x=340, y=355) 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.destroy()