class CustomSpinbox(Frame): def __init__(self, master, *args, label="", minimum=0, maximum=9999, **kwargs): super(CustomSpinbox, self).__init__(master, *args, **kwargs) self.minimum = minimum self.maximum = maximum if maximum > minimum else minimum + 1 self.create_spinbox(label) self.register_filter() def create_spinbox(self, label): from tkinter import Label self.label = Label(self, text=label, width=LABEL_WIDTH) self.spinbox = Spinbox(self, from_=self.minimum, to=self.maximum) self.label.pack(side="left") self.spinbox.pack(side="left", fill="x", expand=True) def register_filter(self): tk = self.get_instance_tk(self) if tk: new_register = tk.register(self.filter_spinbox) self.spinbox.config(validate="key", validatecommand=(new_register, "%P")) def filter_spinbox(self, value): if value.isdigit() and int(value) in range(self.minimum, self.maximum + 1): return True if value == "": return True return False def get_instance_tk(self, widget): from tkinter import Tk if isinstance(widget, Tk): return widget else: master = self.get_instance_tk(widget.master) return master def set_label(self, label): self.label.config(text=label) def get_value(self): return int(self.spinbox.get()) def set_value(self, value): if value in range(self.minimum, self.maximum + 1): self.spinbox.delete(0, "end") self.spinbox.insert("end", str(value))
class TimeChooser(Frame): ''' classdocs ''' def __init__(self, parent, initialTime=None): super().__init__(parent) if initialTime is None: initialTime = datetime.now().time() self.hour = Spinbox(self, from_=1, to=12, width=3) self.hour.grid(column=0, row=0) Label(self, text=":").grid(column=1, row=0) self.minute = Spinbox(self, from_=00, to=59, format="%02.0f", width=3) self.minute.grid(column=2, row=0) self.ampm = Spinbox(self, values=("AM", "PM"), width=4) self.ampm.grid(column=3, row=0) # set AM/PM self.ampm.delete(0, "end") self.ampm.insert(0, "AM" if initialTime.hour < 12 else "PM") # set hour, 12-hour display self.hour.delete(0, "end") if initialTime.hour == 0: self.hour.insert(0, "12") elif initialTime.hour <= 12: self.hour.insert(0, str(initialTime.hour)) else: self.hour.insert(0, str(initialTime.hour - 12)) # set minute self.minute.delete(0, "end") self.minute.insert(0, "{:0>2d}".format(initialTime.minute)) # readonly the entry widgets self.hour.config(state="readonly") self.minute.config(state="readonly") self.ampm.config(state="readonly") def getTime(self): hour = int(self.hour.get()) if self.ampm.get() == "AM": hour %= 12 elif hour < 12: hour += 12 return time(hour=int(hour), minute=int(self.minute.get()))
def __init__(self,master=None): Frame.__init__(self,master) #Sides of Dice labelSides=Label(self,text="Sides") labelSides.grid(row=0,column=0) self.sides=StringVar() self.sides.set(20) spinboxSides=Spinbox(self,from_=1,to=20,increment=1,width=4) spinboxSides.config(textvariable=self.sides, font="sans 24", justify="center") spinboxSides.grid(row=0,column=1) #Number of Dices labelNumber=Label(self,text="Number") labelNumber.grid(row=1,column=0) self.number=StringVar() self.number.set(1) spinboxNumber=Spinbox(self,from_=1,to=30,increment=1,width=4) spinboxNumber.config(textvariable=self.number, font="sans 24", justify="center") spinboxNumber.grid(row=1,column=1) #Modifier labelModifier=Label(self,text="Modifier") labelModifier.grid(row=2,column=0) self.modifier=StringVar() self.modifier.set(0) spinboxModifier=Spinbox(self,from_=-5,to=5,increment=1,width=4) spinboxModifier.config(textvariable=self.modifier, font="sans 24", justify="center") spinboxModifier.grid(row=2,column=1) #Hide Checkbox labelHide=Label(self, text="Hide") labelHide.grid(row=2, column=2) self.hide=IntVar() self.hide.set(0) checkbuttonHide=Checkbutton(self,variable=self.hide) checkbuttonHide.grid(row=2,column=3) #Result display self.result=StringVar() self.result.set("") labelResult1=Label(self,text="Result") labelResult1.grid(row=1, column=4) labelResult2=Label(self,text=self.result.get(),relief=SUNKEN,width=4) labelResult2.grid(row=1,column=5) #Button to roll buttonRoll=Button(self,text="Roll!", command=self.roll) buttonRoll.grid(row=2,column=5)
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())
from tkinter import Tk, DoubleVar, Label, Spinbox from functools import partial def update_label(spinbox, label, var): """ Écrit 'min' ou 'max' dans label en fonction de la valeur du textvariable de spinbox """ value = var.get() if value == spinbox.cget('from'): label.config(text='Min') elif value == spinbox.cget('to'): label.config(text='Max') root = Tk() value = DoubleVar(root) label = Label(text=4) spinbox = Spinbox(root, textvariable=value, from_=4, to=8, increment=0.5) spinbox.config(command=partial(update_label, spinbox, label, value)) spinbox.grid(row=0, column=0) label.grid(row=1, column=0) root.mainloop()
class ResizeAndCompressingWindow: def __init__(self, parent): self.parent = parent self.frame0 = Frame(self.parent) self.title = Label(self.frame0, text='Resize and compressing', font='arial 20') self.BackButton = Button(self.title, text='<< Back', background='#888', foreground='#000', padx='2', pady='0', command=self.parent.init_menu_window) self.frame1 = Frame(self.parent) self.DirectoryLabel = Label(self.frame1, text='Directory', width=6) self.directory = StringVar() self.directory.set(os.getcwd()) self.DirectoryEntry = Entry(self.frame1, textvariable=self.directory) self.BrowseButton = Button( self.frame1, text='Browse', background='#888', foreground='#000', padx='2', pady='0', width='10', command=lambda: self.directory.set( filedialog.askdirectory( parent=self.parent, initialdir=self.directory.get, title='Please select a folder with images:'))) self.frame2 = Frame(self.parent) self.MethodLabel = Label(self.frame2, text='Resizing method') self.method_listbox = Listbox(self.frame2, exportselection=False) methods = ['Scale', 'Fit', 'Cover', 'Thumb'] for method in methods: self.method_listbox.insert('end', method) self.method_listbox.bind('<<ListboxSelect>>', self.on_select) self.frame3 = Frame(self.parent) self.SizeLabelText = StringVar() self.SizeLabelText.set('Change resize method!') self.SizeLabel = Label(self.frame3, textvariable=self.SizeLabelText, justify='left') self.HeightFrame = Frame(self.frame3) self.HeightLabel = Label(self.HeightFrame, justify='left', text='Height:') listvalues = [''] listvalues.extend(range(1, 9999 + 1, 1)) validate_int_val = (self.parent.register(Window.validate_int_val), '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W') self.HeightSpinbox = Spinbox(self.HeightFrame, values=listvalues, state='disabled', validate='all', validatecommand=validate_int_val) self.WidthFrame = Frame(self.frame3) self.WidthLabel = Label(self.WidthFrame, justify='left', text='Width:') self.WidthSpinbox = Spinbox(self.WidthFrame, values=listvalues, state='disabled', validate='all', validatecommand=validate_int_val) self.StartButton = Button( self.frame3, text='Start', background='#888', foreground='#000', padx='2', pady='0', width='10', command=self.start_resize_and_compressing, state='disabled') def show(self): self.frame0.pack(fill='x') self.BackButton.pack(side='left') self.title.pack(fill='x', pady=5, ipady=4) self.frame1.pack(fill='x') self.DirectoryLabel.pack(side='left', padx=5, pady=5) self.DirectoryEntry.pack(side='left', padx=5, expand=True, fill='x') self.BrowseButton.pack(side='left') self.frame2.pack(side='left', padx=3, pady=10) self.MethodLabel.pack() self.method_listbox.pack() self.frame3.pack(fill='x', padx=3, pady=10) self.SizeLabel.pack(fill='x', ipady=10) self.HeightFrame.pack(fill='x') self.HeightLabel.pack(side='left', padx=5) self.HeightSpinbox.pack(side='left', padx=6) self.WidthFrame.pack(fill='x') self.WidthLabel.pack(side='left', padx=5) self.WidthSpinbox.pack(side='left', padx=10) self.StartButton.pack(fill='x', pady=10, ipady=10, side='bottom', expand=True) def on_select(self, event): widget = event.widget selection = widget.curselection() try: value = widget.get(selection[0]) except IndexError: return if value == 'Scale': self.SizeLabelText.set( 'You must provide either a target width or a target height,\nbut not both.' ) else: self.SizeLabelText.set( 'You must provide both a width and a height.') self.HeightSpinbox.config(state='normal') self.WidthSpinbox.config(state='normal') self.StartButton.config(state='normal') def start_resize_and_compressing(self): try: method = self.method_listbox.get( self.method_listbox.curselection()) except TclError: messagebox.showerror('Error!', 'Change resize Method.') return height = self.HeightSpinbox.get() width = self.WidthSpinbox.get() processing_thread = threading.Thread(target=tPNG.start_compressing, args=(self.parent, self.directory.get(), method, height, width)) processing_thread.daemon = True message = 'Start resize and compressing process?\n\nParameters:\nMethod : ' + method if height != '': message += '\nHeight: ' + height if width != '': message += '\nWidth: ' + width if height == '' or width == '': if method != 'Scale': Window.error_message('need_width_and_height') elif height == '' and width == '': Window.error_message('need_width_or_height') elif messagebox.askyesno(title='Start?', message=message): processing_thread.start() elif method == 'Scale': Window.error_message('need_width_or_height') elif messagebox.askyesno(title='Start?', message=message): processing_thread.start()
class NavigationForTableFrame(Frame): ''' This class is responsible for navigation over the table object. Table rows are displayed page by page. This class provides buttons that allow to navigate from page to page. Attributes: table (TableFrame or any object that has attribute nb_rows and implements display_data method): table that should be navigated. goto_spin (Spinbox): Spinbox widget that allows to enter page number and to switch between pages. text_var_nb_pages (StringVar): text variable that shows total number of pages. current_page_str (StringVar): text variable that stores currently displayed page. Args: parent (Tk object): parent for this frame. table (TableFrameWithInputOutputBox): table with multiple pages that will be navigated by this frame. ''' def __init__(self, parent, table, *args, **kw): super().__init__(parent, *args, **kw) self.table = table self.goto_spin = None self.text_var_nb_pages = StringVar() self.current_page_str = StringVar() self.create_widgets() def create_widgets(self): ''' Creates all necessary widgets for navigation. ''' prev_btn = Button(self, text='<<', width=5, command=self.show_prev_page) prev_btn.grid(row=0, column=0, sticky=N, padx=3) next_btn = Button(self, text='>>', width=5, command=self.show_next_page) next_btn.grid(row=0, column=1, sticky=N) goto_lbl = Label(self, text='Go to') goto_lbl.grid(row=0, column=3, sticky=N, padx=5) self.goto_spin = Spinbox(self, width=7, from_=1, to=1, textvariable=self.current_page_str, command=self.on_page_change) self.goto_spin.bind('<Return>', self.on_page_change) self.goto_spin.grid(row=0, column=4, sticky=N, padx=5) nb_pages_lb = Label(self, textvariable=self.text_var_nb_pages) nb_pages_lb.grid(row=0, column=5, sticky=W + N, padx=5) self.reset_navigation() def show_prev_page(self): ''' Displays previous page. This method is called when user presses button '<<'. If the first page is currently displayed and the method is called, then the call to this method is ignored. ''' prev_page_index = int(self.current_page_str.get()) - 1 if prev_page_index > 0: self.current_page_str.set(prev_page_index) self.on_page_change() def show_next_page(self): ''' Displays next page. This method is called when user presses button '>>'. If the last page is currently displayed and the method is called, then the call to this method is ignored. ''' next_page_index = int(self.current_page_str.get()) + 1 if next_page_index <= int(self.goto_spin.cget('to')): self.current_page_str.set(next_page_index) self.on_page_change() def on_page_change(self, *args): ''' Displays a page which number is currently stored in current_page_str. This method is called in show_next_page(), show_prev_page() and when the user enters data and presses Enter. args are supplied by Return event. If the entered value is invalid, then the first page is displayed. If the entered value is zero or negative, then the first page is isplayed. If the entered value is larger than the total number of pages, then the last page is displayed. ''' try: curr_page = int(self.current_page_str.get()) except ValueError: curr_page = 1 self.current_page_str.set(curr_page) max_page = int(self.goto_spin.cget('to')) if curr_page > max_page: curr_page = max_page self.current_page_str.set(curr_page) if curr_page <= 0: curr_page = 1 self.current_page_str.set(curr_page) # second -1 because row indeces start with 0 row_index = calculate_start_row_index(curr_page, self.table.nb_rows) self.table.display_data(row_index) def reset_navigation(self): ''' Resets navigation parameters. Sets current page number to 1 and total number of pages to zero. ''' self.current_page_str.set('1') self.text_var_nb_pages.set('1 pages') self.goto_spin.config(to=1) def set_navigation(self, nb_data_pages, reset_curr_page=True): ''' Sets navigation parameters. Sets current page number to 1 and total number of pages to nb_data_pages. Args: nb_data_pages (int): new value for the total number of pages. reset_curr_page (bool): True is current page must be reset to 1, False otherwise. ''' self.goto_spin.config(to=nb_data_pages) if reset_curr_page: self.current_page_str.set('1') self.text_var_nb_pages.set('{0} pages'.format(nb_data_pages))
class NavigationForTableFrame(Frame): ''' This class is responsible for navigation over the table object. Table rows are displayed page by page. This class provides buttons that allow to navigate from page to page. Attributes: table (TableFrame or any object that has attribute nb_rows and implements display_data method): table that should be navigated. goto_spin (Spinbox): Spinbox widget that allows to enter page number and to switch between pages. text_var_nb_pages (StringVar): text variable that shows total number of pages. current_page_str (StringVar): text variable that stores currently displayed page. Args: parent (Tk object): parent for this frame. table (TableFrameWithInputOutputBox): table with multiple pages that will be navigated by this frame. ''' def __init__(self, parent, table, *args, **kw): super().__init__(parent, *args, **kw) self.table = table self.goto_spin = None self.text_var_nb_pages = StringVar() self.current_page_str = StringVar() self.create_widgets() def create_widgets(self): ''' Creates all necessary widgets for navigation. ''' prev_btn = Button(self, text='<<', width=5, command=self.show_prev_page) prev_btn.grid(row=0, column=0, sticky=N, padx=3) next_btn = Button(self, text='>>', width=5, command=self.show_next_page) next_btn.grid(row=0, column=1, sticky=N) goto_lbl = Label(self, text='Go to') goto_lbl.grid(row=0, column=3, sticky=N, padx=5) self.goto_spin = Spinbox(self, width=7, from_=1, to=1, textvariable=self.current_page_str, command=self.on_page_change) self.goto_spin.bind('<Return>', self.on_page_change) self.goto_spin.grid(row=0, column=4, sticky=N, padx=5) nb_pages_lb = Label(self, textvariable=self.text_var_nb_pages) nb_pages_lb.grid(row=0, column=5, sticky=W+N, padx=5) self.reset_navigation() def show_prev_page(self): ''' Displays previous page. This method is called when user presses button '<<'. If the first page is currently displayed and the method is called, then the call to this method is ignored. ''' prev_page_index = int(self.current_page_str.get()) - 1 if prev_page_index > 0: self.current_page_str.set(prev_page_index) self.on_page_change() def show_next_page(self): ''' Displays next page. This method is called when user presses button '>>'. If the last page is currently displayed and the method is called, then the call to this method is ignored. ''' next_page_index = int(self.current_page_str.get()) + 1 if next_page_index <= int(self.goto_spin.cget('to')): self.current_page_str.set(next_page_index) self.on_page_change() def on_page_change(self, *args): ''' Displays a page which number is currently stored in current_page_str. This method is called in show_next_page(), show_prev_page() and when the user enters data and presses Enter. args are supplied by Return event. If the entered value is invalid, then the first page is displayed. If the entered value is zero or negative, then the first page is isplayed. If the entered value is larger than the total number of pages, then the last page is displayed. ''' try: curr_page = int(self.current_page_str.get()) except ValueError: curr_page = 1 self.current_page_str.set(curr_page) max_page = int(self.goto_spin.cget('to')) if curr_page > max_page: curr_page = max_page self.current_page_str.set(curr_page) if curr_page <= 0: curr_page = 1 self.current_page_str.set(curr_page) # second -1 because row indeces start with 0 row_index = calculate_start_row_index(curr_page, self.table.nb_rows) self.table.display_data(row_index) def reset_navigation(self): ''' Resets navigation parameters. Sets current page number to 1 and total number of pages to zero. ''' self.current_page_str.set('1') self.text_var_nb_pages.set('1 pages') self.goto_spin.config(to=1) def set_navigation(self, nb_data_pages, reset_curr_page=True): ''' Sets navigation parameters. Sets current page number to 1 and total number of pages to nb_data_pages. Args: nb_data_pages (int): new value for the total number of pages. reset_curr_page (bool): True is current page must be reset to 1, False otherwise. ''' self.goto_spin.config(to=nb_data_pages) if reset_curr_page: self.current_page_str.set('1') self.text_var_nb_pages.set('{0} pages'.format(nb_data_pages))
class SettingsFrame(Frame): """ Settings frame class. """ def __init__(self, app, *args, **kwargs): """ Constructor. :param Frame app: reference to main tkinter application :param args: optional args to pass to Frame parent class :param kwargs: optional kwargs to pass to Frame parent class """ 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) self._protocol = IntVar() self._raw = IntVar() self._autoscroll = IntVar() self._maxlines = IntVar() self._webmap = IntVar() self._mapzoom = IntVar() self._units = StringVar() self._format = StringVar() self._datalog = IntVar() self._logformat = StringVar() self._record_track = IntVar() self._show_zerosig = IntVar() self._show_legend = IntVar() self._validsettings = True self._in_filepath = None self._logpath = None self._trackpath = None self._img_conn = ImageTk.PhotoImage(Image.open(ICON_CONN)) self._img_disconn = ImageTk.PhotoImage(Image.open(ICON_DISCONN)) self._img_ubxconfig = ImageTk.PhotoImage(Image.open(ICON_UBXCONFIG)) self._img_dataread = ImageTk.PhotoImage(Image.open(ICON_LOGREAD)) self._body() self._do_layout() self._reset() def _body(self): """ Set up frame and widgets. """ for i in range(4): self.grid_columnconfigure(i, weight=1) self.grid_rowconfigure(0, weight=1) self.option_add("*Font", self.__app.font_sm) # serial port configuration panel self._frm_serial = SerialConfigFrame(self, preselect=KNOWNGPS, timeouts=TIMEOUTS, bpsrates=BPSRATES) # connection buttons self._frm_buttons = Frame(self) self._btn_connect = Button( self._frm_buttons, width=45, height=35, image=self._img_conn, command=lambda: self.__app.serial_handler.connect(), ) self._btn_disconnect = Button( self._frm_buttons, width=45, height=35, image=self._img_disconn, command=lambda: self.__app.serial_handler.disconnect(), state=DISABLED, ) self._btn_connect_file = Button( self._frm_buttons, width=45, height=35, image=self._img_dataread, command=lambda: self._on_data_stream(), ) self._lbl_status_preset = Label(self._frm_buttons, font=self.__app.font_md2, text="") # Other configuration options self._frm_options = Frame(self) self._lbl_protocol = Label(self._frm_options, text=LBLPROTDISP) self._rad_nmea = Radiobutton(self._frm_options, text="NMEA", variable=self._protocol, value=NMEA_PROTOCOL) self._rad_ubx = Radiobutton(self._frm_options, text="UBX", variable=self._protocol, value=UBX_PROTOCOL) self._rad_all = Radiobutton(self._frm_options, text="ALL", variable=self._protocol, value=MIXED_PROTOCOL) self._lbl_consoledisplay = Label(self._frm_options, text=LBLDATADISP) self._rad_parsed = Radiobutton(self._frm_options, text="Parsed", variable=self._raw, value=0) self._rad_raw = Radiobutton(self._frm_options, text="Raw", variable=self._raw, value=1) self._lbl_format = Label(self._frm_options, text="Degrees Format") self._spn_format = Spinbox( self._frm_options, values=(DDD, DMS, DMM), width=6, state=READONLY, readonlybackground=ENTCOL, wrap=True, textvariable=self._format, ) self._lbl_units = Label(self._frm_options, text="Units") self._spn_units = Spinbox( self._frm_options, values=(UMM, UIK, UI, UMK), width=13, state=READONLY, readonlybackground=ENTCOL, wrap=True, textvariable=self._units, ) self._chk_scroll = Checkbutton(self._frm_options, text="Autoscroll", variable=self._autoscroll) self._spn_maxlines = Spinbox( self._frm_options, values=("100", "200", "500", "1000", "2000"), width=6, readonlybackground=ENTCOL, wrap=True, textvariable=self._maxlines, state=READONLY, ) self._chk_webmap = Checkbutton( self._frm_options, text="Web Map Zoom", variable=self._webmap, command=lambda: self._on_webmap(), ) self._scl_mapzoom = Scale( self._frm_options, from_=1, to=20, orient=HORIZONTAL, relief="sunken", bg=ENTCOL, variable=self._mapzoom, ) self._chk_zerosig = Checkbutton(self._frm_options, text=LBLSHOWNULL, variable=self._show_zerosig) self._chk_legend = Checkbutton(self._frm_options, text=LBLLEGEND, variable=self._show_legend) self._chk_datalog = Checkbutton( self._frm_options, text=LBLDATALOG, variable=self._datalog, command=lambda: self._on_data_log(), ) self._spn_datalog = Spinbox( self._frm_options, values=("Raw", "Parsed", "Both"), width=7, readonlybackground=ENTCOL, wrap=True, textvariable=self._logformat, state=READONLY, ) self._chk_recordtrack = Checkbutton( self._frm_options, text=LBLTRACKRECORD, variable=self._record_track, command=lambda: self._on_record_track(), ) self._lbl_ubxconfig = Label(self._frm_options, text=LBLUBXCONFIG) self._btn_ubxconfig = Button( self._frm_options, width=45, height=35, text="UBX", image=self._img_ubxconfig, command=lambda: self._on_ubx_config(), state=DISABLED, ) def _do_layout(self): """ Position widgets in frame. """ self._frm_serial.grid(column=0, row=1, columnspan=4, padx=3, pady=3, sticky=(W, E)) ttk.Separator(self).grid(column=0, row=2, columnspan=4, padx=3, pady=3, sticky=(W, E)) self._frm_buttons.grid(column=0, row=3, columnspan=4, sticky=(W, E)) self._btn_connect.grid(column=0, row=0, padx=3, pady=3) self._btn_connect_file.grid(column=1, row=0, padx=3, pady=3) self._btn_disconnect.grid(column=3, row=0, padx=3, pady=3) ttk.Separator(self).grid(column=0, row=7, columnspan=4, padx=3, pady=3, sticky=(W, E)) self._frm_options.grid(column=0, row=8, columnspan=4, sticky=(W, E)) self._lbl_protocol.grid(column=0, row=0, padx=3, pady=3, sticky=(W)) self._rad_nmea.grid(column=1, row=0, padx=0, pady=0, sticky=(W)) self._rad_ubx.grid(column=2, row=0, padx=0, pady=0, sticky=(W)) self._rad_all.grid(column=3, row=0, padx=0, pady=0, sticky=(W)) self._lbl_consoledisplay.grid(column=0, row=1, padx=2, pady=3, sticky=(W)) self._rad_parsed.grid(column=1, row=1, padx=1, pady=3, sticky=(W)) self._rad_raw.grid(column=2, row=1, padx=2, pady=3, sticky=(W)) self._lbl_format.grid(column=0, row=2, padx=3, pady=3, sticky=(W)) self._spn_format.grid(column=1, row=2, padx=2, pady=3, sticky=(W)) self._lbl_units.grid(column=0, row=3, padx=3, pady=3, sticky=(W)) self._spn_units.grid(column=1, row=3, columnspan=3, padx=2, pady=3, sticky=(W)) self._chk_scroll.grid(column=0, row=4, padx=3, pady=3, sticky=(W)) self._spn_maxlines.grid(column=1, row=4, columnspan=3, padx=3, pady=3, sticky=(W)) self._chk_webmap.grid(column=0, row=5, padx=3, pady=3, sticky=(W)) self._scl_mapzoom.grid(column=1, row=5, columnspan=3, sticky=(W)) self._chk_legend.grid(column=0, row=6, padx=3, pady=3, sticky=(W)) self._chk_zerosig.grid(column=1, row=6, columnspan=2, padx=3, pady=3, sticky=(W)) self._chk_datalog.grid(column=0, row=7, padx=3, pady=3, sticky=(W)) self._spn_datalog.grid(column=1, row=7, padx=3, pady=3, sticky=(W)) self._chk_recordtrack.grid(column=0, row=8, columnspan=2, padx=3, pady=3, sticky=(W)) ttk.Separator(self._frm_options).grid(column=0, row=9, columnspan=4, padx=3, pady=3, sticky=(W, E)) self._lbl_ubxconfig.grid(column=0, row=10, padx=3, pady=3, sticky=(W)) self._btn_ubxconfig.grid(column=1, row=10, padx=3, pady=3, sticky=(W)) def _on_ubx_config(self, *args, **kwargs): # pylint: disable=unused-argument """ Open UBX configuration dialog panel. """ self.__app.ubxconfig() def _on_webmap(self): """ Reset webmap refresh timer """ self.__app.frm_mapview.reset_map_refresh() def _on_data_log(self): """ Start or stop data logger """ if self._datalog.get() == 1: self._logpath = self.__app.file_handler.set_logfile_path() if self._logpath is not None: self.__app.set_status("Data logging enabled: " + self._logpath, "green") else: self._datalog.set(False) else: self._logpath = None self._datalog.set(False) # self.__app.file_handler.close_logfile() self.__app.set_status("Data logging disabled", "blue") def _on_record_track(self): """ Start or stop track recorder """ if self._record_track.get() == 1: self._trackpath = self.__app.file_handler.set_trackfile_path() if self._trackpath is not None: self.__app.set_status( "Track recording enabled: " + self._trackpath, "green") else: self._record_track.set(False) else: self._trackpath = None self._record_track.set(False) # self.__app.file_handler.close_trackfile() self.__app.set_status("Track recording disabled", "blue") def _on_data_stream(self): """ Start data file streamer """ self._in_filepath = self.__app.file_handler.open_infile() if self._in_filepath is not None: self.__app.set_status("") self.__app.serial_handler.connect_file() def _reset(self): """ Reset settings to defaults. """ self._protocol.set(MIXED_PROTOCOL) self._format.set(DDD) self._units.set(UMM) self._autoscroll.set(1) self._maxlines.set(300) self._raw.set(False) self._webmap.set(False) self._mapzoom.set(10) self._show_legend.set(True) self._show_zerosig.set(False) self._datalog.set(False) self._record_track.set(False) def enable_controls(self, status: int): """ Public method to enable and disable those controls which depend on connection status. :param int status: connection status as integer (0=Disconnected, 1=Connected to serial, 2=Connected to file, 3=No serial ports available) """ self._frm_serial.set_status(status) self._btn_connect.config( state=(DISABLED if status in (CONNECTED, CONNECTED_FILE, NOPORTS) else NORMAL)) self._btn_disconnect.config( state=(DISABLED if status in (DISCONNECTED, NOPORTS) else NORMAL)) self._chk_datalog.config( state=(DISABLED if status in (CONNECTED, CONNECTED_FILE, NOPORTS) else NORMAL)) self._spn_datalog.config( state=(DISABLED if status in (CONNECTED, CONNECTED_FILE, NOPORTS) else READONLY)) self._chk_recordtrack.config( state=(DISABLED if status in (CONNECTED, CONNECTED_FILE) else NORMAL)) self._btn_connect_file.config( state=(DISABLED if status in (CONNECTED, CONNECTED_FILE) else NORMAL)) self._btn_ubxconfig.config( state=(DISABLED if status in (DISCONNECTED, CONNECTED_FILE, NOPORTS) else NORMAL)) self.__app.menu.options_menu.entryconfig( 0, state=(DISABLED if status in (CONNECTED_FILE, DISCONNECTED, NOPORTS) else NORMAL), ) def get_size(self) -> (int, int): """ Get current frame size. :return: (width, height) :rtype: tuple """ self.update_idletasks() # Make sure we know about any resizing return (self.winfo_width(), self.winfo_height()) def serial_settings(self) -> Frame: """ Return reference to common serial configuration panel :return: reference to serial form :rtype: Frame """ return self._frm_serial @property def protocol(self) -> int: """ Getter for displayed protocols :return: protocol displayed (0=NMEA, 1=UBX, 2=BOTH) :rtype: int """ return self._protocol.get() @property def raw(self) -> int: """ Getter for console display format :return: display format (0 - parsed, 1 = raw) :rtype: int """ return self._raw.get() @property def autoscroll(self) -> int: """ Getter for autoscroll flag :return: scroll setting (0 = no scroll, 1 = auto) :rtype: int """ return self._autoscroll.get() @property def maxlines(self) -> int: """ Getter for max console display lines :return: max lines in console display (default=300) :rtype: int """ return self._maxlines.get() @property def webmap(self) -> int: """ Getter for webmap flag :return: map type (0 = static map, 1 = dynamic web map) :rtype: int """ return self._webmap.get() @property def mapzoom(self) -> int: """ Getter for webmap zoom level :return: webmap zoom level (1-20) :rtype: int """ return self._mapzoom.get() @property def units(self) -> int: """ Getter for display units :return: "UMM" = metric m/s, "UMK" = metric kmph, "UI" = imperial mph, "UIK" = imperial knots :rtype: int """ return self._units.get() @property def format(self) -> str: """ Getter for degrees format :return: "DD.D" = decimal degrees, "DM.M" = degrees, decimal minutes, "D.M.S" = degrees, minutes, seconds :rtype: str """ return self._format.get() @property def infilepath(self) -> str: """ Getter for input file path :return: input file path :rtype: str """ return self._in_filepath @property def outfilepath(self) -> str: """ Getter for output file path :return: output file path :rtype: str """ return self._logpath @property def datalogging(self) -> int: """ Getter for datalogging flag :return: 0 = no log, 1 = record datalog :rtype: int """ return self._datalog.get() @property def logformat(self) -> str: """ Getter for datalogging format :return: "Raw", "Parsed", "Both" :rtype: str """ return self._logformat.get() @property def record_track(self) -> int: """ Getter for record track flag :return: 0 = no track, 1 = record track :rtype: int """ return self._record_track.get() @property def show_zero(self) -> int: """ Getter for zero signal flag :return: 0 = exclude, 1 = include :rtype: int """ return self._show_zerosig.get() @property def show_legend(self) -> int: """ Getter for graph legend flag :return: 0 = hide, 1 = show :rtype: int """ return self._show_legend.get()
class Application(Frame): def __init__(self, master=None): """ Main GUI.""" Frame.__init__(self, master) Frame.grid(self, padx=(40, 40), pady=(10, 10)) self.path1 = StringVar() path1_lbl = ttk.Label(self, text='Path:') path1_lbl.grid(column=1, columnspan=4, row=1, sticky=W) path1_entry = ttk.Entry(self, width=30, textvariable=self.path1) path1_entry.grid(column=1, columnspan=4, row=2, sticky=(W, E)) path1_btn = ttk.Button(self, text="Browse", command=self.open1) path1_btn.grid(column=1, row=3, sticky=W, padx=(0, 0)) self.graph1_btn = ttk.Button(self, text="Graph", state=DISABLED, command=lambda: self.graph1(self.C, 1)) self.graph1_btn.grid(column=2, row=3, sticky=W) self.info1_lbl = ttk.Label(self, text='Scan Info/Comments:') self.info1_lbl.grid(column=1, columnspan=4, row=5, sticky=W, pady=(10, 0)) self.info1_Entry = Text(self, width=30, height=12) self.info1_Entry.grid(column=1, columnspan=4, row=6, sticky=(N, W, E)) in_C = StringVar() self.input_entry = ttk.Entry(self, width=10, textvariable=in_C) self.input_entry.grid(column=4, row=3, sticky=(W, E)) self.int_btn = ttk.Button(self, text="Input Array", command=lambda: self.Input_C()) self.int_btn.grid(column=4, row=5, sticky=W) self.int_lbl = ttk.Label(self, text="Inverse Distance " "Weighting Interpolation", font='bold') self.int_lbl.grid(column=1, columnspan=4, row=7, sticky=W, pady=(10, 2)) self.int_btn = ttk.Button(self, text="Interpolate", state=DISABLED, command=lambda: self.interpolation(self.C)) self.int_btn.grid(column=1, row=8, sticky=W) self.NP1 = IntVar() self.NP1.set(5) n_lbl = ttk.Label(self, text='No. pts') n_lbl.grid(column=1, row=9, sticky=(N, W)) self.n_box = Spinbox(self, format='%.0f', from_=0, to=self.NP1.get(), width=5, increment=1) #1E10 self.n_box.grid(column=1, row=10, sticky=(N, W)) self.n_box.insert(1, 5) p_lbl = ttk.Label(self, text='Power') p_lbl.grid(column=2, row=9, sticky=(N, W)) self.p_box = Spinbox(self, format='%.0f', from_=0, to=1E10, width=5, increment=1) self.p_box.grid(column=2, row=10, sticky=(N, W)) self.p_box.insert(1, 2) self.transpose_chk = IntVar() self.trans_btn = Checkbutton(self, text="Tranpose", variable=self.transpose_chk, state=DISABLED, command=lambda: self.check_tr(self.C)) self.trans_btn.grid(column=3, row=10, sticky=(N, W)) self.Refl_x = IntVar() self.Refl_x.set(1) self.Refl_x_btn = Checkbutton(self, text="Reflect_x", variable=self.Refl_x, state=DISABLED, command=lambda: self.check_tr(self.C)) self.Refl_x_btn.grid(column=3, row=9, sticky=(N, W)) self.info1_Entry.insert(END, "Reflect x = %s" % (self.Refl_x.get())) self.N_out_btn = ttk.Button(self, text="Save-Grid", state=DISABLED, command=lambda: self.N_out(self.N)) self.N_out_btn.grid(column=1, row=12, sticky=W) self.M_out_btn = ttk.Button(self, text="Save-xyz", state=DISABLED, command=lambda: self.N_out(self.M)) self.M_out_btn.grid(column=2, row=12, sticky=W) self.plot_btn = ttk.Button(self, text="Plot", state=DISABLED, command=lambda: self.plot(self.C, self.N)) self.plot_btn.grid(column=3, row=12, sticky=(N, W)) # Default values for the interpolated grid self.x01_ = StringVar() self.y01_ = StringVar() self.x01_.set(0.600001) #default self.y01_.set(0.600001) #default self.dx1_ = DoubleVar() # from file self.dy1_ = DoubleVar() # from file self.y02_ = StringVar() self.x02_ = StringVar() self.x02_.set(0.60) #default self.y02_.set(0.60) #default self.dx2_ = StringVar() self.dy2_ = StringVar() self.dx2_.set(0.5) #default self.dy2_.set(0.5) #default self.np_x2_ = StringVar() self.np_y2_ = StringVar() self.np_x2_.set(13) #default self.np_y2_.set(13) #default self.grid2_lbl = ttk.Label(self, text="Interpolated Grid") self.grid2_lbl.grid(column=1, columnspan=4, row=22, sticky=(W, E), pady=(5, 2)) x01_entry = ttk.Entry(self, width=6, textvariable=self.x01_) x01_entry.grid(column=2, row=17, sticky=W) x01_lbl = ttk.Label(self, text='x0') x01_lbl.grid(column=1, row=17, sticky=(N, W), padx=(40, 0)) y01_entry = ttk.Entry(self, width=6, textvariable=self.y01_) y01_entry.grid(column=4, row=17, sticky=W) y01_lbl = ttk.Label(self, text='y0') y01_lbl.grid(column=3, row=17, sticky=(N, W), padx=(40, 0)) dx1_entry = ttk.Entry(self, width=6, textvariable=self.dx1_) dx1_entry.grid(column=2, row=18, sticky=W) dx1_lbl = ttk.Label(self, text='dx1') dx1_lbl.grid(column=1, row=18, sticky=(N, W), padx=(40, 0)) dy1_entry = ttk.Entry(self, width=6, textvariable=self.dy1_) dy1_entry.grid(column=4, row=18, sticky=W) dy1_lbl = ttk.Label(self, text='dy1') dy1_lbl.grid(column=3, row=18, sticky=(N, W), padx=(40, 0)) x02_entry = ttk.Entry(self, width=6, textvariable=self.x02_) x02_entry.grid(column=2, row=23, sticky=W) x02_lbl = ttk.Label(self, text='x0 (Int)') x02_lbl.grid(column=1, row=23, sticky=(N, W), padx=(40, 0)) y02_entry = ttk.Entry(self, width=6, textvariable=self.y02_) y02_entry.grid(column=4, row=23, sticky=W) y02_lbl = ttk.Label(self, text='y0 (Int)') y02_lbl.grid(column=3, row=23, sticky=(N, W), padx=(40, 0)) dx2_entry = ttk.Entry(self, width=6, textvariable=self.dx2_) dx2_entry.grid(column=2, row=24, sticky=W) dx2_lbl = ttk.Label(self, text='dx2') dx2_lbl.grid(column=1, row=24, sticky=(N, W), padx=(40, 0)) dy2_entry = ttk.Entry(self, width=6, textvariable=self.dy2_) dy2_entry.grid(column=4, row=24, sticky=W) dy2_lbl = ttk.Label(self, text='dy2') dy2_lbl.grid(column=3, row=24, sticky=(N, W), padx=(40, 0)) np_x2_entry = ttk.Entry(self, width=6, textvariable=self.np_x2_) np_x2_entry.grid(column=2, row=25, sticky=W) np_x2_lbl = ttk.Label(self, text='np_x2') np_x2_lbl.grid(column=1, row=25, sticky=(N, W), padx=(40, 0)) np_y2_entry = ttk.Entry(self, width=6, textvariable=self.np_y2_) np_y2_entry.grid(column=4, row=25, sticky=W) np_y2_lbl = ttk.Label(self, text='np_y2') np_y2_lbl.grid(column=3, row=25, sticky=(N, W), padx=(40, 0)) self.tipwf = DoubleVar() self.tipwf.set(4220) self.tip = IntVar() self.tip_btn = Checkbutton(self, text="Tip correction (mV)", variable=self.tip, state=DISABLED, command=lambda: self.workfunction(self.C)) self.tip_btn.grid(column=3, columnspan=2, row=26, sticky=(N, W), pady=(15, 0)) self.tip_entry = ttk.Entry(self, width=6, textvariable=self.tipwf) self.tip_entry.grid(column=2, row=26, sticky=E, pady=(15, 0)) minmax_lbl = ttk.Label(self, text='Min and Max x/y') minmax_lbl.grid(column=2, columnspan=3, row=19, sticky=(N, W)) self.xi = IntVar() self.xi.set(0) self.xf = IntVar() self.xf.set(0) xdata_lbl = ttk.Label(self, text='x-data_subset') xdata_lbl.grid(column=1, row=20, sticky=(N, W)) self.xidata_box = Spinbox(self, format='%.0f', from_=0, to=self.xf.get(), width=5, increment=1) self.xidata_box.grid(column=2, row=20, sticky=(N, W), padx=(15, 0)) self.xidata_box.insert(1, 0) self.xfdata_box = Spinbox(self, format='%.0f', from_=0, to=self.xf.get(), width=5, increment=1) self.xfdata_box.grid(column=3, row=20, sticky=(N, W)) self.xfdata_box.insert(1, 0) self.yi = IntVar() self.yi.set(0) self.yf = IntVar() self.yf.set(0) ydata_lbl = ttk.Label(self, text='y-data_subset') ydata_lbl.grid(column=1, row=21, sticky=(N, W)) self.yidata_box = Spinbox(self, format='%.0f', from_=0, to=self.yf.get(), width=5, increment=1) self.yidata_box.grid(column=2, row=21, sticky=(N, W), padx=(15, 0)) self.yidata_box.insert(1, 0) self.yfdata_box = Spinbox(self, format='%.0f', from_=0, to=self.yf.get(), width=5, increment=1) self.yfdata_box.grid(column=3, row=21, sticky=(N, W)) self.yfdata_box.insert(1, 0) def enable_btn(self): self.graph1_btn.config(state='ENABLED') self.int_btn.config(state='ENABLED') self.trans_btn.config(state='normal') self.Refl_x_btn.config(state='normal') self.N_out_btn.config(state='ENABLED') self.M_out_btn.config(state='ENABLED') self.tip_btn.config(state='normal') def Input_C(self): """"Loads tab-delimited data from the corresponding text-box""" A = self.input_entry.get() self.info1_Entry.delete(1.0, END) B = [] reader = csv.reader(A.split('\n'), delimiter='\t') for row in reader: row = row[:] B.append(row) B = B[0:len(B) - 1][0:len(B[0])] for i in range(0, len(B)): for j in range(0, len(B[i])): B[i][j] = float(B[i][j]) B = asarray(B) print(B) self.dx1_.set(0.18) self.dy1_.set(0.18) self.NP1.set(len(B[0]) * len(B) - 1) self.n_box.config(to=self.NP1.get()) self.xf.set(len(B[0])) self.xfdata_box.delete(0, "end") self.xfdata_box.insert(1, self.xf.get()) self.xidata_box.config(to=self.xf.get()) self.xfdata_box.config(to=self.xf.get()) self.yf.set(len(B)) self.yfdata_box.delete(0, "end") self.yfdata_box.insert(1, self.yf.get()) self.yidata_box.config(to=self.yf.get()) self.yfdata_box.config(to=self.yf.get()) self.C = B self.enable_btn() self.graph1(B, 1) return self.C def open1(self): """"Loads data from file and displays footer information""" fileName = filedialog.askopenfilename(title="Open CPD file") try: f = open(fileName, 'r') except IOError: pass i = f.readline().strip() if i == "Work Function data": pass else: i = messagebox.askyesno(title="Open file?", message="CPD file header not present!\n" "Proceed to open file?", default='no') if i == 1: pass else: pass self.path1.set(fileName) g = f.read() f.close() # Only CPD data is loaded but there are other measurements Tracking = g.find('Tracking') Grad = g.find('Grad') # Time = g.find('Time') # User = g.find('User') Footer = g.find('/') - 2 # Footer = Footer - 2 CPD_data = g[0:Tracking] # Tracking_data = g[Tracking:Grad] # Grad_data = g[Grad:Time] # Time_data = g[Time:User] # User_data = g[User:Footer] Footer_data = g[Footer:] a = Footer_data.split("\n") Date = a[0] Grad = [int(i) for i in a[-10].split() if i.isdigit()] DAS_Averages = [int(i) for i in a[-18].split() if i.isdigit()] WF_Averages = [int(i) for i in a[-14].split() if i.isdigit()] Xpoints = [int(i) for i in a[-5].split() if i.isdigit()] Ypoints = [int(i) for i in a[-4].split() if i.isdigit()] Xsteps = [int(i) for i in a[-3].split() if i.isdigit()] Ysteps = [int(i) for i in a[-2].split() if i.isdigit()] Xstepscm = Xsteps[0] * 0.0015 #xyscale Ystepscm = Ysteps[0] * 0.0015 # C is the array used for the raw data C = [] reader = csv.reader(CPD_data.split('\n'), delimiter=',') for row in reader: row = row[:-1] C.append(row) C = C[0:len(C) - 1][0:len(C[0])] for i in range(0, len(C)): for j in range(0, len(C[i])): C[i][j] = float(C[i][j]) C = asarray(C) # Clear the textbox before putting in data for new file self.info1_Entry.delete(1.0, END) info_0 = "%s\n%s\n" % (fileName, Date) info_1 = ("Xpoints = %s\nYpoints = %s\nXsteps = %s (%s cm)\n" "Ysteps= %s (%s cm)" \ % (Xpoints[0], Ypoints[0], Xsteps[0], Xstepscm, Ysteps[0], Ystepscm)) info_2 = "\nDAS_Aves = %s\nWF_Averages = %s\nGrad = %s"\ % (DAS_Averages[0],WF_Averages[0],Grad[0]) self.info1_Entry.insert(END, info_0) self.info1_Entry.insert(END, info_1) self.info1_Entry.insert(END, info_2) if self.Refl_x.get() == 1: info_3 = "\nReflect x = %s" % (self.Refl_x.get()) self.info1_Entry.insert(END, info_3) if self.transpose_chk.get() == 1: info_4 = "\nTranspose = %s" % (self.transpose_chk.get()) self.info1_Entry.insert(END, info_4) self.enable_btn() # To prevent divide by 0 issue 1E-8 is added if Xpoints[0] == len(C[0]): self.dx1_.set(Xstepscm + 1E-8) self.dy1_.set(Ystepscm + 1E-8) else: self.dy1_.set(Xstepscm + 1E-8) self.dx1_.set(Ystepscm + 1E-8) self.NP1.set(len(C[0]) * len(C) - 1) self.n_box.config(to=self.NP1.get()) self.xf.set(len(C[0])) self.xfdata_box.delete(0, "end") self.xfdata_box.insert(1, self.xf.get()) self.xidata_box.config(to=self.xf.get()) self.xfdata_box.config(to=self.xf.get()) self.yf.set(len(C)) self.yfdata_box.delete(0, "end") self.yfdata_box.insert(1, self.yf.get()) self.yidata_box.config(to=self.yf.get()) self.yfdata_box.config(to=self.yf.get()) self.tip.set(0) self.C = C self.Cr = C return self.C, self.Cr def graph1(self, data, row_a): """Graphs the raw CPD data""" plt.close() plt.figure(figsize=(3.5, 3.5), dpi=100, frameon=False) im = plt.imshow(data, cmap='jet') plt.colorbar(im, orientation='vertical', fraction=0.046, pad=0.05) plt.tight_layout() plt.savefig(path.join(tmpdir, im_name1), dpi=100, bbox_inches='tight') c = Canvas(self, width=350, height=350, bg='white') c.grid(row=row_a, column=5, columnspan=2, rowspan=50, sticky=(W, N), padx=50) c.background = PhotoImage(file=path.join(tmpdir, im_name1)) c.create_image(1, 20, image=c.background, anchor=NW) def interpolation(self, C): """Performs inverse distance interpolation""" temp = [] for j in range(int(self.yidata_box.get()), int(self.yfdata_box.get())): temp.append([]) for i in range(int(self.xidata_box.get()), int(self.xfdata_box.get())): temp[j - int(self.yidata_box.get())].append(C[j, i]) # Sub-array of raw data defined by the min and max x/y value C = temp C = asarray(C) n = self.n_box.get() n = int(n) p = self.p_box.get() p = int(p) x01 = float(self.x01_.get()) y01 = float(self.y01_.get()) dx1 = float(self.dx1_.get()) dy1 = float(self.dy1_.get()) y02 = float(self.y02_.get()) x02 = float(self.x02_.get()) dx2 = float(self.dx2_.get()) dy2 = float(self.dy2_.get()) np_x2 = int(self.np_x2_.get()) np_y2 = int(self.np_y2_.get()) if self.transpose_chk.get() == 1: C = transpose(C) # Define the dimensions of the raw data grid np_x1 = len(C[0]) np_y1 = len(C) NP1 = np_x1 * np_y1 x1 = ones(np_x1) for i in range(0, np_x1): x1[i] = x01 + dx1 * i y1 = ones(np_y1) for i in range(0, np_y1): y1[i] = y01 + dy1 * i if self.Refl_x.get() == 1: x1_ = ones(np_x1) for i in range(0, len(x1)): x1_[i] = x1[-1 - i] x1 = x1_ data_1d = C.flatten() # Define the dimensions of interpolated data grid NP2 = np_x2 * np_y2 x2 = ones(np_x2) for i in range(0, np_x2): x2[i] = x02 + dx2 * i y2 = ones(np_y2) for i in range(0, np_y2): y2[i] = y02 + dy2 * i # Intperolation calculation k2 = 0 int_data = ones(NP2) dist = [0] * (NP1) index = [0] * (NP1) for j2 in range(0, np_y2): for i2 in range(0, np_x2): dist_2d = [] dist_1d = [] for j in range(0, np_y1): dist_2d.append([]) for i in range(0, np_x1): dist_2d[j].append( sqrt((x2[i2] - x1[i])**2 + (y2[j2] - y1[j])**2)) dist_1d.append( sqrt((x2[i2] - x1[i])**2 + (y2[j2] - y1[j])**2)) index = sorted(range(len(dist_1d)), key=lambda x: dist_1d[x]) dist = sorted(dist_1d) up = min(n, NP1) temp = 0 lamb = ones(up) if dist[0] > 0: for i in range(0, up): lamb[i] = (1/(dist[i]**p))\ /sum(ones(up)/power_(dist[0:up],p)) temp = temp + data_1d[index[i]] * lamb[i] else: temp = data_1d[index[i]] int_data[k2] = temp k2 = k2 + 1 M1 = [] N = [] k2 = 0 for j2 in range(0, np_y2): N.append([]) for i2 in range(0, np_x2): M1.append([x02 + i2 * dx2, y02 + j2 * dy2, int_data[k2]]) N[j2].append(int_data[k2]) k2 = k2 + 1 M1 = asarray(M1) N = asarray(N) # Generate a xyz equivalent array if np_x2 == np_y2: Mt = [] for j2 in range(0, np_y2): for i2 in range(0, np_x2): Mt.append([y02 + j2 * dy2, x02 + i2 * dx2, N[i2, j2]]) k2 = k2 + 1 M = append(Mt, M1, axis=1) else: M = M1 self.N = N self.M1 = M1 self.M = M self.graph1(self.N, 8) self.plot_btn.config(state='ENABLED') return (self.N, self.M1, self.M) def check_tr(self, C): self.info1_Entry.delete(10.0, END) if self.Refl_x.get() == 1: info_3 = "\nReflect x = %s" % (self.Refl_x.get()) self.info1_Entry.insert(END, info_3) if self.transpose_chk.get() == 1: info_4 = "\nTranspose = %s" % (self.transpose_chk.get()) self.info1_Entry.insert(END, info_4) self.interpolation(C) def plot(self, C, N): """Produces images of the raw and interpolated data plots""" plt.close('all') fig_ext = plt.figure(dpi=200) ax1 = fig_ext.add_subplot(121) ax1_im = plt.imshow(C, vmin=amin([amin(C), amin(N)]), vmax=amax([amax(C), amax(N)]), cmap='jet') cbar = plt.colorbar(ax1_im, orientation='vertical', fraction=0.046, pad=0.05) # aspect='auto') if self.tip.get() == 1: cbar.set_label('Work Function (meV)') else: cbar.set_label('CPD (mV)') plt.xlabel('x-axis') plt.ylabel('y-axis') ax2 = fig_ext.add_subplot(122) ax2_im = plt.imshow(N, vmin=amin([amin(C), amin(N)]), vmax=amax([amax(C), amax(N)]), cmap='jet') cbar = plt.colorbar(ax2_im, orientation='vertical', fraction=0.046, pad=0.05) #, aspect='auto') if self.tip.get() == 1: cbar.set_label('Work Function (meV)') else: cbar.set_label('CPD (mV)') plt.xlabel('x-axis') plt.ylabel('y-axis') plt.tight_layout() fig_ext = plt.gcf() plt.show() def N_out(self, N): """Exports the data as a csv file via dialogue box""" file_opt = options = {} options['filetypes'] = [('all files', '.*'), ('CSV (Comma Delimited)', '.csv')] options['initialfile'] = '.csv' options['title'] = 'Save Array as CSV' try: fo1 = filedialog.asksaveasfile(mode='wb', **file_opt) savetxt(fo1, N, delimiter=',', footer=self.info1_Entry.get(1.0, END)) fo1.close() except IOError: messagebox.showinfo(title="Output file", message="Output file issue") def workfunction(self, C): """Applies linear offset to CPD, useful for correcing for the tip's workfunction and converting CPD into workfunction""" if self.tip.get() == 1: self.C = C + float(self.tipwf.get()) self.tip_entry.config(state='disabled') else: self.C = (C - float(self.tipwf.get())) self.tip_entry.config(state="normal") self.graph1(self.C, 1) return self.C
def Spinbox(root, **options): s = TKSpinbox(root) s.config(**options) s.pack()
class MyGUI(): def __init__(self, root, frame): self.root = root self.root.title("ClockPy") #self.root.resizable(0,0) self.root.maxsize(width=385, height=550) self.root.minsize(width=385, height=550) self.root.iconbitmap("./icons/clock.ico") self.frame = frame # ----------- Function Refresh Clock ----------- def tick(): time_string = time.strftime("%I:%M") time_string2 = time.strftime(":%S") time_day = time.strftime("%a, %d %B") time_m = time.strftime("%p") self.clock.config(text=time_string) self.clock_s.config(text=time_string2) self.clock_d.config(text=time_day) self.clock_m.config(text=time_m) self.clock.after(200, tick) # ----------- Function DataBASE ----------- #Load database db_name = 'database.db' # Operation database query = 'SELECT * FROM color' query_alarm = 'SELECT * FROM alarm' query2 = 'UPDATE color SET hexa=?' query_alarm2 = 'UPDATE alarm SET state=?' query_alarm3 = 'UPDATE alarm SET hours=?, minutes=?, meridiam=?' # Database Consult Update def db_query(query, parameters=(), alarm=None): with sqlite3.connect(db_name) as conn: cursor = conn.cursor() result = cursor.execute(query, parameters) conn.commit() if (parameters == ()): if (alarm == None): for row in result: return row[1] else: for row in result: return row[1:5] hexa_c = db_query(query) self.frame.config(width="385", height="550", bg=hexa_c) # ----------- Function Check Status Alarm ----------- def check_alarm(): self.data_alarm_check = db_query(query_alarm, alarm="Y") time_check_h = time.strftime("%I") time_check_m = time.strftime("%M") time_check_mr = time.strftime("%p") time_check_s = time.strftime("%S") if (self.data_alarm_check[0] < 10): hours_check = "0" + str(self.data_alarm_check[0]) else: hours_check = str(self.data_alarm_check[0]) if (self.data_alarm_check[1] < 10): minutes_check = "0" + str(self.data_alarm_check[1]) else: minutes_check = str(self.data_alarm_check[1]) # Check Alarm and playsound if (self.data_alarm_check[3] == "on"): if (time_check_s == "00"): if (time_check_h == hours_check): if (time_check_m == minutes_check): if (time_check_mr == self.data_alarm_check[2]): playsound("./sound/alarm_sound.mp3") self.root.deiconify() self.root.focus_set() self.root.after(1000, check_alarm) # ----------- Windows Clock Alarm ----------- def windows(): hexa_c = db_query(query) self.main_wn = Toplevel(self.root, takefocus=True, bg=hexa_c) self.main_wn.focus_force() self.main_wn.title("ClockPy Alarm") self.main_wn.geometry("320x158") self.main_wn.resizable(0, 0) self.main_wn.iconbitmap("./icons/clock.ico") self.main_wn.grab_set() self.date_alarm = db_query(query_alarm, alarm="Y") self.img_on = PhotoImage(file="./icons/on.png") self.img_off = PhotoImage(file="./icons/off.png") self.img_menu = PhotoImage(file="./icons/menu.png") self.switch = self.date_alarm[3] def check_state_alarm(): if (self.date_alarm[0] < 10): self.lb_hours.config(text="0" + str(self.date_alarm[0])) else: self.lb_hours.config(text=self.date_alarm[0]) if (self.date_alarm[1] < 10): self.lb_minutes.config(text=":0" + str(self.date_alarm[1])) else: self.lb_minutes.config(text=":" + str(self.date_alarm[1])) self.lb_meridiam.config(text=self.date_alarm[2]) if (self.switch == "on"): self.bt_switch.config(image=self.img_on) else: self.bt_switch.config(image=self.img_off) def change_switch(): if (self.switch == "off"): self.bt_switch.config(image=self.img_on) self.switch = "on" db_query(query_alarm2, ("on", )) else: self.bt_switch.config(image=self.img_off) self.switch = "off" db_query(query_alarm2, ("off", )) self.space_alarm = Frame(self.main_wn, width=300, height=100, bg="white") self.space_alarm.place(x=10, y=20) self.lb_hours = Label(self.space_alarm, font=("Roboto Light", 54), bg="white") self.lb_hours.place(x=10, y=0) self.lb_minutes = Label(self.space_alarm, font=("Roboto Light", 54), bg="white") self.lb_minutes.place(x=90, y=0) self.lb_meridiam = Label(self.space_alarm, font=("Roboto Light", 14), bg="white") self.lb_meridiam.place(x=190, y=15) self.bt_switch = Button(self.space_alarm, activebackground="white", command=lambda: change_switch()) self.bt_switch.config(bg="white", bd=0, highlightthickness=0, relief='flat') self.bt_switch.place(x=245, y=10) self.bt_config_alarm = Button(self.space_alarm, image=self.img_menu, activebackground="white") self.bt_config_alarm.config(bg="white", bd=0, highlightthickness=0, relief='flat', command=lambda: setting_alarm()) self.bt_config_alarm.place(x=250, y=55) check_state_alarm() # ----------- Windows Settings Alarm ----------- def setting_alarm(): self.settings_wn = Toplevel(self.main_wn, bg=hexa_c, takefocus=True) self.settings_wn.focus_force() self.settings_wn.geometry("470x165") self.settings_wn.iconbitmap("./icons/clock.ico") self.settings_wn.grab_set() self.settings_wn.resizable(0, 0) self.settings_wn.title("ClockPy Alarm") self.space_alarm2 = Frame(self.settings_wn, width=450, height=100, bg="white") self.space_alarm2.place(x=10, y=20) self.select_hours = Spinbox(self.space_alarm2, from_=1, to=12, width=2, font=("Roboto Light", 50), bd=0, relief='flat', activebackground="white", textvariable=2, state="readonly") self.select_hours.config(buttondownrelief="flat", readonlybackground="white") self.select_hours.place(x=10, y=5) self.select_minutes = Spinbox(self.space_alarm2, from_=00, to=59, format="%02.0f", width=2, font=("Roboto Light", 50), bd=0, relief='flat', activebackground="white") self.select_minutes.config(buttondownrelief="flat", readonlybackground="white", state="readonly") self.select_minutes.place(x=150, y=5) self.select_meridiam = Spinbox(self.space_alarm2, values=("AM", "PM"), width=3, font=("Roboto Light", 50), bd=0, relief='flat', activebackground="white") self.select_meridiam.config(buttondownrelief="flat", readonlybackground="white", state="readonly") self.select_meridiam.place(x=285, y=5) self.bt_save_sttg = Button(self.settings_wn, text="Save", font=("Roboto Light", 12), bd=0, relief="flat", bg="white", command=lambda: save_sttg()) self.bt_save_sttg.place(x=415, y=125) def save_sttg(): h = self.select_hours.get() m = self.select_minutes.get() md = self.select_meridiam.get() db_query(query_alarm3, ( h, m, md, )) self.date_alarm = db_query(query_alarm, alarm="Y") check_state_alarm() self.settings_wn.destroy() # ----------- Function Change Color ----------- def change_color(): rgb, hexa = askcolor() self.frame.config(bg=hexa) self.clock.config(bg=hexa) self.clock_s.config(bg=hexa) self.clock_m.config(bg=hexa) self.clock_d.config(bg=hexa) self.button1.config(bg=hexa, activebackground=hexa) self.button2.config(bg=hexa, activebackground=hexa) #self.lb.config(bg=hexa) # Update Value color database if (hexa != None): db_query(query2, (hexa, )) # ----------- Clock Configure ----------- # Clock Hours Minutes self.clock = Label(self.frame, font=("Roboto Light", 64), bg=hexa_c, foreground="white") self.clock.place(x=65, y=150) # Clock Seconds self.clock_s = Label(self.frame, font=("Roboto Light", 22), bg=hexa_c, foreground="white") self.clock_s.place(x=272, y=200) # Clock Meridiem self.clock_m = Label(self.frame, font=("Roboto Light", 22), bg=hexa_c, foreground="white") self.clock_m.place(x=272, y=165) # Day Month self.clock_d = Label(self.frame, font=("Roboto Light", 14), bg=hexa_c, foreground="white") self.clock_d.place(x=80, y=240) tick() check_alarm() # ----------- Button Change Color ----------- self.img = PhotoImage(file="./icons/color.png") self.img2 = PhotoImage(file="./icons/alarm.png") # Button Pallete Colors self.button1 = Button(self.frame, image=self.img, activebackground=hexa_c, command=lambda: change_color()) self.button1.config(bg=hexa_c, bd=0, highlightthickness=0, relief='flat') self.button1.place(x=5, y=505) # Button Settings self.button2 = Button(self.frame, image=self.img2, activebackground=hexa_c, command=lambda: windows()) self.button2.config(bg=hexa_c, bd=0, highlightthickness=0, relief='flat') self.button2.place(x=340, y=505) self.frame.pack()
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()
class Interface: """ GUI class """ def __init__(self, master): # colour swatches self.gray1 = "#f6f6f6" self.gray2 = "#eaeaea" self.gray3 = "#d9d9d9" # key parameters self.running = False self.sect_width = 360 self.rb_choice = StringVar() self.dob1_val = StringVar() self.dob2_val = StringVar() self.df_records = StringVar() master.geometry("800x600+200+200") master.title("Red Snapper") master.resizable(False, False) master.configure(background=self.gray1) # LEFT SECTION LAYER # -------------------------------------------------------------------- self.sect_left = Frame(master) self.sect_left.place(x=15, y=15, width=self.sect_width, height=570) self.sect_left.config(relief=RIDGE) self.sect_left.config(background=self.gray2) # RIGHT SECTION LAYER # -------------------------------------------------------------------- self.sect_right = Frame(master) self.sect_right.place(x=-15, y=200, width=self.sect_width, height=385) self.sect_right.place(relx=1.0, anchor="ne") self.sect_right.config(relief=RIDGE) self.sect_right.config(background=self.gray2) # Sliders layer self.layer_sliders = Frame(self.sect_left) self.layer_sliders.place(y=0, width=self.sect_width, height=320) self.layer_sliders.config(**self.layer_props(self.gray2)) self.lab_sliders = Label(self.layer_sliders) self.lab_sliders.config(**self.title_props("Parameters")) self.lab_sliders.pack() # DOB layer self.layer_dob = Frame(self.sect_left) self.layer_dob.place(y=320, width=self.sect_width, height=80) self.layer_dob.config(**self.layer_props(self.gray2)) self.lab_dob = Label(self.layer_dob) self.lab_dob.config(**self.title_props("Birthdays range")) self.lab_dob.pack() # Export layer self.layer_export = Frame(self.sect_left) self.layer_export.place(y=400, width=self.sect_width, height=80) self.layer_export.config(**self.layer_props(self.gray2)) self.lab_export = Label(self.layer_export) self.lab_export.config(**self.title_props("Export format")) self.lab_export.pack() # Run layer self.layer_run = Frame(self.sect_left) self.layer_run.place(y=480, width=self.sect_width, height=100) self.layer_run.config(**self.layer_props(self.gray2)) self.lab_run = Label(self.layer_run) self.lab_run.config(**self.title_props("Run")) self.lab_run.pack() # About layer self.layer_about = Frame(self.sect_right) self.layer_about.place(width=self.sect_width, height=385) self.layer_about.config(**self.layer_props(self.gray2)) self.lab_about = Label(self.layer_about) self.lab_about.config(**self.title_props("About Red Snapper")) self.lab_about.pack() # sliders self.sli_wom = Scale(self.layer_sliders, from_=0, to=100) self.sli_wom.config(**self.sli_props()) self.sli_wom.config(label="Percentage of women in dataset.") self.sli_wom.pack(padx=20, pady=10) self.sli_wom.set(50) self.sli_nam = Scale(self.layer_sliders, from_=0, to=100) self.sli_nam.config(**self.sli_props()) self.sli_nam.config(label="Percentage of people with double name") self.sli_nam.pack(padx=20, pady=0) self.sli_nam.set(25) self.sli_sur = Scale(self.layer_sliders, from_=0, to=100) self.sli_sur.config(**self.sli_props()) self.sli_sur.config(label="Percentage of people with double surname") self.sli_sur.pack(padx=20, pady=10) self.sli_sur.set(15) # DOB Layer - From Date self.dob1_val.set("1945") self.lab_dob1 = Label(self.layer_dob, text="From date") self.lab_dob1.config(**self.label_props()) self.lab_dob1.pack(side=LEFT, padx=5) self.box_dob1 = Spinbox(self.layer_dob) self.box_dob1.config(from_=1945, to=1996, textvariable=self.dob1_val) self.box_dob1.config(**self.date_props()) self.box_dob1.pack(side=LEFT) # DOB Layer - To Date self.dob2_val.set("1997") self.lab_dob2 = Label(self.layer_dob, text="To date") self.lab_dob2.config(**self.label_props()) self.lab_dob2.pack(side=LEFT, padx=17) self.box_dob2 = Spinbox(self.layer_dob) self.box_dob2.config(from_=1946, to=1997, textvariable=self.dob2_val) self.box_dob2.config(**self.date_props()) self.box_dob2.pack(side=LEFT) # Export layer - JSON / CSV radio buttons self.rb_choice.set("CSV") self.rb1 = Radiobutton(self.layer_export, text="Save as CSV", variable=self.rb_choice, value="CSV") self.rb1.config(**self.radio_props()) self.rb1.place(y=35, x=50) self.rb2 = Radiobutton(self.layer_export, text="Save as JSON", variable=self.rb_choice, value="JSON") self.rb2.config(**self.radio_props()) self.rb2.place(y=35, x=200) # Run layer - no of records spinbox self.df_records.set("100") self.box_gen = Spinbox(self.layer_run) self.box_gen.config(from_=1, to=999999, textvariable=self.df_records) self.box_gen.config(increment=1000, width=19) self.box_gen.place(x=70, y=53) self.lab_gen = Label(self.layer_run, text="Number of records") self.lab_gen.config(**self.label_props()) self.lab_gen.place(x=70, y=30) # Run layer - generate button self.btn_run = ttk.Button(self.layer_run) self.btn_run.place(x=225, y=35, height=40) self.btn_run_reset() # header & logo section self.sect_logo = Frame(master) self.sect_logo.place(x=-15, y=30, width=350, height=120) self.sect_logo.place(relx=1.0, anchor="ne") self.logo = PhotoImage(file="./redsnapper/interface/logo.png") self.lab_logo = Label(self.sect_logo, image=self.logo) self.lab_logo.config(background=self.gray1) self.lab_logo.pack() # About box_about = Text(self.layer_about) box_about.config(**self.text_props()) box_about.pack(pady=10, padx=10) txt = """This program allows generating thousands of rows filled with pseudo-random data. """ \ + """\nThe generated records (like name, """ \ + """ surname, date of birth, e-mail address) can be used to provide sample data to: - test query performance of your database - practice data operations with BI tools.""" \ + """ \nThe application uses 4 processes to generate data simultaneously. """ \ + """ It takes about 25 seconds to create 1 million rows of data.\n""" box_about.insert(END, txt) # styling wrapped into functions for reusability def sli_props(self): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return { "length": 300, "orient": HORIZONTAL, "sliderrelief": FLAT, "showvalue": 1, "resolution": 1, "sliderlength": 25, "tickinterval": 100, "font": ("Arial", 8), "activebackground": "#333333", "background": "#666666", "troughcolor": "#d0d4d2", "foreground": "#eeeeee", "highlightthickness": 8, "highlightcolor": "#ffffff", "highlightbackground": self.gray3, "borderwidth": 1 } @staticmethod def layer_props(bgcolor): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return {"relief": RIDGE, "background": bgcolor} def title_props(self, title): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return { "text": title, "background": self.gray3, "width": self.sect_width, "borderwidth": 1, "relief": RIDGE } def radio_props(self): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return { "background": self.gray2, "activebackground": self.gray2, } def date_props(self): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return { "width": 8, "increment": 1, "font": ("Arial", 8), "background": "#666666", "buttonbackground": "#666666", "foreground": "#eeeeee", "highlightthickness": 8, "highlightcolor": "#ffffff", "highlightbackground": self.gray2, "borderwidth": 1 } def label_props(self): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return { "background": self.gray2, "highlightcolor": "#ffffff", "highlightbackground": self.gray2, "borderwidth": 1 } def text_props(self): """ bundle popular attributes of TK control so they can be reused :return: dict of bundled props """ return { "font": ("Arial", 11), "background": self.gray1, "foreground": "#212121", "highlightthickness": 8, "highlightbackground": self.gray1, "highlightcolor": self.gray1, "borderwidth": 0, "wrap": "word", "spacing1": 11, "spacing2": 7, } def produce_props(self): """ produce dict of key GUI parameters selected by user :return: no return parameters """ rows = int(self.box_gen.get()) props = { "pgender": self.sli_wom.get(), "pdname": self.sli_nam.get(), "pdsurname": self.sli_sur.get(), "dob1": self.box_dob1.get(), "dob2": self.box_dob2.get(), } dataset = Dataset().run_workload(rows, **props) exp_format = self.rb_choice.get() if exp_format == "CSV": Export().to_csv(dataset) else: Export().to_json(dataset) self.btn_run_reset() return def btn_run_reset(self): """ abort button (when generating) :return: no return parameters """ self.running = False self.btn_run.config(text="Generate", command=self.btn_run_start) return def btn_run_start(self): """ handle the run button :return: no return parameters """ self.running = True newthread = threading.Thread(target=self.produce_props) newthread.start() self.btn_run.config(text="Abort", command=self.btn_run_reset) return