From 50261625a45c08693b7ce3a2130c79faa8254de0 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sun, 23 Sep 2018 12:10:25 -0400 Subject: [PATCH 1/2] Addec chaining capability to Finalize method... more compacting the user's code! --- PySimpleGUI.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index d1f7b02c..4d9fab53 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -2001,9 +2001,23 @@ class FlexForm: # return None, None return BuildResults(self, False, self) + + def Finalize(self): + if self.TKrootDestroyed: + return self + if not self.Shown: + self.Show(non_blocking=True) + try: + rc = self.TKroot.update() + except: + self.TKrootDestroyed = True + _my_windows.Decrement() + # return None, None + return self + # Another name for ReadNonBlocking. PrepareForUpdate = ReadNonBlocking - Finalize = ReadNonBlocking + # Finalize = ReadNonBlocking PreRead = ReadNonBlocking From 7e00dd16fe069de15729d063a810a01195289140 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sun, 23 Sep 2018 12:16:50 -0400 Subject: [PATCH 2/2] RELEASE 3.5.2 --- Demo_All_Widgets.py | 2 - Demo_Button_Click.py | 5 +- Demo_Button_States.py | 77 ++-- Demo_Canvas.py | 4 +- Demo_Chatterbot.py | 35 +- Demo_Desktop_Widget_CPU_Graph.py | 3 +- Demo_Disable_Elements.py | 8 +- Demo_Font_Sizer.py | 2 +- Demo_Func_Callback_Simulation.py | 36 +- Demo_Graph_Drawing.py | 5 +- Demo_Graph_Element_Sine_Wave.py | 5 +- Demo_Graph_Noise.py | 5 +- Demo_Matplotlib.py | 9 +- Demo_Ping_Line_Graph.py | 587 ++++++++++++++++++++++++++++++- Demo_Pong.py | 7 +- Demo_Super_Simple_Form.py | 18 +- Demo_Tabbed_Form.py | 144 ++++---- docs/index.md | 12 +- readme.md | 12 +- 19 files changed, 745 insertions(+), 231 deletions(-) diff --git a/Demo_All_Widgets.py b/Demo_All_Widgets.py index 6a83153e..bf81163d 100644 --- a/Demo_All_Widgets.py +++ b/Demo_All_Widgets.py @@ -3,13 +3,11 @@ import PySimpleGUI as sg sg.ChangeLookAndFeel('GreenTan') - # ------ Menu Definition ------ # menu_def = [['File', ['Open', 'Save', 'Exit', 'Properties']], ['Edit', ['Paste', ['Special', 'Normal', ], 'Undo'], ], ['Help', 'About...'], ] - # ------ Column Definition ------ # column1 = [[sg.Text('Column 1', background_color='#F7F3EC', justification='center', size=(10, 1))], [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 1')], diff --git a/Demo_Button_Click.py b/Demo_Button_Click.py index 4a4ba306..2dfa029c 100644 --- a/Demo_Button_Click.py +++ b/Demo_Button_Click.py @@ -12,10 +12,7 @@ layout = [ sg.ReadFormButton('Submit', button_color=('white', 'springgreen4'), key='submit')] ] -form = sg.FlexForm("Button Click", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False, - default_button_element_size=(12,1)) -form.Layout(layout) -form.Finalize() # only needed if want to diable elements prior to showing form +form = sg.FlexForm("Button Click", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False, default_button_element_size=(12,1)).Layout(layout).Finalize() form.FindElement('submit').Update(disabled=True) diff --git a/Demo_Button_States.py b/Demo_Button_States.py index e0198d82..e3a9cfb7 100644 --- a/Demo_Button_States.py +++ b/Demo_Button_States.py @@ -1,58 +1,31 @@ import PySimpleGUI as sg -""" -Demonstrates using a "tight" layout with a Dark theme. -Shows how button states can be controlled by a user application. The program manages the disabled/enabled -states for buttons and changes the text color to show greyed-out (disabled) buttons -""" -sg.ChangeLookAndFeel('Dark') -sg.SetOptions(element_padding=(0,0)) +sg.ChangeLookAndFeel('LightGreen') +sg.SetOptions(element_padding=(0, 0)) -layout = [[sg.T('User:', pad=((3,0),0)), sg.OptionMenu(values = ('User 1', 'User 2'), size=(20,1)), sg.T('0', size=(8,1))], - [sg.T('Customer:', pad=((3,0),0)), sg.OptionMenu(values=('Customer 1', 'Customer 2'), size=(20,1)), sg.T('1', size=(8,1))], - [sg.T('Notes:', pad=((3,0),0)), sg.In(size=(44,1), background_color='white', text_color='black')], - [sg.ReadFormButton('Start', button_color=('white', 'black'), key='Start'), - sg.ReadFormButton('Stop', button_color=('white', 'black'), key='Stop'), - sg.ReadFormButton('Reset', button_color=('white', 'firebrick3'), key='Reset'), - sg.ReadFormButton('Submit', button_color=('white', 'springgreen4'), key='Submit')] - ] +# ------ Menu Definition ------ # +menu_def = [['File', ['Open', 'Save', 'Exit' ]], + ['Edit', ['Paste', ['Special', 'Normal', ], 'Undo'], ], + ['Help', 'About...'], ] -form = sg.FlexForm("Time Tracker", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False, - default_button_element_size=(12,1)) -form.Layout(layout) -form.Finalize() -form.FindElement('Stop').Update(disabled=True) -form.FindElement('Reset').Update(disabled=True) -form.FindElement('Submit').Update(disabled=True) -recording = have_data = False +# ------ GUI Defintion ------ # +layout = [ + [sg.Menu(menu_def)], + [sg.Output(size=(60, 20))] +] + +form = sg.FlexForm("Windows-like program", default_element_size=(12, 1), auto_size_text=False, auto_size_buttons=False, + default_button_element_size=(12, 1)).Layout(layout) + +# ------ Loop & Process button menu choices ------ # while True: button, values = form.Read() - print(button) - if button is None: - exit(69) - if button is 'Start': - form.FindElement('Start').Update(disabled=True) - form.FindElement('Stop').Update(disabled=False) - form.FindElement('Reset').Update(disabled=False) - form.FindElement('Submit').Update(disabled=True) - recording = True - elif button is 'Stop' and recording: - form.FindElement('Stop').Update(disabled=True) - form.FindElement('Start').Update(disabled=False) - form.FindElement('Submit').Update(disabled=False) - recording = False - have_data = True - elif button is 'Reset': - form.FindElement('Stop').Update(disabled=True) - form.FindElement('Start').Update(disabled=False) - form.FindElement('Submit').Update(disabled=True) - form.FindElement('Reset').Update(disabled=False) - recording = False - have_data = False - elif button is 'Submit' and have_data: - form.FindElement('Stop').Update(disabled=True) - form.FindElement('Start').Update(disabled=False) - form.FindElement('Submit').Update(disabled=True) - form.FindElement('Reset').Update(disabled=False) - recording = False - + if button == None or button == 'Exit': + break + print('Button = ', button) + # ------ Process menu choices ------ # + if button == 'About...': + sg.Popup('About this program', 'Version 1.0', 'PySimpleGUI rocks...') + elif button == 'Open': + filename = sg.PopupGetFile('file to open', no_window=True) + print(filename) \ No newline at end of file diff --git a/Demo_Canvas.py b/Demo_Canvas.py index 05156c7e..cbe01caa 100644 --- a/Demo_Canvas.py +++ b/Demo_Canvas.py @@ -6,9 +6,7 @@ layout = [ [sg.T('Change circle color to:'), sg.ReadFormButton('Red'), sg.ReadFormButton('Blue')] ] -form = sg.FlexForm('Canvas test') -form.Layout(layout) -form.Finalize() +form = sg.FlexForm('Canvas test').Layout(layout).Finalize() cir = form.FindElement('canvas').TKCanvas.create_oval(50, 50, 100, 100) diff --git a/Demo_Chatterbot.py b/Demo_Chatterbot.py index f7936482..12832a46 100644 --- a/Demo_Chatterbot.py +++ b/Demo_Chatterbot.py @@ -12,6 +12,7 @@ to collect user input that is sent to the chatbot. The reply is displayed in th # Create the 'Trainer GUI' # The Trainer GUI consists of a lot of progress bars stacked on top of each other sg.ChangeLookAndFeel('GreenTan') +sg.DebugWin() MAX_PROG_BARS = 20 # number of training sessions bars = [] texts = [] @@ -21,8 +22,7 @@ for i in range(MAX_PROG_BARS): texts.append(sg.T(' ' * 20, size=(20, 1), justification='right')) training_layout += [[texts[i], bars[i]],] # add a single row -training_form = sg.FlexForm('Training') -training_form.Layout(training_layout) +training_form = sg.FlexForm('Training').Layout(training_layout) current_bar = 0 # callback function for training runs @@ -50,19 +50,20 @@ chatbot = ChatBot('Ron Obvious', trainer='chatterbot.trainers.ChatterBotCorpusTr chatbot.train("chatterbot.corpus.english") ################# GUI ################# -with sg.FlexForm('Chat Window', auto_size_text=True, default_element_size=(30, 2)) as form: - layout = [[sg.Output(size=(80, 20))], - [sg.Multiline(size=(70, 5), enter_submits=True), - sg.ReadFormButton('SEND', bind_return_key=True), sg.ReadFormButton('EXIT')]] - form.Layout(layout) - # ---===--- Loop taking in user input and using it to query HowDoI web oracle --- # - while True: - button, (value,) = form.Read() - if button is not 'SEND': - break - string = value.rstrip() - print(' '+string) - # send the user input to chatbot to get a response - response = chatbot.get_response(value.rstrip()) - print(response) \ No newline at end of file +layout = [[sg.Output(size=(80, 20))], + [sg.Multiline(size=(70, 5), enter_submits=True), + sg.ReadFormButton('SEND', bind_return_key=True), sg.ReadFormButton('EXIT')]] + +form = sg.FlexForm('Chat Window', auto_size_text=True, default_element_size=(30, 2)).Layout(layout) + +# ---===--- Loop taking in user input and using it to query HowDoI web oracle --- # +while True: + button, (value,) = form.Read() + if button is not 'SEND': + break + string = value.rstrip() + print(' '+string) + # send the user input to chatbot to get a response + response = chatbot.get_response(value.rstrip()) + print(response) \ No newline at end of file diff --git a/Demo_Desktop_Widget_CPU_Graph.py b/Demo_Desktop_Widget_CPU_Graph.py index ddc6663a..3456ce3e 100644 --- a/Demo_Desktop_Widget_CPU_Graph.py +++ b/Demo_Desktop_Widget_CPU_Graph.py @@ -36,8 +36,7 @@ def main(): layout = [ [sg.Quit( button_color=('white','black')), sg.T('', pad=((100,0),0), font='Any 15', key='output')], [sg.Graph(CANVAS_SIZE, (0,0), (SAMPLES,SAMPLE_MAX),background_color='black', key='graph')],] - form = sg.FlexForm('CPU Graph', grab_anywhere=True, keep_on_top=True, background_color='black', no_titlebar=True, use_default_focus=False) - form.Layout(layout) + form = sg.FlexForm('CPU Graph', grab_anywhere=True, keep_on_top=True, background_color='black', no_titlebar=True, use_default_focus=False).Layout(layout) graph = form.FindElement('graph') output = form.FindElement('output') diff --git a/Demo_Disable_Elements.py b/Demo_Disable_Elements.py index cf351a8f..aed84807 100644 --- a/Demo_Disable_Elements.py +++ b/Demo_Disable_Elements.py @@ -20,13 +20,9 @@ layout = [ sg.ReadFormButton('Values', button_color=('white', 'springgreen4')), sg.SimpleButton('Exit', button_color=('white', '#00406B'))]] -form = sg.FlexForm("Time Tracker", default_element_size=(12, 1), text_justification='r', auto_size_text=False, +form = sg.FlexForm("Disable Elements Demo", default_element_size=(12, 1), text_justification='r', auto_size_text=False, auto_size_buttons=False, keep_on_top=True, grab_anywhere=False, - default_button_element_size=(12, 1)) - -form.Layout(layout) - -form.Finalize() + default_button_element_size=(12, 1)).Layout(layout).Finalize() form.FindElement('cbox').Update(disabled=True) form.FindElement('listbox').Update(disabled=True) diff --git a/Demo_Font_Sizer.py b/Demo_Font_Sizer.py index e79e686e..d030af93 100644 --- a/Demo_Font_Sizer.py +++ b/Demo_Font_Sizer.py @@ -11,7 +11,7 @@ form = sg.FlexForm("Font size selector", grab_anywhere=False) form.Layout(layout) while True: button, values= form.Read() - if button is None: + if button is None or button == 'Quit': break sz_spin = int(values['spin']) sz_slider = int(values['slider']) diff --git a/Demo_Func_Callback_Simulation.py b/Demo_Func_Callback_Simulation.py index 198337c3..a3f5df84 100644 --- a/Demo_Func_Callback_Simulation.py +++ b/Demo_Func_Callback_Simulation.py @@ -1,36 +1,14 @@ import PySimpleGUI as sg -# This design pattern simulates button callbacks -# Note that callbacks are NOT a part of the package's interface to the -# caller intentionally. The underlying implementation actually does use -# tkinter callbacks. They are simply hidden from the user. +layout = [[sg.Text('Filename', )], + [sg.Input(), sg.FileBrowse()], + [sg.OK(), sg.Cancel()]] -# The callback functions -def button1(): - print('Button 1 callback') +button, (number,) = sg.FlexForm('Get filename example').LayoutAndRead(layout) -def button2(): - print('Button 2 callback') -# Create a standard form -form = sg.FlexForm('Button callback example') -# Layout the design of the GUI -layout = [[sg.Text('Please click a button', auto_size_text=True)], - [sg.ReadFormButton('1'), sg.ReadFormButton('2'), sg.Quit()]] -# Show the form to the user -form.Layout(layout) -# Event loop. Read buttons, make callbacks -while True: - # Read the form - button, value = form.Read() - # Take appropriate action based on button - if button == '1': - button1() - elif button == '2': - button2() - elif button =='Quit' or button is None: - break +import PySimpleGUI as sg -# All done! -sg.PopupOK('Done') +button, (filename,) = sg.FlexForm('Get filename example').LayoutAndRead( + [[sg.Text('Filename')], [sg.Input(), sg.FileBrowse()], [sg.OK(), sg.Cancel()]]) \ No newline at end of file diff --git a/Demo_Graph_Drawing.py b/Demo_Graph_Drawing.py index fc4ca3c8..de8a82f7 100644 --- a/Demo_Graph_Drawing.py +++ b/Demo_Graph_Drawing.py @@ -5,15 +5,14 @@ layout = [ [sg.T('Change circle color to:'), sg.ReadFormButton('Red'), sg.ReadFormButton('Blue'), sg.ReadFormButton('Move')] ] -form = sg.FlexForm('Canvas test') -form.Layout(layout) -form.Finalize() +form = sg.FlexForm('Graph test').Layout(layout).Finalize() graph = form.FindElement('graph') circle = graph.DrawCircle((75,75), 25, fill_color='black',line_color='white') point = graph.DrawPoint((75,75), 10, color='green') oval = graph.DrawOval((25,300), (100,280), fill_color='purple', line_color='purple' ) rectangle = graph.DrawRectangle((25,300), (100,280), line_color='purple' ) +line = graph.DrawLine((0,0), (100,100)) while True: button, values = form.Read() diff --git a/Demo_Graph_Element_Sine_Wave.py b/Demo_Graph_Element_Sine_Wave.py index 0d451067..5d922fde 100644 --- a/Demo_Graph_Element_Sine_Wave.py +++ b/Demo_Graph_Element_Sine_Wave.py @@ -1,10 +1,9 @@ import math import PySimpleGUI as sg -layout = [[sg.Graph(canvas_size=(400, 400), graph_bottom_left=(-100,-100), graph_top_right=(100,100), background_color='white', key='graph')],] +layout = [[sg.Graph(canvas_size=(400, 400), graph_bottom_left=(-100,-100), graph_top_right=(100,100), background_color='white', key='graph', tooltip='This is a cool graph!')],] -form = sg.FlexForm('Graph of Sine Function').Layout(layout) -form.Finalize() +form = sg.FlexForm('Graph of Sine Function', grab_anywhere=True).Layout(layout).Finalize() graph = form.FindElement('graph') graph.DrawLine((-100,0), (100,0)) diff --git a/Demo_Graph_Noise.py b/Demo_Graph_Noise.py index da52464d..fbef4bc4 100644 --- a/Demo_Graph_Noise.py +++ b/Demo_Graph_Noise.py @@ -31,10 +31,7 @@ def main(): layout = [ [sg.Quit( button_color=('white','black'))], [sg.Graph(CANVAS_SIZE, (0,0), (SAMPLES,SAMPLE_MAX),background_color='black', key='graph')],] - form = sg.FlexForm('Canvas test', grab_anywhere=True, background_color='black', no_titlebar=False, use_default_focus=False) - form.Layout(layout) - - form.Finalize() + form = sg.FlexForm('Canvas test', grab_anywhere=True, background_color='black', no_titlebar=False, use_default_focus=False).Layout(layout).Finalize() graph = form.FindElement('graph') prev_response_time = None diff --git a/Demo_Matplotlib.py b/Demo_Matplotlib.py index 8b5d334d..7b2553f7 100644 --- a/Demo_Matplotlib.py +++ b/Demo_Matplotlib.py @@ -107,19 +107,16 @@ fig = plt.gcf() # if using Pyplot then get the figure from the plot # information to display. # # --------------------------------------------------------------------------------# figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds -canvas_elem = sg.Canvas(size=(figure_w, figure_h)) # get the canvas we'll be drawing on # define the form layout layout = [[sg.Text('Plot test')], - [canvas_elem], + [sg.Canvas(size=(figure_w, figure_h), key='canvas')], [sg.OK(pad=((figure_w / 2, 0), 3), size=(4, 2))]] # create the form and show it without the plot -form = sg.FlexForm('Demo Application - Embedding Matplotlib In PySimpleGUI') -form.Layout(layout) -form.ReadNonBlocking() +form = sg.FlexForm('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout).Finalize() # add the plot to the window -fig_photo = draw_figure(canvas_elem.TKCanvas, fig) +fig_photo = draw_figure(form.FindElement('canvas').TKCanvas, fig) # show it all again and get buttons button, values = form.Read() diff --git a/Demo_Ping_Line_Graph.py b/Demo_Ping_Line_Graph.py index 1faa9754..ef6e2f4d 100644 --- a/Demo_Ping_Line_Graph.py +++ b/Demo_Ping_Line_Graph.py @@ -1,8 +1,587 @@ -import ping from threading import Thread import time import PySimpleGUI as sg +# !/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" + A pure python ping implementation using raw sockets. + + (This is Python 3 port of https://github.com/jedie/python-ping) + (Tested and working with python 2.7, should work with 2.6+) + + Note that ICMP messages can only be sent from processes running as root + (in Windows, you must run this script as 'Administrator'). + + Derived from ping.c distributed in Linux's netkit. That code is + copyright (c) 1989 by The Regents of the University of California. + That code is in turn derived from code written by Mike Muuss of the + US Army Ballistic Research Laboratory in December, 1983 and + placed in the public domain. They have my thanks. + + Bugs are naturally mine. I'd be glad to hear about them. There are + certainly word - size dependencies here. + + Copyright (c) Matthew Dixon Cowles, . + Distributable under the terms of the GNU General Public License + version 2. Provided with no warranties of any sort. + + Original Version from Matthew Dixon Cowles: + -> ftp://ftp.visi.com/users/mdc/ping.py + + Rewrite by Jens Diemer: + -> http://www.python-forum.de/post-69122.html#69122 + + Rewrite by George Notaras: + -> http://www.g-loaded.eu/2009/10/30/python-ping/ + + Enhancements by Martin Falatic: + -> http://www.falatic.com/index.php/39/pinging-with-python + + Enhancements and fixes by Georgi Kolev: + -> http://github.com/jedie/python-ping/ + + Bug fix by Andrejs Rozitis: + -> http://github.com/rozitis/python-ping/ + + Revision history + ~~~~~~~~~~~~~~~~ + May 1, 2014 + ----------- + Little modifications by Mohammad Emami + - Added Python 3 support. For now this project will just support + python 3.x + - Tested with python 3.3 + - version was upped to 0.6 + + March 19, 2013 + -------------- + * Fixing bug to prevent divide by 0 during run-time. + + January 26, 2012 + ---------------- + * Fixing BUG #4 - competability with python 2.x [tested with 2.7] + - Packet data building is different for 2.x and 3.x. + 'cose of the string/bytes difference. + * Fixing BUG #10 - the multiple resolv issue. + - When pinging domain names insted of hosts (for exmaple google.com) + you can get different IP every time you try to resolv it, we should + resolv the host only once and stick to that IP. + * Fixing BUGs #3 #10 - Doing hostname resolv only once. + * Fixing BUG #14 - Removing all 'global' stuff. + - You should not use globul! Its bad for you...and its not thread safe! + * Fix - forcing the use of different times on linux/windows for + more accurate mesurments. (time.time - linux/ time.clock - windows) + * Adding quiet_ping function - This way we'll be able to use this script + as external lib. + * Changing default timeout to 3s. (1second is not enought) + * Switching data syze to packet size. It's easyer for the user to ignore the + fact that the packet headr is 8b and the datasize 64 will make packet with + size 72. + + October 12, 2011 + -------------- + Merged updates from the main project + -> https://github.com/jedie/python-ping + + September 12, 2011 + -------------- + Bugfixes + cleanup by Jens Diemer + Tested with Ubuntu + Windows 7 + + September 6, 2011 + -------------- + Cleanup by Martin Falatic. Restored lost comments and docs. Improved + functionality: constant time between pings, internal times consistently + use milliseconds. Clarified annotations (e.g., in the checksum routine). + Using unsigned data in IP & ICMP header pack/unpack unless otherwise + necessary. Signal handling. Ping-style output formatting and stats. + + August 3, 2011 + -------------- + Ported to py3k by Zach Ware. Mostly done by 2to3; also minor changes to + deal with bytes vs. string changes (no more ord() in checksum() because + >source_string< is actually bytes, added .encode() to data in + send_one_ping()). That's about it. + + March 11, 2010 + -------------- + changes by Samuel Stauffer: + - replaced time.clock with default_timer which is set to + time.clock on windows and time.time on other systems. + + November 8, 2009 + ---------------- + Improved compatibility with GNU/Linux systems. + + Fixes by: + * George Notaras -- http://www.g-loaded.eu + Reported by: + * Chris Hallman -- http://cdhallman.blogspot.com + + Changes in this release: + - Re-use time.time() instead of time.clock(). The 2007 implementation + worked only under Microsoft Windows. Failed on GNU/Linux. + time.clock() behaves differently under the two OSes[1]. + + [1] http://docs.python.org/library/time.html#time.clock + + May 30, 2007 + ------------ + little rewrite by Jens Diemer: + - change socket asterisk import to a normal import + - replace time.time() with time.clock() + - delete "return None" (or change to "return" only) + - in checksum() rename "str" to "source_string" + + December 4, 2000 + ---------------- + Changed the struct.pack() calls to pack the checksum and ID as + unsigned. My thanks to Jerome Poincheval for the fix. + + November 22, 1997 + ----------------- + Initial hack. Doesn't do much, but rather than try to guess + what features I (or others) will want in the future, I've only + put in what I need now. + + December 16, 1997 + ----------------- + For some reason, the checksum bytes are in the wrong order when + this is run under Solaris 2.X for SPARC but it works right under + Linux x86. Since I don't know just what's wrong, I'll swap the + bytes always and then do an htons(). + + =========================================================================== + IP header info from RFC791 + -> http://tools.ietf.org/html/rfc791) + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Version| IHL |Type of Service| Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Identification |Flags| Fragment Offset | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Time to Live | Protocol | Header Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Address | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Destination Address | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Options | Padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + =========================================================================== + ICMP Echo / Echo Reply Message header info from RFC792 + -> http://tools.ietf.org/html/rfc792 + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Identifier | Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data ... + +-+-+-+-+- + + =========================================================================== + ICMP parameter info: + -> http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml + + =========================================================================== + An example of ping's typical output: + + PING heise.de (193.99.144.80): 56 data bytes + 64 bytes from 193.99.144.80: icmp_seq=0 ttl=240 time=127 ms + 64 bytes from 193.99.144.80: icmp_seq=1 ttl=240 time=127 ms + 64 bytes from 193.99.144.80: icmp_seq=2 ttl=240 time=126 ms + 64 bytes from 193.99.144.80: icmp_seq=3 ttl=240 time=126 ms + 64 bytes from 193.99.144.80: icmp_seq=4 ttl=240 time=127 ms + + ----heise.de PING Statistics---- + 5 packets transmitted, 5 packets received, 0.0% packet loss + round-trip (ms) min/avg/max/med = 126/127/127/127 + + =========================================================================== +""" + +# =============================================================================# +import argparse +import os, sys, socket, struct, select, time, signal + +__description__ = 'A pure python ICMP ping implementation using raw sockets.' + +if sys.platform == "win32": + # On Windows, the best timer is time.clock() + default_timer = time.clock +else: + # On most other platforms the best timer is time.time() + default_timer = time.time + +NUM_PACKETS = 3 +PACKET_SIZE = 64 +WAIT_TIMEOUT = 3.0 + +# =============================================================================# +# ICMP parameters + +ICMP_ECHOREPLY = 0 # Echo reply (per RFC792) +ICMP_ECHO = 8 # Echo request (per RFC792) +ICMP_MAX_RECV = 2048 # Max size of incoming buffer + +MAX_SLEEP = 1000 + + +class MyStats: + thisIP = "0.0.0.0" + pktsSent = 0 + pktsRcvd = 0 + minTime = 999999999 + maxTime = 0 + totTime = 0 + avrgTime = 0 + fracLoss = 1.0 + + +myStats = MyStats # NOT Used globally anymore. + + +# =============================================================================# +def checksum(source_string): + """ + A port of the functionality of in_cksum() from ping.c + Ideally this would act on the string as a series of 16-bit ints (host + packed), but this works. + Network data is big-endian, hosts are typically little-endian + """ + countTo = (int(len(source_string) / 2)) * 2 + sum = 0 + count = 0 + + # Handle bytes in pairs (decoding as short ints) + loByte = 0 + hiByte = 0 + while count < countTo: + if (sys.byteorder == "little"): + loByte = source_string[count] + hiByte = source_string[count + 1] + else: + loByte = source_string[count + 1] + hiByte = source_string[count] + try: # For Python3 + sum = sum + (hiByte * 256 + loByte) + except: # For Python2 + sum = sum + (ord(hiByte) * 256 + ord(loByte)) + count += 2 + + # Handle last byte if applicable (odd-number of bytes) + # Endianness should be irrelevant in this case + if countTo < len(source_string): # Check for odd length + loByte = source_string[len(source_string) - 1] + try: # For Python3 + sum += loByte + except: # For Python2 + sum += ord(loByte) + + sum &= 0xffffffff # Truncate sum to 32 bits (a variance from ping.c, which + # uses signed ints, but overflow is unlikely in ping) + + sum = (sum >> 16) + (sum & 0xffff) # Add high 16 bits to low 16 bits + sum += (sum >> 16) # Add carry from above (if any) + answer = ~sum & 0xffff # Invert and truncate to 16 bits + answer = socket.htons(answer) + + return answer + + +# =============================================================================# +def do_one(myStats, destIP, hostname, timeout, mySeqNumber, packet_size, quiet=False): + """ + Returns either the delay (in ms) or None on timeout. + """ + delay = None + + try: # One could use UDP here, but it's obscure + mySocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname("icmp")) + except socket.error as e: + print("failed. (socket error: '%s')" % e.args[1]) + raise # raise the original error + + my_ID = os.getpid() & 0xFFFF + + sentTime = send_one_ping(mySocket, destIP, my_ID, mySeqNumber, packet_size) + if sentTime == None: + mySocket.close() + return delay + + myStats.pktsSent += 1 + + recvTime, dataSize, iphSrcIP, icmpSeqNumber, iphTTL = receive_one_ping(mySocket, my_ID, timeout) + + mySocket.close() + + if recvTime: + delay = (recvTime - sentTime) * 1000 + if not quiet: + print("%d bytes from %s: icmp_seq=%d ttl=%d time=%d ms" % ( + dataSize, socket.inet_ntoa(struct.pack("!I", iphSrcIP)), icmpSeqNumber, iphTTL, delay) + ) + myStats.pktsRcvd += 1 + myStats.totTime += delay + if myStats.minTime > delay: + myStats.minTime = delay + if myStats.maxTime < delay: + myStats.maxTime = delay + else: + delay = None + print("Request timed out.") + + return delay + + +# =============================================================================# +def send_one_ping(mySocket, destIP, myID, mySeqNumber, packet_size): + """ + Send one ping to the given >destIP<. + """ + # destIP = socket.gethostbyname(destIP) + + # Header is type (8), code (8), checksum (16), id (16), sequence (16) + # (packet_size - 8) - Remove header size from packet size + myChecksum = 0 + + # Make a dummy heder with a 0 checksum. + header = struct.pack( + "!BBHHH", ICMP_ECHO, 0, myChecksum, myID, mySeqNumber + ) + + padBytes = [] + startVal = 0x42 + # 'cose of the string/byte changes in python 2/3 we have + # to build the data differnely for different version + # or it will make packets with unexpected size. + if sys.version[:1] == '2': + bytes = struct.calcsize("d") + data = ((packet_size - 8) - bytes) * "Q" + data = struct.pack("d", default_timer()) + data + else: + for i in range(startVal, startVal + (packet_size - 8)): + padBytes += [(i & 0xff)] # Keep chars in the 0-255 range + # data = bytes(padBytes) + data = bytearray(padBytes) + + # Calculate the checksum on the data and the dummy header. + myChecksum = checksum(header + data) # Checksum is in network order + + # Now that we have the right checksum, we put that in. It's just easier + # to make up a new header than to stuff it into the dummy. + header = struct.pack( + "!BBHHH", ICMP_ECHO, 0, myChecksum, myID, mySeqNumber + ) + + packet = header + data + + sendTime = default_timer() + + try: + mySocket.sendto(packet, (destIP, 1)) # Port number is irrelevant for ICMP + except socket.error as e: + print("General failure (%s)" % (e.args[1])) + return + + return sendTime + + +# =============================================================================# +def receive_one_ping(mySocket, myID, timeout): + """ + Receive the ping from the socket. Timeout = in ms + """ + timeLeft = timeout / 1000 + + while True: # Loop while waiting for packet or timeout + startedSelect = default_timer() + whatReady = select.select([mySocket], [], [], timeLeft) + howLongInSelect = (default_timer() - startedSelect) + if whatReady[0] == []: # Timeout + return None, 0, 0, 0, 0 + + timeReceived = default_timer() + + recPacket, addr = mySocket.recvfrom(ICMP_MAX_RECV) + + ipHeader = recPacket[:20] + iphVersion, iphTypeOfSvc, iphLength, \ + iphID, iphFlags, iphTTL, iphProtocol, \ + iphChecksum, iphSrcIP, iphDestIP = struct.unpack( + "!BBHHHBBHII", ipHeader + ) + + icmpHeader = recPacket[20:28] + icmpType, icmpCode, icmpChecksum, \ + icmpPacketID, icmpSeqNumber = struct.unpack( + "!BBHHH", icmpHeader + ) + + if icmpPacketID == myID: # Our packet + dataSize = len(recPacket) - 28 + # print (len(recPacket.encode())) + return timeReceived, (dataSize + 8), iphSrcIP, icmpSeqNumber, iphTTL + + timeLeft = timeLeft - howLongInSelect + if timeLeft <= 0: + return None, 0, 0, 0, 0 + + +# =============================================================================# +def dump_stats(myStats): + """ + Show stats when pings are done + """ + print("\n----%s PYTHON PING Statistics----" % (myStats.thisIP)) + + if myStats.pktsSent > 0: + myStats.fracLoss = (myStats.pktsSent - myStats.pktsRcvd) / myStats.pktsSent + + print("%d packets transmitted, %d packets received, %0.1f%% packet loss" % ( + myStats.pktsSent, myStats.pktsRcvd, 100.0 * myStats.fracLoss + )) + + if myStats.pktsRcvd > 0: + print("round-trip (ms) min/avg/max = %d/%0.1f/%d" % ( + myStats.minTime, myStats.totTime / myStats.pktsRcvd, myStats.maxTime + )) + + print("") + return + + +# =============================================================================# +def signal_handler(signum, frame): + """ + Handle exit via signals + """ + dump_stats() + print("\n(Terminated with signal %d)\n" % (signum)) + sys.exit(0) + + +# =============================================================================# +def verbose_ping(hostname, timeout=WAIT_TIMEOUT, count=NUM_PACKETS, + packet_size=PACKET_SIZE, path_finder=False): + """ + Send >count< ping to >destIP< with the given >timeout< and display + the result. + """ + signal.signal(signal.SIGINT, signal_handler) # Handle Ctrl-C + if hasattr(signal, "SIGBREAK"): + # Handle Ctrl-Break e.g. under Windows + signal.signal(signal.SIGBREAK, signal_handler) + + myStats = MyStats() # Reset the stats + + mySeqNumber = 0 # Starting value + + try: + destIP = socket.gethostbyname(hostname) + print("\nPYTHON PING %s (%s): %d data bytes" % (hostname, destIP, packet_size)) + except socket.gaierror as e: + print("\nPYTHON PING: Unknown host: %s (%s)" % (hostname, e.args[1])) + print() + return + + myStats.thisIP = destIP + + for i in range(count): + delay = do_one(myStats, destIP, hostname, timeout, mySeqNumber, packet_size) + + if delay == None: + delay = 0 + + mySeqNumber += 1 + + # Pause for the remainder of the MAX_SLEEP period (if applicable) + if (MAX_SLEEP > delay): + time.sleep((MAX_SLEEP - delay) / 1000) + + dump_stats(myStats) + + +# =============================================================================# +def quiet_ping(hostname, timeout=WAIT_TIMEOUT, count=NUM_PACKETS, + packet_size=PACKET_SIZE, path_finder=False): + """ + Same as verbose_ping, but the results are returned as tuple + """ + myStats = MyStats() # Reset the stats + mySeqNumber = 0 # Starting value + + try: + destIP = socket.gethostbyname(hostname) + except socket.gaierror as e: + return False + + myStats.thisIP = destIP + + # This will send packet that we dont care about 0.5 seconds before it starts + # acrutally pinging. This is needed in big MAN/LAN networks where you sometimes + # loose the first packet. (while the switches find the way... :/ ) + if path_finder: + fakeStats = MyStats() + do_one(fakeStats, destIP, hostname, timeout, + mySeqNumber, packet_size, quiet=True) + time.sleep(0.5) + + for i in range(count): + delay = do_one(myStats, destIP, hostname, timeout, + mySeqNumber, packet_size, quiet=True) + + if delay == None: + delay = 0 + + mySeqNumber += 1 + + # Pause for the remainder of the MAX_SLEEP period (if applicable) + if (MAX_SLEEP > delay): + time.sleep((MAX_SLEEP - delay) / 1000) + + if myStats.pktsSent > 0: + myStats.fracLoss = (myStats.pktsSent - myStats.pktsRcvd) / myStats.pktsSent + if myStats.pktsRcvd > 0: + myStats.avrgTime = myStats.totTime / myStats.pktsRcvd + + # return tuple(max_rtt, min_rtt, avrg_rtt, percent_lost) + return myStats.maxTime, myStats.minTime, myStats.avrgTime, myStats.fracLoss + + +# =============================================================================# +def main(): + parser = argparse.ArgumentParser(description=__description__) + parser.add_argument('-q', '--quiet', action='store_true', + help='quiet output') + parser.add_argument('-c', '--count', type=int, default=NUM_PACKETS, + help=('number of packets to be sent ' + '(default: %(default)s)')) + parser.add_argument('-W', '--timeout', type=float, default=WAIT_TIMEOUT, + help=('time to wait for a response in seoncds ' + '(default: %(default)s)')) + parser.add_argument('-s', '--packet-size', type=int, default=PACKET_SIZE, + help=('number of data bytes to be sent ' + '(default: %(default)s)')) + parser.add_argument('destination') + # args = parser.parse_args() + + ping = verbose_ping + # if args.quiet: + # ping = quiet_ping + ping('Google.com', timeout=1000) + # ping(args.destination, timeout=args.timeout*1000, count=args.count, + # packet_size=args.packet_size) + + # set coordinate system canvas_right = 300 canvas_left = 0 @@ -22,7 +601,7 @@ def ping_thread(args): global g_exit, g_response_time while not g_exit: - g_response_time = ping.quiet_ping('google.com', timeout=1000) + g_response_time = quiet_ping('google.com', timeout=1000) def convert_xy_to_canvas_xy(x_in,y_in): @@ -43,9 +622,7 @@ layout = [ [sg.T('Ping times to Google.com', font='Any 18')], [sg.Quit()] ] -form = sg.FlexForm('Canvas test', grab_anywhere=True) -form.Layout(layout) -form.Finalize() +form = sg.FlexForm('Ping Times To Google.com', grab_anywhere=True).Layout(layout).Finalize() canvas = form.FindElement('canvas').TKCanvas diff --git a/Demo_Pong.py b/Demo_Pong.py index 0e883804..3aef52c7 100644 --- a/Demo_Pong.py +++ b/Demo_Pong.py @@ -128,9 +128,8 @@ def pong(): layout = [[sg.Canvas(size=(700, 400), background_color='black', key='canvas')], [sg.T(''), sg.ReadFormButton('Quit')]] # ------------- Create window ------------- - form = sg.FlexForm('Canvas test', return_keyboard_events=True) - form.Layout(layout) - form.Finalize() # TODO Replace with call to form.Finalize once code released + form = sg.FlexForm('The Classic Game of Pong', return_keyboard_events=True).Layout(layout).Finalize() + # form.Finalize() # TODO Replace with call to form.Finalize once code released # ------------- Get the tkinter Canvas we're drawing on ------------- canvas = form.FindElement('canvas').TKCanvas @@ -150,7 +149,6 @@ def pong(): # ------------- Read the form, get keypresses ------------- button, values = form.ReadNonBlocking() - # ------------- If quit ------------- if button is None and values is None or button == 'Quit': exit(69) @@ -167,6 +165,7 @@ def pong(): if ball1.checkwin(): sg.Popup('Game Over', ball1.checkwin() + ' won!!') + break # ------------- Bottom of loop, delay between animations ------------- diff --git a/Demo_Super_Simple_Form.py b/Demo_Super_Simple_Form.py index a1039249..80c229a4 100644 --- a/Demo_Super_Simple_Form.py +++ b/Demo_Super_Simple_Form.py @@ -1,16 +1,14 @@ import PySimpleGUI as sg -# Very basic form. Return values as a dictionary -form = sg.FlexForm('Simple data entry form') # begin with a blank form - +form = sg.FlexForm('Simple data entry form') layout = [ - [sg.Text('Please enter your Name, Address, Phone')], - [sg.Text('Name', size=(15, 1)), sg.InputText('name', key='name')], - [sg.Text('Address', size=(15, 1)), sg.InputText('address', key='address')], - [sg.Text('Phone', size=(15, 1)), sg.InputText('phone', key='phone')], - [sg.Ok(), sg.Cancel()] - ] + [sg.Text('Please enter your Name, Address, Phone')], + [sg.Text('Name', size=(15, 1)), sg.InputText('1', key='name')], + [sg.Text('Address', size=(15, 1)), sg.InputText('2', key='address')], + [sg.Text('Phone', size=(15, 1)), sg.InputText('3', key='phone')], + [sg.Submit(), sg.Cancel()] +] button, values = form.LayoutAndRead(layout) -sg.Popup(button, values, values['name'], values['address'], values['phone']) +sg.Popup(button, values, values['name'], values['address'], values['phone']) \ No newline at end of file diff --git a/Demo_Tabbed_Form.py b/Demo_Tabbed_Form.py index d63d1205..21b640e1 100644 --- a/Demo_Tabbed_Form.py +++ b/Demo_Tabbed_Form.py @@ -1,87 +1,83 @@ import PySimpleGUI as sg -def eBaySuperSearcherGUI(): - # Drop Down list of options - configs = ('0 - Gruen - Started 2 days ago in Watches', - '1 - Gruen - Currently Active in Watches', - '2 - Alpina - Currently Active in Jewelry', - '3 - Gruen - Ends in 1 day in Watches', - '4 - Gruen - Completed in Watches', - '5 - Gruen - Advertising', - '6 - Gruen - Currently Active in Jewelry', - '7 - Gruen - Price Test', - '8 - Gruen - No brand name specified') +# Drop Down list of options +configs = ('0 - Gruen - Started 2 days ago in Watches', + '1 - Gruen - Currently Active in Watches', + '2 - Alpina - Currently Active in Jewelry', + '3 - Gruen - Ends in 1 day in Watches', + '4 - Gruen - Completed in Watches', + '5 - Gruen - Advertising', + '6 - Gruen - Currently Active in Jewelry', + '7 - Gruen - Price Test', + '8 - Gruen - No brand name specified') - us_categories = ('Use Default with no change', - 'All - 1', - 'Jewelry - 281', - ' Watches - 14324', - ' Wristwatches - 31387', - ' Pocket Watches - 3937', - 'Advertising - 34', - ' Watch Ads - 165254' - ) +us_categories = ('Use Default with no change', + 'All - 1', + 'Jewelry - 281', + ' Watches - 14324', + ' Wristwatches - 31387', + ' Pocket Watches - 3937', + 'Advertising - 34', + ' Watch Ads - 165254' + ) - german_categories =('Use Default with no change', - 'All - 1', - 'Jewelry - 281', - ' Watches - 14324', - ' Wristwatches - 31387', - ' Pocket Watches - 3937', - 'Advertising - 1', - ' Watch Ads - 19823' - ) +german_categories =('Use Default with no change', + 'All - 1', + 'Jewelry - 281', + ' Watches - 14324', + ' Wristwatches - 31387', + ' Pocket Watches - 3937', + 'Advertising - 1', + ' Watch Ads - 19823' + ) - # the form layout - with sg.FlexForm('EBay Super Searcher', auto_size_text=True) as form: - with sg.FlexForm('EBay Super Searcher', auto_size_text=False) as form2: - layout_tab_1 = [[sg.Text('eBay Super Searcher!', size=(60,1), font=('helvetica', 15))], - [sg.Text('Choose base configuration to run')], - [sg.InputCombo(configs)], - [sg.Text('_'*100, size=(80,1))], - [sg.InputText(),sg.Text('Choose Destination Folder'), sg.FolderBrowse(target=(sg.ThisRow,0))], - [sg.InputText(),sg.Text('Custom text to add to folder name')], - [sg.Text('_'*100, size=(80,1))], - [sg.Checkbox('US', default=True, size=(15, 1)), sg.Checkbox('German', size=(15, 1), default=True, )], - [sg.Radio('Active Listings','ActiveComplete', default = True,size=(15, 1)), sg.Radio('Completed Listings', 'ActiveComplete', size=(15, 1))], - [sg.Text('_'*100, size=(80,1))], - [sg.Checkbox('Save Images', size=(15,1)),sg.Checkbox('Save PDFs', size=(15,1)), sg.Checkbox('Extract PDFs', size=(15,1))], - [sg.Text('_'*100, size=(80,1))], - [sg.Text('Time Filters')], - [sg.Radio('No change','time', default=True),sg.Radio('ALL listings','time'),sg.Radio('Started 1 day ago','time', size=(15,1)),sg.Radio('Started 2 days ago','time', size=(15,1)), sg.Radio('Ends in 1 day','time', size=(15,1))], - [sg.Text('_'*100, size=(80,1))], - [sg.Text('Price Range'), sg.InputText(size=(10,1)),sg.Text('To'), sg.InputText(size=(10,1))], - [sg.Text('_'*100, size=(80,1))], - [sg.Submit(button_color=('red', 'yellow')), sg.Cancel(button_color=('white', 'blue'))]] +# the form layout +form = sg.FlexForm('EBay Super Searcher', auto_size_text=True) + +form2 = sg.FlexForm('EBay Super Searcher', auto_size_text=False) + +layout_tab_1 = [[sg.Text('eBay Super Searcher!', size=(60,1), font=('helvetica', 15))], + [sg.Text('Choose base configuration to run')], + [sg.InputCombo(configs)], + [sg.Text('_'*100, size=(80,1))], + [sg.InputText(),sg.Text('Choose Destination Folder'), sg.FolderBrowse(target=(sg.ThisRow,0))], + [sg.InputText(),sg.Text('Custom text to add to folder name')], + [sg.Text('_'*100, size=(80,1))], + [sg.Checkbox('US', default=True, size=(15, 1)), sg.Checkbox('German', size=(15, 1), default=True, )], + [sg.Radio('Active Listings','ActiveComplete', default = True,size=(15, 1)), sg.Radio('Completed Listings', 'ActiveComplete', size=(15, 1))], + [sg.Text('_'*100, size=(80,1))], + [sg.Checkbox('Save Images', size=(15,1)),sg.Checkbox('Save PDFs', size=(15,1)), sg.Checkbox('Extract PDFs', size=(15,1))], + [sg.Text('_'*100, size=(80,1))], + [sg.Text('Time Filters')], + [sg.Radio('No change','time', default=True),sg.Radio('ALL listings','time'),sg.Radio('Started 1 day ago','time', size=(15,1)),sg.Radio('Started 2 days ago','time', size=(15,1)), sg.Radio('Ends in 1 day','time', size=(15,1))], + [sg.Text('_'*100, size=(80,1))], + [sg.Text('Price Range'), sg.InputText(size=(10,1)),sg.Text('To'), sg.InputText(size=(10,1))], + [sg.Text('_'*100, size=(80,1))], + [sg.Submit(button_color=('red', 'yellow')), sg.Cancel(button_color=('white', 'blue'))]] - # First category is default (need to special case this) - layout_tab_2 = [[sg.Text('Choose Category')], - [sg.Text('US Categories'),sg.Text('German Categories')], - [sg.Radio(us_categories[0],'CATUS', default=True), sg.Radio(german_categories[0], 'CATDE', default=True)]] +# First category is default (need to special case this) +layout_tab_2 = [[sg.Text('Choose Category')], + [sg.Text('US Categories'),sg.Text('German Categories')], + [sg.Radio(us_categories[0],'CATUS', default=True), sg.Radio(german_categories[0], 'CATDE', default=True)]] - for i,cat in enumerate(us_categories): - if i == 0: continue # skip first one - layout_tab_2.append([sg.Radio(cat,'CATUS'), sg.Radio(german_categories[i],'CATDE')]) +for i,cat in enumerate(us_categories): + if i == 0: continue # skip first one + layout_tab_2.append([sg.Radio(cat,'CATUS'), sg.Radio(german_categories[i],'CATDE')]) - layout_tab_2.append([sg.Text('_' * 100, size=(75, 1))]) - layout_tab_2.append([sg.Text('US Search String Override')]) - layout_tab_2.append([sg.InputText(size=(100,1))]) - layout_tab_2.append([sg.Text('German Search String Override')]) - layout_tab_2.append([sg.InputText(size=(100,1))]) - layout_tab_2.append([sg.Text('Typical US Search String')]) - layout_tab_2.append([sg.InputText(size=(100,1), default_text='gruen -sara -quarz -quartz -embassy -bob -robert -elephants -adidas -LED ')]) - layout_tab_2.append([sg.Text('_' * 100, size=(75, 1))]) - layout_tab_2.append([sg.ReadButton('Submit', button_color=('red', 'yellow')), sg.Cancel(button_color=('white', 'blue'))]) +layout_tab_2.append([sg.Text('_' * 100, size=(75, 1))]) +layout_tab_2.append([sg.Text('US Search String Override')]) +layout_tab_2.append([sg.InputText(size=(100,1))]) +layout_tab_2.append([sg.Text('German Search String Override')]) +layout_tab_2.append([sg.InputText(size=(100,1))]) +layout_tab_2.append([sg.Text('Typical US Search String')]) +layout_tab_2.append([sg.InputText(size=(100,1), default_text='gruen -sara -quarz -quartz -embassy -bob -robert -elephants -adidas -LED ')]) +layout_tab_2.append([sg.Text('_' * 100, size=(75, 1))]) +layout_tab_2.append([sg.ReadButton('Submit', button_color=('red', 'yellow')), sg.Cancel(button_color=('white', 'blue'))]) - results = sg.ShowTabbedForm('eBay Super Searcher', (form,layout_tab_1,'Where To Save'), (form2, layout_tab_2, 'Categories & Search String')) - - return results +results = sg.ShowTabbedForm('eBay Super Searcher', (form,layout_tab_1,'Where To Save'), (form2, layout_tab_2, 'Categories & Search String')) -if __name__ == '__main__': - # sg.SetOptions(background_color='white') - results = eBaySuperSearcherGUI() - print(results) - sg.Popup('Results', results) \ No newline at end of file + +sg.Popup('Results', results) \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 578ced22..0a835cd5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,7 @@ # PySimpleGUI -![Python Version](https://img.shields.io/badge/PySimpleGUI_Version-3.5.1-red.svg?longCache=true&style=for-the-badge) +![Python Version](https://img.shields.io/badge/PySimpleGUI_Version-3.5.2-red.svg?longCache=true&style=for-the-badge) [Wiki for the latest news](https://github.com/MikeTheWatchGuy/PySimpleGUI/wiki) @@ -1846,8 +1846,8 @@ The order of operations to obtain a tkinter Canvas Widget is: [sg.OK(pad=((figure_w / 2, 0), 3), size=(4, 2))]] # create the form and show it without the plot - form = sg.FlexForm('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout) - form.Finalize() + form = sg.FlexForm('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout).Finalize() + # add the plot to the window fig_photo = draw_figure(form.FindElement('canvas').TKCanvas, fig) @@ -2518,6 +2518,7 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it | 03.04.01 | Sept 18, 2018 - See release notes | 03.05.00 | Sept 20, 2018 - See release notes | 03.05.01 | Sept 22, 2018 - See release notes +| 03.05.02 | Sept 23, 2018 - See release notes ### Release Notes 2.3 - Sliders, Listbox's and Image elements (oh my!) @@ -2600,6 +2601,11 @@ OneLineProgressMeter function added which gives you not only a one-line solution * Bug fix for broken PySimpleGUI if Python version < 3.6 (sorry!) * LOTS of Readme changes +#### 3.5.2 +* Made `Finalize()` in a way that it can be chained +* Fixed bug in return values from Frame Element contents + + ### Upcoming Make suggestions people! Future release features diff --git a/readme.md b/readme.md index 578ced22..0a835cd5 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ # PySimpleGUI -![Python Version](https://img.shields.io/badge/PySimpleGUI_Version-3.5.1-red.svg?longCache=true&style=for-the-badge) +![Python Version](https://img.shields.io/badge/PySimpleGUI_Version-3.5.2-red.svg?longCache=true&style=for-the-badge) [Wiki for the latest news](https://github.com/MikeTheWatchGuy/PySimpleGUI/wiki) @@ -1846,8 +1846,8 @@ The order of operations to obtain a tkinter Canvas Widget is: [sg.OK(pad=((figure_w / 2, 0), 3), size=(4, 2))]] # create the form and show it without the plot - form = sg.FlexForm('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout) - form.Finalize() + form = sg.FlexForm('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout).Finalize() + # add the plot to the window fig_photo = draw_figure(form.FindElement('canvas').TKCanvas, fig) @@ -2518,6 +2518,7 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it | 03.04.01 | Sept 18, 2018 - See release notes | 03.05.00 | Sept 20, 2018 - See release notes | 03.05.01 | Sept 22, 2018 - See release notes +| 03.05.02 | Sept 23, 2018 - See release notes ### Release Notes 2.3 - Sliders, Listbox's and Image elements (oh my!) @@ -2600,6 +2601,11 @@ OneLineProgressMeter function added which gives you not only a one-line solution * Bug fix for broken PySimpleGUI if Python version < 3.6 (sorry!) * LOTS of Readme changes +#### 3.5.2 +* Made `Finalize()` in a way that it can be chained +* Fixed bug in return values from Frame Element contents + + ### Upcoming Make suggestions people! Future release features