class RefObjectBSC(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller self.title = "Configure the image's scale" self.responsive_image = None self.boxes = [] self.box = None self.stage1_widgets = [] self.stage2_widgets = [] self.initialize_widgets() self.bind("<<ShowFrame>>", self.on_show_frame) def initialize_widgets(self): # WATCHERS # Update state of navigation buttons self.current_contour_var = IntVar() self.current_contour_var.trace("w", self.update_navigation) # Transition between stages self.selected_object_var = StringVar() self.selected_object_var.trace("w", self.update_stage) # Switch between horizontal and vertical bisections self.dimension_type = StringVar() self.dimension_type.set("horizontal") self.dimension_type.trace("w", self.update_image) # Update confirm button state self.real_dimension_var = StringVar() self.real_dimension_var.trace("w", self.update_confirm_button) # Min size of object title column self.grid_columnconfigure(0, minsize=150) # Min size of change button column self.grid_columnconfigure(1, minsize=100) # title of ref object image self.ref_object_var = StringVar() self.ref_object_title = Label(self, textvariable=self.ref_object_var, font=self.controller.header_font) self.ref_object_title.grid(row=0, column=0, sticky=W, padx=20, pady=20) # STAGE 1 # Controls to navigate contours self.prev_button = GreenButton(self, text="Previous", image=self.controller.arrow_left, compound=LEFT, command=lambda: self.show_contour( self.current_contour_var.get() - 1)) self.stage1_widgets.append( (self.prev_button, lambda: self.prev_button.grid( row=0, column=1, sticky=SE, padx=5, pady=20))) self.next_button = GreenButton(self, text="Next", image=self.controller.arrow_right, compound=RIGHT, command=lambda: self.show_contour( self.current_contour_var.get() + 1)) self.stage1_widgets.append( (self.next_button, lambda: self.next_button.grid(row=0, column=2, sticky=SW, pady=20) )) # image in row=1, col=0, colspan=3, rowspan varies with stage # instructions self.instructions_var = StringVar() self.instructions = Label(self, textvariable=self.instructions_var, relief=GROOVE, padx=10, pady=10) self.instructions.grid(row=1, column=3, padx=40) # select reference object self.select_button = YellowButton( self, text="Use this object as reference", command=lambda: self.selected_object_var.set( self.current_contour_var.get())) self.stage1_widgets.append( (self.select_button, lambda: self.select_button.grid(row=2, column=3, sticky=N))) # STAGE 2 # Change reference object self.change_button = GreenButton( self, text="Change", command=lambda: self.selected_object_var.set("")) self.stage2_widgets.append( (self.change_button, lambda: self.change_button.grid( row=0, column=1, columnspan=2, sticky=SE, pady=20))) # select dimension to enter for the reference object self.dimension_label = Label(self, text="Select dimension", font=self.controller.header_font, anchor=SW) self.stage2_widgets.append( (self.dimension_label, lambda: self.dimension_label.grid( row=2, column=3, sticky=NSEW, padx=40, pady=10))) self.dimension_width = Radiobutton(self, text="Width", variable=self.dimension_type, value="horizontal", cursor="hand2", anchor=SW) self.dimension_height = Radiobutton(self, text="Height", variable=self.dimension_type, value="vertical", cursor="hand2", anchor=NW) self.stage2_widgets.append( (self.dimension_width, lambda: self.dimension_width.grid( row=3, column=3, sticky=NSEW, padx=60))) self.stage2_widgets.append( (self.dimension_height, lambda: self.dimension_height.grid( row=4, column=3, sticky=NSEW, padx=60))) # user-entered dimension (for pixels-per-metric) self.real_dimension_label = Label( self, text="True measure of pink line (in centimeters)", font=self.controller.header_font, anchor=SW) self.stage2_widgets.append( (self.real_dimension_label, lambda: self.real_dimension_label.grid( row=5, column=3, padx=40, pady=20, sticky=NSEW))) # %d = Type of action (1=insert, 0=delete, -1 for others) # %P = value of the entry if the edit is allowed # %S = the text string being inserted or deleted, if any validate_cmd = (self.register(self.validate_dimension), '%d', '%P', '%S') self.real_dimension = EntryWithPlaceholder( self, text_var=self.real_dimension_var, placeholder_text="0.00", validate="key", validatecommand=validate_cmd, textvariable=self.real_dimension_var) self.stage2_widgets.append( (self.real_dimension, lambda: self.real_dimension.grid( row=6, column=3, padx=60, sticky=NW))) # Invalid dimension message self.invalid_dimension = Label( self, text="Dimension must be between 1 and 28 centimeters", fg="red", anchor=W) # confirm button self.confirm_button = YellowButton(self, text="CONFIRM", command=self.confirm) self.stage2_widgets.append( (self.confirm_button, lambda: self.confirm_button.grid( row=8, column=3, sticky=SE, padx=20, pady=20))) # set dimension entry placeholder self.real_dimension.set_placeholder() # start in stage 1 self.selected_object_var.set("") def on_show_frame(self, event=None): # fetch all reference objects self.boxes = render_boxes() # Show the last object we were browsing, or the 1st one if this is a fresh session try: self.show_contour(self.current_contour_var.get()) # In case something weird happens except IndexError: print("could not show contour; resetting") self.reset() self.on_show_frame() def show_contour(self, index): self.box = self.boxes[index] self.current_contour_var.set(index) self.update_image() def update_image(self, *args): if self.box is not None: image = self.box[self.dimension_type.get()][0] if self.responsive_image is not None: self.responsive_image.destroy() self.responsive_image = ResponsiveImage(self, image) # stage 2 if self.selected_object_var.get(): self.responsive_image.grid(row=1, column=0, rowspan=8, columnspan=3, sticky=NSEW, pady=20) # stage 1 else: self.responsive_image.grid(row=1, column=0, rowspan=2, columnspan=3, sticky=NSEW, pady=20) def update_navigation(self, *args): current = self.current_contour_var.get() # update image title self.ref_object_var.set("Object #" + str(current + 1)) # toggle prev if current == 0: self.prev_button.configure(state=DISABLED, cursor="arrow") else: self.prev_button.configure(state=NORMAL, cursor="hand2") # toggle next if current == len(self.boxes) - 1: self.next_button.configure(state=DISABLED, cursor="arrow") else: self.next_button.configure(state=NORMAL, cursor="hand2") def update_stage(self, *args): # Object has been selected if self.selected_object_var.get(): # Show stage 2 self.set_stage2() else: # Show stage 1 self.set_stage1() def set_stage1(self): current = self.current_contour_var.get() # Update image title self.ref_object_var.set("Object #" + str(current + 1)) # Update instructions self.instructions_var.set( "Choose an object for which you know its width or height.\n" "This will allow to calculate the real dimensions of the bamboo slice." ) # Hide stage 2 for (widget, grid_command) in self.stage2_widgets: widget.grid_forget() # Hide invalid message self.invalid_dimension.grid_forget() # Show stage 1 for (widget, grid_command) in self.stage1_widgets: grid_command() # Update responsive image if self.responsive_image is not None: self.responsive_image.grid(row=1, column=0, rowspan=2, columnspan=3, sticky=NSEW, pady=20) # Update responsive reset_both_responsive(self) make_columns_responsive(self, ignored=[1, 2]) make_rows_responsive(self, ignored=[0]) def set_stage2(self): # Update image title self.ref_object_var.set("Selected Reference Object") # Update instructions self.instructions_var.set( "Now please tell us how long is the dimension given by the pink line in the image.\n" "Provide the most decimals for more accurate results!") # Hide stage 1 for (widget, grid_command) in self.stage1_widgets: widget.grid_forget() # Show stage 2 for (widget, grid_command) in self.stage2_widgets: grid_command() # Update responsive image if self.responsive_image is not None: self.responsive_image.grid(row=1, column=0, rowspan=8, columnspan=3, sticky=NSEW, pady=20) # Update responsive reset_both_responsive(self) make_columns_responsive(self, ignored=[0, 1]) make_rows_responsive(self, ignored=[0, 2, 3, 4, 5, 6, 7]) def validate_dimension(self, action, value_if_allowed, text): # only when inserting if (action == "1"): if text in "0123456789.": try: # maximum set by size of scanner (8.5 x 11 inches) if float(value_if_allowed) >= 1.0 and float( value_if_allowed) <= 28.0: # remove invalid message self.invalid_dimension.grid_forget() return True else: # Make system bell sound self.bell() # Show invalid message self.invalid_dimension.grid(row=7, column=3, sticky=NSEW, padx=60, pady=20) return False except ValueError: self.bell() return False else: self.bell() return False else: return True def update_confirm_button(self, *args): dimension = self.real_dimension_var.get() try: # not empty string and greater than 1 if dimension and float(dimension) >= 1.0: self.confirm_button.configure(state=NORMAL, cursor="hand2") else: self.confirm_button.configure(state=DISABLED, cursor="arrow") except ValueError: print("cannot cast dimension value to float") self.confirm_button.configure(state=DISABLED, cursor="arrow") def confirm(self): # pixels per metric = distance in pixels / distance in centimeters ppm = self.box[self.dimension_type.get()][1] / float( self.real_dimension.get()) set_pixels_per_metric(ppm) # Show results self.controller.show_frame("ResultsBSC") def reset(self): # destroy the image container if self.responsive_image is not None: self.responsive_image.grid_forget() self.responsive_image.destroy() self.responsive_image = None # reset real dimension entry field self.real_dimension.set_placeholder() # Default to width self.dimension_type.set("horizontal") # clear selected object; start in stage 1 self.selected_object_var.set("") # clear ref objects self.boxes.clear() self.box = None # Start showing 1st contour box self.current_contour_var.set(0)
def initialize_widgets(self): # WATCHERS # Update state of navigation buttons self.current_contour_var = IntVar() self.current_contour_var.trace("w", self.update_navigation) # Transition between stages self.selected_object_var = StringVar() self.selected_object_var.trace("w", self.update_stage) # Switch between horizontal and vertical bisections self.dimension_type = StringVar() self.dimension_type.set("horizontal") self.dimension_type.trace("w", self.update_image) # Update confirm button state self.real_dimension_var = StringVar() self.real_dimension_var.trace("w", self.update_confirm_button) # Min size of object title column self.grid_columnconfigure(0, minsize=150) # Min size of change button column self.grid_columnconfigure(1, minsize=100) # title of ref object image self.ref_object_var = StringVar() self.ref_object_title = Label(self, textvariable=self.ref_object_var, font=self.controller.header_font) self.ref_object_title.grid(row=0, column=0, sticky=W, padx=20, pady=20) # STAGE 1 # Controls to navigate contours self.prev_button = GreenButton(self, text="Previous", image=self.controller.arrow_left, compound=LEFT, command=lambda: self.show_contour( self.current_contour_var.get() - 1)) self.stage1_widgets.append( (self.prev_button, lambda: self.prev_button.grid( row=0, column=1, sticky=SE, padx=5, pady=20))) self.next_button = GreenButton(self, text="Next", image=self.controller.arrow_right, compound=RIGHT, command=lambda: self.show_contour( self.current_contour_var.get() + 1)) self.stage1_widgets.append( (self.next_button, lambda: self.next_button.grid(row=0, column=2, sticky=SW, pady=20) )) # image in row=1, col=0, colspan=3, rowspan varies with stage # instructions self.instructions_var = StringVar() self.instructions = Label(self, textvariable=self.instructions_var, relief=GROOVE, padx=10, pady=10) self.instructions.grid(row=1, column=3, padx=40) # select reference object self.select_button = YellowButton( self, text="Use this object as reference", command=lambda: self.selected_object_var.set( self.current_contour_var.get())) self.stage1_widgets.append( (self.select_button, lambda: self.select_button.grid(row=2, column=3, sticky=N))) # STAGE 2 # Change reference object self.change_button = GreenButton( self, text="Change", command=lambda: self.selected_object_var.set("")) self.stage2_widgets.append( (self.change_button, lambda: self.change_button.grid( row=0, column=1, columnspan=2, sticky=SE, pady=20))) # select dimension to enter for the reference object self.dimension_label = Label(self, text="Select dimension", font=self.controller.header_font, anchor=SW) self.stage2_widgets.append( (self.dimension_label, lambda: self.dimension_label.grid( row=2, column=3, sticky=NSEW, padx=40, pady=10))) self.dimension_width = Radiobutton(self, text="Width", variable=self.dimension_type, value="horizontal", cursor="hand2", anchor=SW) self.dimension_height = Radiobutton(self, text="Height", variable=self.dimension_type, value="vertical", cursor="hand2", anchor=NW) self.stage2_widgets.append( (self.dimension_width, lambda: self.dimension_width.grid( row=3, column=3, sticky=NSEW, padx=60))) self.stage2_widgets.append( (self.dimension_height, lambda: self.dimension_height.grid( row=4, column=3, sticky=NSEW, padx=60))) # user-entered dimension (for pixels-per-metric) self.real_dimension_label = Label( self, text="True measure of pink line (in centimeters)", font=self.controller.header_font, anchor=SW) self.stage2_widgets.append( (self.real_dimension_label, lambda: self.real_dimension_label.grid( row=5, column=3, padx=40, pady=20, sticky=NSEW))) # %d = Type of action (1=insert, 0=delete, -1 for others) # %P = value of the entry if the edit is allowed # %S = the text string being inserted or deleted, if any validate_cmd = (self.register(self.validate_dimension), '%d', '%P', '%S') self.real_dimension = EntryWithPlaceholder( self, text_var=self.real_dimension_var, placeholder_text="0.00", validate="key", validatecommand=validate_cmd, textvariable=self.real_dimension_var) self.stage2_widgets.append( (self.real_dimension, lambda: self.real_dimension.grid( row=6, column=3, padx=60, sticky=NW))) # Invalid dimension message self.invalid_dimension = Label( self, text="Dimension must be between 1 and 28 centimeters", fg="red", anchor=W) # confirm button self.confirm_button = YellowButton(self, text="CONFIRM", command=self.confirm) self.stage2_widgets.append( (self.confirm_button, lambda: self.confirm_button.grid( row=8, column=3, sticky=SE, padx=20, pady=20))) # set dimension entry placeholder self.real_dimension.set_placeholder() # start in stage 1 self.selected_object_var.set("")
class ConfigBPC(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller self.title = "Configuration" self.initialize_widgets() def initialize_widgets(self): # CALIBRATION # Ring diameter entry value self.ring_diameter_var = StringVar() self.ring_diameter_var.trace("w", self.update_begin_button) # Calibration object value self.calibration_object_var = StringVar() self.calibration_object_var.trace("w", self.update_begin_button) # Distance to end of rail value self.distance_z_var = StringVar() self.distance_z_var.trace("w", self.update_begin_button) # %d = Type of action (1=insert, 0=delete, -1 for others) # %P = value of the entry if the edit is allowed # %S = the text string being inserted or deleted, if any validate_cmd = (self.register(self.validate_dimension), '%d', '%P', '%S') # Calibration settings group self.calibration_settings = LabelFrame( self, text="Calibration Settings", fg="grey", padx=20, pady=20, font=self.controller.header_font) self.calibration_settings.grid(row=0, column=0, sticky=NS + W, padx=20, pady=20) # Ring diameter self.ring_diameter_label = Label(self.calibration_settings, text="Ring structure diameter", anchor=SW, font=self.controller.bold_font) self.ring_diameter_label.grid(row=0, column=0, sticky=SW, padx=20) self.ring_diameter_entry = EntryWithPlaceholder( self.calibration_settings, text_var=self.ring_diameter_var, placeholder_text="0.00", validatecommand=validate_cmd, validate="key", textvariable=self.ring_diameter_var) self.ring_diameter_entry.grid(row=1, column=0, sticky=NW, padx=20, pady=20) # Calibration object self.calibration_object_label = Label(self.calibration_settings, text="Calibration object radius", font=self.controller.bold_font, anchor=SW) self.calibration_object_label.grid(row=0, column=1, sticky=SW, padx=20) self.calibration_object_entry = EntryWithPlaceholder( self.calibration_settings, text_var=self.calibration_object_var, placeholder_text="0.00", validatecommand=validate_cmd, textvariable=self.calibration_object_var, validate="key") self.calibration_object_entry.grid(row=1, column=1, sticky=NW, padx=20, pady=20) # Distance to flat surface at end of rail self.distance_z_label = Label(self.calibration_settings, text="Distance to the end of the rail", anchor=SW, font=self.controller.bold_font) self.distance_z_label.grid(row=2, column=0, sticky=SW, padx=20) self.distance_z_entry = EntryWithPlaceholder( self.calibration_settings, text_var=self.distance_z_var, placeholder_text="0.00", validate="key", validatecommand=validate_cmd, textvariable=self.distance_z_var) self.distance_z_entry.grid(row=3, column=0, sticky=NW, padx=20, pady=20) # Invalid dimension message self.invalid_dimension = Label( self.calibration_settings, text="Dimension must be between 1 and 28 centimeters", fg="red", anchor=W) # make calibration section responsive make_columns_responsive(self.calibration_settings) make_rows_responsive(self.calibration_settings) # description label self.description_label = Label( self, text="Information about the sample (optional)", font=self.controller.bold_font) self.description_label.grid(row=1, column=0, sticky=SW, padx=20, pady=20) # Description text area self.text_area = ScrollableTextArea(self) self.text_area.grid(row=2, column=0, sticky=NW, padx=20) # begin button self.begin_button = YellowButton(self, text="BEGIN", command=self.begin, image=self.controller.arrow_right, compound=RIGHT) self.begin_button.grid(row=3, column=0, sticky=SE, padx=20, pady=20) # set placeholders self.ring_diameter_entry.set_placeholder() self.calibration_object_entry.set_placeholder() self.distance_z_entry.set_placeholder() make_rows_responsive(self) make_columns_responsive(self) def validate_dimension(self, action, value_if_allowed, text): # only when inserting if (action == "1"): if text in "0123456789.": try: # maximum set by size of scanner (8.5 x 11 inches) if float(value_if_allowed) >= 1.0 and float( value_if_allowed) <= 28.0: # remove invalid message self.invalid_dimension.grid_forget() return True else: # Make system bell sound self.bell() # Show invalid message self.invalid_dimension.grid(row=7, column=3, sticky=NSEW, padx=60, pady=20) return False except ValueError: self.bell() return False else: self.bell() return False else: return True def update_begin_button(self, *args): ring_diameter = self.ring_diameter_var.get() calibration_obj = self.calibration_object_var.get() distance_z = self.distance_z_var.get() try: ring_diameter_ok = ring_diameter and float(ring_diameter) >= 1.0 calibration_object_ok = calibration_obj and float( calibration_obj) >= 1.0 distance_z_ok = distance_z and float(distance_z) >= 1.0 # All entries filled if ring_diameter_ok and calibration_object_ok and distance_z_ok: self.begin_button.configure(state=NORMAL, cursor="hand2") else: self.begin_button.configure(state=DISABLED, cursor="arrow") except ValueError: print("cannot cast values to float") self.begin_button.configure(state=DISABLED, cursor="arrow") def begin(self): # save sample description set_sampleDescription(self.text_area.get_text()) # save calibration settings ring_diameter = float(self.ring_diameter_var.get()) calibration_obj = float(self.calibration_object_var.get()) distance_z = float(self.distance_z_var.get()) set_calibration_settings(ringDiameter=ring_diameter, obj_radius=calibration_obj, distance_z=distance_z) # Show sensors live feed self.controller.show_frame("MeasureBPC") def reset(self): # reset description self.text_area.clear_text()
def initialize_widgets(self): # CALIBRATION # Ring diameter entry value self.ring_diameter_var = StringVar() self.ring_diameter_var.trace("w", self.update_begin_button) # Calibration object value self.calibration_object_var = StringVar() self.calibration_object_var.trace("w", self.update_begin_button) # Distance to end of rail value self.distance_z_var = StringVar() self.distance_z_var.trace("w", self.update_begin_button) # %d = Type of action (1=insert, 0=delete, -1 for others) # %P = value of the entry if the edit is allowed # %S = the text string being inserted or deleted, if any validate_cmd = (self.register(self.validate_dimension), '%d', '%P', '%S') # Calibration settings group self.calibration_settings = LabelFrame( self, text="Calibration Settings", fg="grey", padx=20, pady=20, font=self.controller.header_font) self.calibration_settings.grid(row=0, column=0, sticky=NS + W, padx=20, pady=20) # Ring diameter self.ring_diameter_label = Label(self.calibration_settings, text="Ring structure diameter", anchor=SW, font=self.controller.bold_font) self.ring_diameter_label.grid(row=0, column=0, sticky=SW, padx=20) self.ring_diameter_entry = EntryWithPlaceholder( self.calibration_settings, text_var=self.ring_diameter_var, placeholder_text="0.00", validatecommand=validate_cmd, validate="key", textvariable=self.ring_diameter_var) self.ring_diameter_entry.grid(row=1, column=0, sticky=NW, padx=20, pady=20) # Calibration object self.calibration_object_label = Label(self.calibration_settings, text="Calibration object radius", font=self.controller.bold_font, anchor=SW) self.calibration_object_label.grid(row=0, column=1, sticky=SW, padx=20) self.calibration_object_entry = EntryWithPlaceholder( self.calibration_settings, text_var=self.calibration_object_var, placeholder_text="0.00", validatecommand=validate_cmd, textvariable=self.calibration_object_var, validate="key") self.calibration_object_entry.grid(row=1, column=1, sticky=NW, padx=20, pady=20) # Distance to flat surface at end of rail self.distance_z_label = Label(self.calibration_settings, text="Distance to the end of the rail", anchor=SW, font=self.controller.bold_font) self.distance_z_label.grid(row=2, column=0, sticky=SW, padx=20) self.distance_z_entry = EntryWithPlaceholder( self.calibration_settings, text_var=self.distance_z_var, placeholder_text="0.00", validate="key", validatecommand=validate_cmd, textvariable=self.distance_z_var) self.distance_z_entry.grid(row=3, column=0, sticky=NW, padx=20, pady=20) # Invalid dimension message self.invalid_dimension = Label( self.calibration_settings, text="Dimension must be between 1 and 28 centimeters", fg="red", anchor=W) # make calibration section responsive make_columns_responsive(self.calibration_settings) make_rows_responsive(self.calibration_settings) # description label self.description_label = Label( self, text="Information about the sample (optional)", font=self.controller.bold_font) self.description_label.grid(row=1, column=0, sticky=SW, padx=20, pady=20) # Description text area self.text_area = ScrollableTextArea(self) self.text_area.grid(row=2, column=0, sticky=NW, padx=20) # begin button self.begin_button = YellowButton(self, text="BEGIN", command=self.begin, image=self.controller.arrow_right, compound=RIGHT) self.begin_button.grid(row=3, column=0, sticky=SE, padx=20, pady=20) # set placeholders self.ring_diameter_entry.set_placeholder() self.calibration_object_entry.set_placeholder() self.distance_z_entry.set_placeholder() make_rows_responsive(self) make_columns_responsive(self)
class ConfigBPC(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) self.controller = controller self.title = "Configuration" self.initialize_widgets() def initialize_widgets(self): # CALIBRATION # Ring diameter entry value self.ring_diameter_var = StringVar() self.ring_diameter_var.trace("w", self.update_begin_button) # Calibration object value self.calibration_object_var = StringVar() self.calibration_object_var.trace("w", self.update_begin_button) # Distance to end of rail value self.distance_z_var = StringVar() self.distance_z_var.trace("w", self.update_begin_button) # %d = Type of action (1=insert, 0=delete, -1 for others) # %P = value of the entry if the edit is allowed # %S = the text string being inserted or deleted, if any # %W = the name of the widget validate_cmd = (self.register(self.validate_calibration_settings), '%d', '%P', '%S', '%W') # Calibration settings group self.calibration_settings = LabelFrame(self, text="Calibration Settings (all measures in centimeters)", fg="grey", padx=20, pady=20, font=self.controller.header_font) self.calibration_settings.grid(row=0, column=0, sticky=NSEW, padx=20, pady=20) # Ring diameter self.ring_diameter_label = Label(self.calibration_settings, text="Ring structure diameter", anchor=SW, font=self.controller.bold_font) self.ring_diameter_label.grid(row=0, column=0, sticky=SW, padx=20) # ring diameter range self.range_ring_diameter = Label(self.calibration_settings, text="[Valid range: 10 - 30]", fg="grey", anchor=SW, font=self.controller.small_font) self.range_ring_diameter.grid(row=1, column=0, sticky=NW, padx=20) self.ring_diameter_entry = EntryWithPlaceholder(self.calibration_settings, text_var=self.ring_diameter_var, placeholder_text="0.00", validatecommand=validate_cmd, validate="key", textvariable=self.ring_diameter_var, name="ring") self.ring_diameter_entry.grid(row=2, column=0, sticky=NW, padx=20, pady=20) # Calibration object self.calibration_object_label = Label(self.calibration_settings, text="Calibration object diameter", font=self.controller.bold_font, anchor=SW) self.calibration_object_label.grid(row=0, column=1, sticky=SW, padx=20) # calibration object diameter range self.range_calibration_obj_diameter = Label(self.calibration_settings, text="[Valid range: 2 - 26]", fg="grey", anchor=NW, font=self.controller.small_font) self.range_calibration_obj_diameter.grid(row=1, column=1, sticky=NW, padx=20) self.calibration_object_entry = EntryWithPlaceholder(self.calibration_settings, text_var=self.calibration_object_var, placeholder_text="0.00", validatecommand=validate_cmd, textvariable=self.calibration_object_var, validate="key", name="calibration_obj") self.calibration_object_entry.grid(row=2, column=1, sticky=NW, padx=20, pady=20) # Distance to flat surface at end of rail self.distance_z_label = Label(self.calibration_settings, text="Distance to the end of the rail", anchor=SW, font = self.controller.bold_font) self.distance_z_label.grid(row=3, column=0, sticky=SW, padx=20) # z distance range self.range_z_distance = Label(self.calibration_settings, text="[Valid range: 15.24 - 645]", fg="grey", anchor=NW, font=self.controller.small_font) self.range_z_distance.grid(row=4, column=0, sticky=NW, padx=20) self.distance_z_entry = EntryWithPlaceholder(self.calibration_settings, text_var=self.distance_z_var, placeholder_text="0.00", validate="key", name="z_distance", validatecommand=validate_cmd, textvariable=self.distance_z_var) self.distance_z_entry.grid(row=5, column=0, sticky=NW, padx=20, pady=20) # calibration object diameter greater than ring diameter self.calibration_obj_greater_ring = Label(self.calibration_settings, text="The calibration object's diameter\ncan't be greater than the ring diameter", fg="red", anchor=NW) # make calibration section responsive make_columns_responsive(self.calibration_settings) make_rows_responsive(self.calibration_settings) # description label self.description_label = Label(self, text="Information about the bamboo sample (optional)", font=self.controller.bold_font) self.description_label.grid(row=1, column=0, sticky=SW, padx=20, pady=20) # Description text area self.text_area = ScrollableTextArea(self) self.text_area.grid(row=2, column=0, sticky=NW, padx=20) # begin button self.begin_button = YellowButton(self, text="BEGIN", command=self.begin, image=self.controller.arrow_right, compound=RIGHT) self.begin_button.grid(row=3, column=0, sticky=SE, padx=20, pady=20) # set placeholders self.ring_diameter_entry.set_placeholder() self.calibration_object_entry.set_placeholder() self.distance_z_entry.set_placeholder() make_rows_responsive(self) make_columns_responsive(self) # min size of buttons row self.grid_rowconfigure(3, minsize=80) def validate_calibration_settings(self, action, value_if_allowed, text, widget): # only when inserting if action == "1": if text in "0123456789.": try: # name of the widget widget_name = str(widget).split(".")[-1] # ring if widget_name == "ring": # valid range [10,30] if float(value_if_allowed) >= 1.0 and float(value_if_allowed) <= 30.0: return True else: # Make system bell sound self.bell() return False # calibration object elif widget_name == "calibration_obj": # valid range [2,26] if float(value_if_allowed) >= 1.0 and float(value_if_allowed) <= 26.0: return True else: # Make system bell sound self.bell() return False # z distance entry else: # valid range [15.24, 645] if float(value_if_allowed) >= 1.0 and float(value_if_allowed) <= 645.0: return True else: # Make system bell sound self.bell() return False except ValueError: self.bell() return False else: self.bell() return False else: return True def update_begin_button(self, *args): ring_diameter = self.ring_diameter_var.get() calibration_obj = self.calibration_object_var.get() distance_z = self.distance_z_var.get() # valid range [10,30] ring_diameter_ok = ring_diameter and float(ring_diameter) >= 10.0 # valid range [2,26] calibration_object_ok = calibration_obj and float(calibration_obj) >= 2.0 # valid range [15.24, 645] distance_z_ok = distance_z and float(distance_z) >= 15.24 # show invalid message when calibration object diameter is greater than ring if ring_diameter_ok and calibration_object_ok and (float(ring_diameter) - float(calibration_obj)) > 0: self.calibration_obj_greater_ring.grid_forget() elif ring_diameter_ok and calibration_object_ok and (float(ring_diameter) - float(calibration_obj)) <= 0: self.calibration_obj_greater_ring.grid(row=3, column=1, sticky=NW, padx=20) # All entries valid if ring_diameter_ok and calibration_object_ok and distance_z_ok and \ (float(ring_diameter) - float(calibration_obj)) > 0: # enable begin button self.begin_button.configure(state=NORMAL, cursor="hand2") # at least one entry is not valid else: # disable begin button self.begin_button.configure(state=DISABLED, cursor="arrow") def begin(self): # save sample description set_sampleDescription(self.text_area.text.get(1.0, END)) # save calibration settings ring_diameter = float(self.ring_diameter_var.get()) calibration_obj = float(self.calibration_object_var.get()) distance_z = float(self.distance_z_var.get()) set_calibration_settings(ringDiameter=ring_diameter, obj_diameter=calibration_obj, distance_z=distance_z) # Show sensors live feed self.controller.show_frame("MeasureBPC") def reset(self): # reset description self.text_area.text.delete(1.0, END)
def initialize_widgets(self): # CALIBRATION # Ring diameter entry value self.ring_diameter_var = StringVar() self.ring_diameter_var.trace("w", self.update_begin_button) # Calibration object value self.calibration_object_var = StringVar() self.calibration_object_var.trace("w", self.update_begin_button) # Distance to end of rail value self.distance_z_var = StringVar() self.distance_z_var.trace("w", self.update_begin_button) # %d = Type of action (1=insert, 0=delete, -1 for others) # %P = value of the entry if the edit is allowed # %S = the text string being inserted or deleted, if any # %W = the name of the widget validate_cmd = (self.register(self.validate_calibration_settings), '%d', '%P', '%S', '%W') # Calibration settings group self.calibration_settings = LabelFrame(self, text="Calibration Settings (all measures in centimeters)", fg="grey", padx=20, pady=20, font=self.controller.header_font) self.calibration_settings.grid(row=0, column=0, sticky=NSEW, padx=20, pady=20) # Ring diameter self.ring_diameter_label = Label(self.calibration_settings, text="Ring structure diameter", anchor=SW, font=self.controller.bold_font) self.ring_diameter_label.grid(row=0, column=0, sticky=SW, padx=20) # ring diameter range self.range_ring_diameter = Label(self.calibration_settings, text="[Valid range: 10 - 30]", fg="grey", anchor=SW, font=self.controller.small_font) self.range_ring_diameter.grid(row=1, column=0, sticky=NW, padx=20) self.ring_diameter_entry = EntryWithPlaceholder(self.calibration_settings, text_var=self.ring_diameter_var, placeholder_text="0.00", validatecommand=validate_cmd, validate="key", textvariable=self.ring_diameter_var, name="ring") self.ring_diameter_entry.grid(row=2, column=0, sticky=NW, padx=20, pady=20) # Calibration object self.calibration_object_label = Label(self.calibration_settings, text="Calibration object diameter", font=self.controller.bold_font, anchor=SW) self.calibration_object_label.grid(row=0, column=1, sticky=SW, padx=20) # calibration object diameter range self.range_calibration_obj_diameter = Label(self.calibration_settings, text="[Valid range: 2 - 26]", fg="grey", anchor=NW, font=self.controller.small_font) self.range_calibration_obj_diameter.grid(row=1, column=1, sticky=NW, padx=20) self.calibration_object_entry = EntryWithPlaceholder(self.calibration_settings, text_var=self.calibration_object_var, placeholder_text="0.00", validatecommand=validate_cmd, textvariable=self.calibration_object_var, validate="key", name="calibration_obj") self.calibration_object_entry.grid(row=2, column=1, sticky=NW, padx=20, pady=20) # Distance to flat surface at end of rail self.distance_z_label = Label(self.calibration_settings, text="Distance to the end of the rail", anchor=SW, font = self.controller.bold_font) self.distance_z_label.grid(row=3, column=0, sticky=SW, padx=20) # z distance range self.range_z_distance = Label(self.calibration_settings, text="[Valid range: 15.24 - 645]", fg="grey", anchor=NW, font=self.controller.small_font) self.range_z_distance.grid(row=4, column=0, sticky=NW, padx=20) self.distance_z_entry = EntryWithPlaceholder(self.calibration_settings, text_var=self.distance_z_var, placeholder_text="0.00", validate="key", name="z_distance", validatecommand=validate_cmd, textvariable=self.distance_z_var) self.distance_z_entry.grid(row=5, column=0, sticky=NW, padx=20, pady=20) # calibration object diameter greater than ring diameter self.calibration_obj_greater_ring = Label(self.calibration_settings, text="The calibration object's diameter\ncan't be greater than the ring diameter", fg="red", anchor=NW) # make calibration section responsive make_columns_responsive(self.calibration_settings) make_rows_responsive(self.calibration_settings) # description label self.description_label = Label(self, text="Information about the bamboo sample (optional)", font=self.controller.bold_font) self.description_label.grid(row=1, column=0, sticky=SW, padx=20, pady=20) # Description text area self.text_area = ScrollableTextArea(self) self.text_area.grid(row=2, column=0, sticky=NW, padx=20) # begin button self.begin_button = YellowButton(self, text="BEGIN", command=self.begin, image=self.controller.arrow_right, compound=RIGHT) self.begin_button.grid(row=3, column=0, sticky=SE, padx=20, pady=20) # set placeholders self.ring_diameter_entry.set_placeholder() self.calibration_object_entry.set_placeholder() self.distance_z_entry.set_placeholder() make_rows_responsive(self) make_columns_responsive(self) # min size of buttons row self.grid_rowconfigure(3, minsize=80)