diff --git a/Demo_Crossword_Puzzle.py b/Demo_Crossword_Puzzle.py new file mode 100644 index 00000000..9919b802 --- /dev/null +++ b/Demo_Crossword_Puzzle.py @@ -0,0 +1,53 @@ +import sys +if sys.version_info[0] >= 3: + import PySimpleGUI as sg +else: + import PySimpleGUI27 as sg +import random +import string + +""" + Demo application to show how to draw rectangles and letters on a Graph Element + This demo mocks up a crossword puzzle board + It will place a letter where you click on the puzzle +""" + + +BOX_SIZE = 25 + +layout = [ + [sg.Text('Crossword Puzzle Using PySimpleGUI'), sg.Text('', key='_OUTPUT_')], + [sg.Graph((800,800), (0,450), (450,0), key='_GRAPH_', change_submits=True, drag_submits=False)], + [sg.Button('Show'), sg.Button('Exit')] + ] + +window = sg.Window('Window Title', ).Layout(layout).Finalize() + +g = window.FindElement('_GRAPH_') + +for row in range(16): + for col in range(16): + if random.randint(0,100) > 10: + g.DrawRectangle((col * BOX_SIZE + 5, row * BOX_SIZE + 3), (col * BOX_SIZE + BOX_SIZE + 5, row * BOX_SIZE + BOX_SIZE + 3), line_color='black') + else: + g.DrawRectangle((col * BOX_SIZE + 5, row * BOX_SIZE + 3), (col * BOX_SIZE + BOX_SIZE + 5, row * BOX_SIZE + BOX_SIZE + 3), line_color='black', fill_color='black') + + g.DrawText('{}'.format(row * 6 + col + 1), (col * BOX_SIZE + 10, row * BOX_SIZE + 8)) + +while True: # Event Loop + event, values = window.Read() + print(event, values) + if event is None or event == 'Exit': + break + mouse = values['_GRAPH_'] + + if event == '_GRAPH_': + if mouse == (None, None): + continue + box_x = mouse[0]//BOX_SIZE + box_y = mouse[1]//BOX_SIZE + letter_location = (box_x * BOX_SIZE + 18, box_y * BOX_SIZE + 17) + print(box_x, box_y) + g.DrawText('{}'.format(random.choice(string.ascii_uppercase)), letter_location, font='Courier 25') + +window.Close() diff --git a/PySimpleGUI.py b/PySimpleGUI.py index e3fa7420..7eee4c48 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1581,7 +1581,7 @@ class Canvas(Element): # Graph # # ---------------------------------------------------------------------- # class Graph(Element): - def __init__(self, canvas_size, graph_bottom_left, graph_top_right, background_color=None, pad=None, key=None, + def __init__(self, canvas_size, graph_bottom_left, graph_top_right, background_color=None, pad=None, change_submits=False, drag_submits=False, key=None, tooltip=None): ''' Graph Element @@ -1598,19 +1598,38 @@ class Graph(Element): self.TopRight = graph_top_right self._TKCanvas = None self._TKCanvas2 = None - + self.ChangeSubmits = change_submits + self.DragSubmits = drag_submits + self.ClickPosition = (None, None) + self.MouseButtonDown = False super().__init__(ELEM_TYPE_GRAPH, background_color=background_color, size=canvas_size, pad=pad, key=key, tooltip=tooltip) return def _convert_xy_to_canvas_xy(self, x_in, y_in): + if None in (x_in,y_in): + return None, None scale_x = (self.CanvasSize[0] - 0) / (self.TopRight[0] - self.BottomLeft[0]) scale_y = (0 - self.CanvasSize[1]) / (self.TopRight[1] - self.BottomLeft[1]) new_x = 0 + scale_x * (x_in - self.BottomLeft[0]) new_y = self.CanvasSize[1] + scale_y * (y_in - self.BottomLeft[1]) return new_x, new_y + + def _convert_canvas_xy_to_xy(self, x_in, y_in): + if None in (x_in,y_in): + return None, None + scale_x = (self.CanvasSize[0] - 0) / (self.TopRight[0] - self.BottomLeft[0]) + scale_y = (0 - self.CanvasSize[1]) / (self.TopRight[1] - self.BottomLeft[1]) + + new_x = x_in/scale_x+self.BottomLeft[0] + new_y = (y_in - self.CanvasSize[1]) / scale_y + self.BottomLeft[1] + return int(new_x), int(new_y) + + def DrawLine(self, point_from, point_to, color='black', width=1): + if point_from == (None, None): + return converted_point_from = self._convert_xy_to_canvas_xy(point_from[0], point_from[1]) converted_point_to = self._convert_xy_to_canvas_xy(point_to[0], point_to[1]) if self._TKCanvas2 is None: @@ -1620,6 +1639,8 @@ class Graph(Element): return self._TKCanvas2.create_line(converted_point_from, converted_point_to, width=width, fill=color) def DrawPoint(self, point, size=2, color='black'): + if point == (None, None): + return converted_point = self._convert_xy_to_canvas_xy(point[0], point[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') @@ -1630,6 +1651,8 @@ class Graph(Element): outline=color) def DrawCircle(self, center_location, radius, fill_color=None, line_color='black'): + if center_location == (None, None): + return converted_point = self._convert_xy_to_canvas_xy(center_location[0], center_location[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') @@ -1672,6 +1695,8 @@ class Graph(Element): converted_bottom_right[1], fill=fill_color, outline=line_color) def DrawText(self, text, location, color='black', font=None, angle=0): + if location == (None, None): + return converted_point = self._convert_xy_to_canvas_xy(location[0], location[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') @@ -1722,6 +1747,50 @@ class Graph(Element): print('*** form = sg.Window("My Form").Layout(layout).Finalize() ***') return self._TKCanvas2 + # Realtime button release callback + def ButtonReleaseCallBack(self, event): + self.ClickPosition = (None, None) + self.LastButtonClickedWasRealtime = not self.DragSubmits + if self.Key is not None: + self.ParentForm.LastButtonClicked = self.Key + else: + self.ParentForm.LastButtonClicked = '__GRAPH__' # need to put something rather than None + if self.ParentForm.CurrentlyRunningMainloop: + self.ParentForm.TKroot.quit() + if self.DragSubmits: + self.ParentForm.LastButtonClicked = None + self.MouseButtonDown = False + + + # Realtime button callback + def ButtonPressCallBack(self, event): + self.ClickPosition = self._convert_canvas_xy_to_xy(event.x, event.y) + self.ParentForm.LastButtonClickedWasRealtime = self.DragSubmits + if self.Key is not None: + self.ParentForm.LastButtonClicked = self.Key + else: + self.ParentForm.LastButtonClicked = '__GRAPH__' # need to put something rather than None + if self.ParentForm.CurrentlyRunningMainloop: + self.ParentForm.TKroot.quit() # kick out of loop if read was called + self.MouseButtonDown = True + + + # Realtime button callback + def MotionCallBack(self, event): + if not self.MouseButtonDown: + return + self.ClickPosition = self._convert_canvas_xy_to_xy(event.x, event.y) + self.ParentForm.LastButtonClickedWasRealtime = self.DragSubmits + if self.Key is not None: + self.ParentForm.LastButtonClicked = self.Key + else: + self.ParentForm.LastButtonClicked = '__GRAPH__' # need to put something rather than None + if self.ParentForm.CurrentlyRunningMainloop: + self.ParentForm.TKroot.quit() # kick out of loop if read was called + + + + def __del__(self): super().__del__() @@ -3641,6 +3710,8 @@ def BuildResultsForSubform(form, initialize_only, top_level_form): value = element.SelectedRows elif element.Type == ELEM_TYPE_TREE: value = element.SelectedRows + elif element.Type == ELEM_TYPE_GRAPH: + value = element.ClickPosition else: value = None @@ -4362,6 +4433,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.Tooltip is not None: element.TooltipObject = ToolTip(element._TKCanvas, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) + # ------------------------- Graph element ------------------------- # elif element_type == ELEM_TYPE_GRAPH: width, height = element_size @@ -4379,6 +4451,11 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.Tooltip is not None: element.TooltipObject = ToolTip(element._TKCanvas, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) + if element.ChangeSubmits: + element._TKCanvas2.bind('', element.ButtonReleaseCallBack) + element._TKCanvas2.bind('', element.ButtonPressCallBack) + if element.DragSubmits: + element._TKCanvas2.bind('', element.MotionCallBack) # ------------------------- MENUBAR element ------------------------- # elif element_type == ELEM_TYPE_MENUBAR: menu_def = element.MenuDefinition