Release 3.12.0 & 1.12.0
This commit is contained in:
parent
42c5499687
commit
f60137c4b2
83 changed files with 2030 additions and 1118 deletions
615
docs/cookbook.md
615
docs/cookbook.md
|
@ -17,6 +17,7 @@ with
|
|||
|
||||
There is a short section in the Readme with instruction on installing PySimpleGUI
|
||||
|
||||
If you like this Cookbook, then you'll LOVE the 100+ sample programs that are just like these. You'll find them in the GitHub at http://www.PySimpleGUI.com. These Recipes are simply several of those programs displayed in document format.
|
||||
|
||||
## Simple Data Entry - Return Values As List
|
||||
Same GUI screen except the return values are in a list instead of a dictionary and doesn't have initial values.
|
||||
|
@ -96,7 +97,7 @@ Quickly add a GUI allowing the user to browse for a filename if a filename is no
|
|||
if len(sys.argv) == 1:
|
||||
event, (fname,) = sg.Window('My Script').Layout([[sg.Text('Document to open')],
|
||||
[sg.In(), sg.FileBrowse()],
|
||||
[sg.Open(), sg.Cancel()]]).Read()
|
||||
[sg.CButton('Open'), sg.CButton('Cancel')]]).Read()
|
||||
else:
|
||||
fname = sys.argv[1]
|
||||
|
||||
|
@ -191,37 +192,60 @@ Example of nearly all of the widgets in a single window. Uses a customized colo
|
|||
-------------
|
||||
|
||||
|
||||
## Window that stays open reading inputs and button clicks
|
||||
|
||||
This is the most basic form of a "Persistent Window", a window that remains open after button clicks and data entry.
|
||||
|
||||
```python
|
||||
import PySimpleGUI as sg
|
||||
|
||||
layout = [[sg.Text('Persistent window')],
|
||||
[sg.Input()],
|
||||
[sg.Button('Read'), sg.Exit()]]
|
||||
|
||||
window = sg.Window('Window that stays open').Layout(layout)
|
||||
|
||||
while True:
|
||||
event, values = window.Read()
|
||||
if event is None or event == 'Exit':
|
||||
break
|
||||
print(event, values)
|
||||
|
||||
window.Close()
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Non-Blocking Window With Periodic Update
|
||||
An async Window that has a event read loop. A Text Element is updated periodically with a running timer. Note that `value` is checked for None which indicates the window was closed using X.
|
||||
An async Window that has a event read loop. A Text Element is updated periodically with a running timer. Note that `value` is checked for None which indicates the window was closed using X.
|
||||
Use caution when using windows with a timeout. You should rarely need to use a timeout=0, non-blocking call, so try not to abuse this design pattern.
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
import PySimpleGUI as sg
|
||||
import time
|
||||
|
||||
gui_rows = [[sg.Text('Stopwatch', size=(20, 2), justification='center')],
|
||||
[sg.Text('', size=(10, 2), font=('Helvetica', 20), justification='center', key='output')],
|
||||
[sg.T(' ' * 5), sg.ReadButton('Start/Stop', focus=True), sg.Quit()]]
|
||||
|
||||
window = sg.Window('Running Timer').Layout(gui_rows)
|
||||
|
||||
timer_running = True
|
||||
i = 0
|
||||
# Event Loop
|
||||
while True:
|
||||
i += 1 * (timer_running is True)
|
||||
event, values = window.ReadNonBlocking()
|
||||
|
||||
if values is None or event == 'Quit': # if user closed the window using X or clicked Quit button
|
||||
break
|
||||
elif event == 'Start/Stop':
|
||||
timer_running = not timer_running
|
||||
|
||||
window.FindElement('output').Update('{:02d}:{:02d}.{:02d}'.format((i // 100) // 60, (i // 100) % 60, i % 100))
|
||||
time.sleep(.01)
|
||||
```python
|
||||
import PySimpleGUI as sg
|
||||
|
||||
gui_rows = [[sg.Text('Stopwatch', size=(20, 2), justification='center')],
|
||||
[sg.Text('', size=(10, 2), font=('Helvetica', 20), justification='center', key='output')],
|
||||
[sg.T(' ' * 5), sg.Button('Start/Stop', focus=True), sg.Quit()]]
|
||||
|
||||
window = sg.Window('Running Timer').Layout(gui_rows)
|
||||
|
||||
timer_running = True
|
||||
i = 0
|
||||
# Event Loop
|
||||
while True:
|
||||
i += 1 * (timer_running is True)
|
||||
event, values = window.Read(timeout=10) # Please try and use a timeout when possible
|
||||
if event is None or event == 'Quit': # if user closed the window using X or clicked Quit button
|
||||
break
|
||||
elif event == 'Start/Stop':
|
||||
timer_running = not timer_running
|
||||
window.FindElement('output').Update('{:02d}:{:02d}.{:02d}'.format((i // 100) // 60, (i // 100) % 60, i % 100))
|
||||
```
|
||||
|
||||
|
||||
--------
|
||||
|
||||
|
@ -247,7 +271,7 @@ The architecture of some programs works better with button callbacks instead of
|
|||
|
||||
# Layout the design of the GUI
|
||||
layout = [[sg.Text('Please click a button', auto_size_text=True)],
|
||||
[sg.ReadButton('1'), sg.ReadButton('2'), sg.Quit()]]
|
||||
[sg.Button('1'), sg.Button('2'), sg.Quit()]]
|
||||
|
||||
# Show the Window to the user
|
||||
window = sg.Window('Button callback example').Layout(layout)
|
||||
|
@ -261,7 +285,8 @@ The architecture of some programs works better with button callbacks instead of
|
|||
button1()
|
||||
elif event == '2':
|
||||
button2()
|
||||
elif event =='Quit' or event is None:
|
||||
elif event =='Quit' or event is None:
|
||||
window.Close()
|
||||
break
|
||||
|
||||
# All done!
|
||||
|
@ -288,19 +313,19 @@ This recipe implements a remote control interface for a robot. There are 4 dire
|
|||
|
||||
#
|
||||
# Some place later in your code...
|
||||
# You need to perform a ReadNonBlocking on your window every now and then or
|
||||
# else it won't refresh.
|
||||
# You need to perform a Read or Refresh on your window every now and then or
|
||||
# else it will appear your program has hung
|
||||
#
|
||||
# your program's main loop
|
||||
while (True):
|
||||
# This is the code that reads and updates your window
|
||||
event, values = window.ReadNonBlocking()
|
||||
event, values = window.Read(timeout=10)
|
||||
if event is not None:
|
||||
print(event)
|
||||
if event == 'Quit' or values is None:
|
||||
break
|
||||
|
||||
window.CloseNonBlocking() # Don't forget to close your window!
|
||||
window.Close() # Don't forget to close your window!
|
||||
|
||||
---------
|
||||
|
||||
|
@ -324,63 +349,83 @@ Buttons can have PNG of GIF images on them. This Media Player recipe requires 4
|
|||
|
||||

|
||||
|
||||
import PySimpleGUI as sg
|
||||
|
||||
background = '#F0F0F0'
|
||||
# Set the backgrounds the same as the background on the buttons
|
||||
sg.SetOptions(background_color=background, element_background_color=background)
|
||||
# Images are located in a subfolder in the Demo Media Player.py folder
|
||||
image_pause = './ButtonGraphics/Pause.png'
|
||||
image_restart = './ButtonGraphics/Restart.png'
|
||||
image_next = './ButtonGraphics/Next.png'
|
||||
image_exit = './ButtonGraphics/Exit.png'
|
||||
|
||||
# define layout of the rows
|
||||
layout = [[sg.Text('Media File Player', size=(17, 1), font=("Helvetica", 25))],
|
||||
[sg.Text('', size=(15, 2), font=("Helvetica", 14), key='output')],
|
||||
[sg.ReadButton('Restart Song', button_color=(background, background),
|
||||
image_filename=image_restart, image_size=(50, 50), image_subsample=2, border_width=0),
|
||||
sg.Text(' ' * 2),
|
||||
sg.ReadButton('Pause', button_color=(background, background),
|
||||
image_filename=image_pause, image_size=(50, 50), image_subsample=2, border_width=0),
|
||||
sg.Text(' ' * 2),
|
||||
sg.ReadButton('Next', button_color=(background, background),
|
||||
image_filename=image_next, image_size=(50, 50), image_subsample=2, border_width=0),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Text(' ' * 2), sg.Button('Exit', button_color=(background, background),
|
||||
image_filename=image_exit, image_size=(50, 50), image_subsample=2,
|
||||
border_width=0)],
|
||||
[sg.Text('_' * 30)],
|
||||
[sg.Text(' ' * 30)],
|
||||
[
|
||||
sg.Slider(range=(-10, 10), default_value=0, size=(10, 20), orientation='vertical',
|
||||
font=("Helvetica", 15)),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Slider(range=(-10, 10), default_value=0, size=(10, 20), orientation='vertical',
|
||||
font=("Helvetica", 15)),
|
||||
sg.Text(' ' * 8),
|
||||
sg.Slider(range=(-10, 10), default_value=0, size=(10, 20), orientation='vertical',
|
||||
font=("Helvetica", 15))],
|
||||
[sg.Text('Bass', font=("Helvetica", 15), size=(6, 1)),
|
||||
sg.Text('Treble', font=("Helvetica", 15), size=(10, 1)),
|
||||
sg.Text('Volume', font=("Helvetica", 15), size=(7, 1))]
|
||||
]
|
||||
|
||||
window = sg.Window('Media File Player', auto_size_text=True, default_element_size=(20, 1),
|
||||
font=("Helvetica", 25)).Layout(layout)
|
||||
# Our event loop
|
||||
while (True):
|
||||
# Read the window (this call will not block)
|
||||
event, values = window.ReadNonBlocking()
|
||||
if event == 'Exit' or values is None:
|
||||
break
|
||||
# If a button was pressed, display it on the GUI by updating the text element
|
||||
if event:
|
||||
window.FindElement('output').Update(event)
|
||||
|
||||
```python
|
||||
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
#
|
||||
# An Async Demonstration of a media player
|
||||
# Uses button images for a super snazzy look
|
||||
# See how it looks here:
|
||||
# https://user-images.githubusercontent.com/13696193/43159403-45c9726e-8f50-11e8-9da0-0d272e20c579.jpg
|
||||
#
|
||||
def MediaPlayerGUI():
|
||||
background = '#F0F0F0'
|
||||
# Set the backgrounds the same as the background on the buttons
|
||||
sg.SetOptions(background_color=background, element_background_color=background)
|
||||
# Images are located in a subfolder in the Demo Media Player.py folder
|
||||
image_pause = './ButtonGraphics/Pause.png'
|
||||
image_restart = './ButtonGraphics/Restart.png'
|
||||
image_next = './ButtonGraphics/Next.png'
|
||||
image_exit = './ButtonGraphics/Exit.png'
|
||||
|
||||
# A text element that will be changed to display messages in the GUI
|
||||
|
||||
|
||||
# define layout of the rows
|
||||
layout= [[sg.Text('Media File Player',size=(17,1), font=("Helvetica", 25))],
|
||||
[sg.Text('', size=(15, 2), font=("Helvetica", 14), key='output')],
|
||||
[sg.Button('', button_color=(background,background),
|
||||
image_filename=image_restart, image_size=(50, 50), image_subsample=2, border_width=0, key='Restart Song'),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Button('', button_color=(background,background),
|
||||
image_filename=image_pause, image_size=(50, 50), image_subsample=2, border_width=0, key='Pause'),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Button('', button_color=(background,background), image_filename=image_next, image_size=(50, 50), image_subsample=2, border_width=0, key='Next'),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Text(' ' * 2), sg.Button('', button_color=(background,background),
|
||||
image_filename=image_exit, image_size=(50, 50), image_subsample=2, border_width=0, key='Exit')],
|
||||
[sg.Text('_'*20)],
|
||||
[sg.Text(' '*30)],
|
||||
[
|
||||
sg.Slider(range=(-10, 10), default_value=0, size=(10, 20), orientation='vertical', font=("Helvetica", 15)),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Slider(range=(-10, 10), default_value=0, size=(10, 20), orientation='vertical', font=("Helvetica", 15)),
|
||||
sg.Text(' ' * 2),
|
||||
sg.Slider(range=(-10, 10), default_value=0, size=(10, 20), orientation='vertical', font=("Helvetica", 15))],
|
||||
[sg.Text(' Bass', font=("Helvetica", 15), size=(9, 1)),
|
||||
sg.Text('Treble', font=("Helvetica", 15), size=(7, 1)),
|
||||
sg.Text('Volume', font=("Helvetica", 15), size=(7, 1))]
|
||||
]
|
||||
|
||||
# Open a form, note that context manager can't be used generally speaking for async forms
|
||||
window = sg.Window('Media File Player', auto_size_text=True, default_element_size=(20, 1),
|
||||
font=("Helvetica", 25)).Layout(layout)
|
||||
# Our event loop
|
||||
while(True):
|
||||
event, values = window.Read(timeout=100) # Poll every 100 ms
|
||||
if event == 'Exit' or event is None:
|
||||
break
|
||||
# If a button was pressed, display it on the GUI by updating the text element
|
||||
if event != sg.TIMEOUT_KEY:
|
||||
window.FindElement('output').Update(event)
|
||||
|
||||
MediaPlayerGUI()
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
----
|
||||
## Script Launcher - Persistent Window
|
||||
This Window doesn't close after button clicks. To achieve this the buttons are specified as `sg.ReadButton` instead of `sg.Button`. The exception to this is the EXIT button. Clicking it will close the window. This program will run commands and display the output in the scrollable window.
|
||||
This Window doesn't close after button clicks. To achieve this the buttons are specified as `sg.Button` instead of `sg.Button`. The exception to this is the EXIT button. Clicking it will close the window. This program will run commands and display the output in the scrollable window.
|
||||
|
||||

|
||||
|
||||
|
@ -403,8 +448,8 @@ This Window doesn't close after button clicks. To achieve this the buttons are
|
|||
layout = [
|
||||
[sg.Text('Script output....', size=(40, 1))],
|
||||
[sg.Output(size=(88, 20))],
|
||||
[sg.ReadButton('script1'), sg.ReadButton('script2'), sg.Button('EXIT')],
|
||||
[sg.Text('Manual command', size=(15, 1)), sg.InputText(focus=True), sg.ReadButton('Run', bind_return_key=True)]
|
||||
[sg.Button('script1'), sg.Button('script2'), sg.Button('EXIT')],
|
||||
[sg.Text('Manual command', size=(15, 1)), sg.InputText(focus=True), sg.Button('Run', bind_return_key=True)]
|
||||
]
|
||||
|
||||
|
||||
|
@ -469,25 +514,27 @@ Perhaps you don't want all the statistics that the EasyProgressMeter provides an
|
|||

|
||||
|
||||
|
||||
import PySimpleGUI as sg
|
||||
|
||||
# layout the Window
|
||||
layout = [[sg.Text('A custom progress meter')],
|
||||
[sg.ProgressBar(10000, orientation='h', size=(20, 20), key='progbar')],
|
||||
[sg.Cancel()]]
|
||||
|
||||
# create the Window
|
||||
window = sg.Window('Custom Progress Meter').Layout(layout)
|
||||
# loop that would normally do something useful
|
||||
for i in range(10000):
|
||||
# check to see if the cancel button was clicked and exit loop if clicked
|
||||
event, values = window.ReadNonBlocking()
|
||||
if event == 'Cancel' or values == None:
|
||||
break
|
||||
# update bar with loop value +1 so that bar eventually reaches the maximum
|
||||
window.FindElement('progbar').UpdateBar(i + 1)
|
||||
# done with loop... need to destroy the window as it's still open
|
||||
window.CloseNonBlocking()
|
||||
```python
|
||||
import PySimpleGUI as sg
|
||||
|
||||
# layout the Window
|
||||
layout = [[sg.Text('A custom progress meter')],
|
||||
[sg.ProgressBar(1000, orientation='h', size=(20, 20), key='progbar')],
|
||||
[sg.Cancel()]]
|
||||
|
||||
# create the Window
|
||||
window = sg.Window('Custom Progress Meter').Layout(layout)
|
||||
# loop that would normally do something useful
|
||||
for i in range(1000):
|
||||
# check to see if the cancel button was clicked and exit loop if clicked
|
||||
event, values = window.Read(timeout=0)
|
||||
if event == 'Cancel' or event is None:
|
||||
break
|
||||
# update bar with loop value +1 so that bar eventually reaches the maximum
|
||||
window.FindElement('progbar').UpdateBar(i + 1)
|
||||
# done with loop... need to destroy the window as it's still open
|
||||
window.Close()
|
||||
```
|
||||
|
||||
|
||||
----
|
||||
|
@ -570,7 +617,7 @@ This simple program keep a window open, taking input values until the user termi
|
|||
[sg.Txt('_' * 10)],
|
||||
[sg.In(size=(8,1), key='denominator')],
|
||||
[sg.Txt('', size=(8,1), key='output') ],
|
||||
[sg.ReadButton('Calculate', bind_return_key=True)]]
|
||||
[sg.Button('Calculate', bind_return_key=True)]]
|
||||
|
||||
window = sg.Window('Math').Layout(layout)
|
||||
|
||||
|
@ -609,7 +656,7 @@ While it's fun to scribble on a Canvas Widget, try Graph Element makes it a down
|
|||
|
||||
layout = [
|
||||
[sg.Canvas(size=(100, 100), background_color='red', key= 'canvas')],
|
||||
[sg.T('Change circle color to:'), sg.ReadButton('Red'), sg.ReadButton('Blue')]
|
||||
[sg.T('Change circle color to:'), sg.Button('Red'), sg.Button('Blue')]
|
||||
]
|
||||
|
||||
window = sg.Window('Canvas test')
|
||||
|
@ -639,7 +686,7 @@ Just like you can draw on a tkinter widget, you can also draw on a Graph Element
|
|||
|
||||
layout = [
|
||||
[sg.Graph(canvas_size=(400, 400), graph_bottom_left=(0,0), graph_top_right=(400, 400), background_color='red', key='graph')],
|
||||
[sg.T('Change circle color to:'), sg.ReadButton('Red'), sg.ReadButton('Blue'), sg.ReadButton('Move')]
|
||||
[sg.T('Change circle color to:'), sg.Button('Red'), sg.Button('Blue'), sg.Button('Move')]
|
||||
]
|
||||
|
||||
window = sg.Window('Graph test')
|
||||
|
@ -674,7 +721,7 @@ This Recipe implements a Raspberry Pi touchscreen based keypad entry. As the di
|
|||
There are a number of features used in this Recipe including:
|
||||
* Default Element Size
|
||||
* auto_size_buttons
|
||||
* ReadButton
|
||||
* Button
|
||||
* Dictionary Return values
|
||||
* Update of Elements in window (Input, Text)
|
||||
* do_not_clear of Input Elements
|
||||
|
@ -689,17 +736,17 @@ There are a number of features used in this Recipe including:
|
|||
# Demonstrates a number of PySimpleGUI features including:
|
||||
# Default element size
|
||||
# auto_size_buttons
|
||||
# ReadButton
|
||||
# Button
|
||||
# Dictionary return values
|
||||
# Update of elements in window (Text, Input)
|
||||
# do_not_clear of Input elements
|
||||
|
||||
layout = [[sg.Text('Enter Your Passcode')],
|
||||
[sg.Input(size=(10, 1), do_not_clear=True, justification='right', key='input')],
|
||||
[sg.ReadButton('1'), sg.ReadButton('2'), sg.ReadButton('3')],
|
||||
[sg.ReadButton('4'), sg.ReadButton('5'), sg.ReadButton('6')],
|
||||
[sg.ReadButton('7'), sg.ReadButton('8'), sg.ReadButton('9')],
|
||||
[sg.ReadButton('Submit'), sg.ReadButton('0'), sg.ReadButton('Clear')],
|
||||
[sg.Button('1'), sg.Button('2'), sg.Button('3')],
|
||||
[sg.Button('4'), sg.Button('5'), sg.Button('6')],
|
||||
[sg.Button('7'), sg.Button('8'), sg.Button('9')],
|
||||
[sg.Button('Submit'), sg.Button('0'), sg.Button('Clear')],
|
||||
[sg.Text('', size=(15, 1), font=('Helvetica', 18), text_color='red', key='out')],
|
||||
]
|
||||
|
||||
|
@ -729,60 +776,61 @@ Use the Canvas Element to create an animated graph. The code is a bit tricky to
|
|||

|
||||
|
||||
|
||||
from tkinter import *
|
||||
from random import randint
|
||||
import PySimpleGUI as g
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, FigureCanvasAgg
|
||||
from matplotlib.figure import Figure
|
||||
import matplotlib.backends.tkagg as tkagg
|
||||
import tkinter as Tk
|
||||
|
||||
|
||||
fig = Figure()
|
||||
|
||||
ax = fig.add_subplot(111)
|
||||
ax.set_xlabel("X axis")
|
||||
ax.set_ylabel("Y axis")
|
||||
ax.grid()
|
||||
|
||||
layout = [[g.Text('Animated Matplotlib', size=(40, 1), justification='center', font='Helvetica 20')],
|
||||
[g.Canvas(size=(640, 480), key='canvas')],
|
||||
[g.ReadButton('Exit', size=(10, 2), pad=((280, 0), 3), font='Helvetica 14')]]
|
||||
|
||||
# create the window and show it without the plot
|
||||
|
||||
|
||||
window = g.Window('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout)
|
||||
window.Finalize() # needed to access the canvas element prior to reading the window
|
||||
|
||||
canvas_elem = window.FindElement('canvas')
|
||||
|
||||
graph = FigureCanvasTkAgg(fig, master=canvas_elem.TKCanvas)
|
||||
canvas = canvas_elem.TKCanvas
|
||||
|
||||
dpts = [randint(0, 10) for x in range(10000)]
|
||||
# Our event loop
|
||||
for i in range(len(dpts)):
|
||||
event, values = window.ReadNonBlocking()
|
||||
if event == 'Exit' or values is None:
|
||||
exit(69)
|
||||
|
||||
ax.cla()
|
||||
ax.grid()
|
||||
|
||||
ax.plot(range(20), dpts[i:i + 20], color='purple')
|
||||
graph.draw()
|
||||
figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds
|
||||
figure_w, figure_h = int(figure_w), int(figure_h)
|
||||
photo = Tk.PhotoImage(master=canvas, width=figure_w, height=figure_h)
|
||||
|
||||
canvas.create_image(640 / 2, 480 / 2, image=photo)
|
||||
|
||||
figure_canvas_agg = FigureCanvasAgg(fig)
|
||||
figure_canvas_agg.draw()
|
||||
|
||||
tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)
|
||||
|
||||
```python
|
||||
from tkinter import *
|
||||
from random import randint
|
||||
import PySimpleGUI as sg
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, FigureCanvasAgg
|
||||
from matplotlib.figure import Figure
|
||||
import matplotlib.backends.tkagg as tkagg
|
||||
import tkinter as Tk
|
||||
|
||||
fig = Figure()
|
||||
|
||||
ax = fig.add_subplot(111)
|
||||
ax.set_xlabel("X axis")
|
||||
ax.set_ylabel("Y axis")
|
||||
ax.grid()
|
||||
|
||||
layout = [[sg.Text('Animated Matplotlib', size=(40, 1), justification='center', font='Helvetica 20')],
|
||||
[sg.Canvas(size=(640, 480), key='canvas')],
|
||||
[sg.Button('Exit', size=(10, 2), pad=((280, 0), 3), font='Helvetica 14')]]
|
||||
|
||||
# create the window and show it without the plot
|
||||
|
||||
|
||||
window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout)
|
||||
window.Finalize() # needed to access the canvas element prior to reading the window
|
||||
|
||||
canvas_elem = window.FindElement('canvas')
|
||||
|
||||
graph = FigureCanvasTkAgg(fig, master=canvas_elem.TKCanvas)
|
||||
canvas = canvas_elem.TKCanvas
|
||||
|
||||
dpts = [randint(0, 10) for x in range(10000)]
|
||||
# Our event loop
|
||||
for i in range(len(dpts)):
|
||||
event, values = window.Read(timeout=20)
|
||||
if event == 'Exit' or event is None:
|
||||
exit(69)
|
||||
|
||||
ax.cla()
|
||||
ax.grid()
|
||||
|
||||
ax.plot(range(20), dpts[i:i + 20], color='purple')
|
||||
graph.draw()
|
||||
figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds
|
||||
figure_w, figure_h = int(figure_w), int(figure_h)
|
||||
photo = Tk.PhotoImage(master=canvas, width=figure_w, height=figure_h)
|
||||
|
||||
canvas.create_image(640 / 2, 480 / 2, image=photo)
|
||||
|
||||
figure_canvas_agg = FigureCanvasAgg(fig)
|
||||
figure_canvas_agg.draw()
|
||||
|
||||
tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Tight Layout with Button States
|
||||
|
@ -809,10 +857,10 @@ In other GUI frameworks this program would be most likely "event driven" with ca
|
|||
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.ReadButton('Start', button_color=('white', 'black'), key='Start'),
|
||||
sg.ReadButton('Stop', button_color=('white', 'black'), key='Stop'),
|
||||
sg.ReadButton('Reset', button_color=('white', 'firebrick3'), key='Reset'),
|
||||
sg.ReadButton('Submit', button_color=('white', 'springgreen4'), key='Submit')]
|
||||
[sg.Button('Start', button_color=('white', 'black'), key='Start'),
|
||||
sg.Button('Stop', button_color=('white', 'black'), key='Stop'),
|
||||
sg.Button('Reset', button_color=('white', 'firebrick3'), key='Reset'),
|
||||
sg.Button('Submit', button_color=('white', 'springgreen4'), key='Submit')]
|
||||
]
|
||||
|
||||
window = sg.Window("Time Tracker", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False,
|
||||
|
@ -973,10 +1021,10 @@ You can easily change colors to match your background by changing a couple of pa
|
|||
|
||||
sg.SetOptions(element_padding=(0,0), button_element_size=(12,1), auto_size_buttons=False)
|
||||
layout = [[sg.Combo(values=namesonly, size=(35,30), key='demofile'),
|
||||
sg.ReadButton('Run', button_color=('white', '#00168B')),
|
||||
sg.ReadButton('Program 1'),
|
||||
sg.ReadButton('Program 2'),
|
||||
sg.ReadButton('Program 3', button_color=('white', '#35008B')),
|
||||
sg.Button('Run', button_color=('white', '#00168B')),
|
||||
sg.Button('Program 1'),
|
||||
sg.Button('Program 2'),
|
||||
sg.Button('Program 3', button_color=('white', '#35008B')),
|
||||
sg.Button('EXIT', button_color=('white','firebrick3'))],
|
||||
[sg.T('', text_color='white', size=(50,1), key='output')]]
|
||||
|
||||
|
@ -1032,72 +1080,82 @@ Much of the code is handling the button states in a fancy way. It could be much
|
|||
|
||||

|
||||
|
||||
import PySimpleGUI as sg
|
||||
import time
|
||||
|
||||
"""
|
||||
Timer Desktop Widget Creates a floating timer that is always on top of other windows You move it by grabbing anywhere on the window Good example of how to do a non-blocking, polling program using PySimpleGUI Can be used to poll hardware when running on a Pi NOTE - you will get a warning message printed when you exit using exit button. It will look something like: invalid command name \"1616802625480StopMove\"
|
||||
"""
|
||||
|
||||
|
||||
# ---------------- Create window ----------------
|
||||
sg.ChangeLookAndFeel('Black')
|
||||
sg.SetOptions(element_padding=(0, 0))
|
||||
|
||||
layout = [[sg.Text('')],
|
||||
[sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='text')],
|
||||
[sg.ReadButton('Pause', key='button', button_color=('white', '#001480')),
|
||||
sg.ReadButton('Reset', button_color=('white', '#007339'), key='Reset'),
|
||||
sg.Exit(button_color=('white', 'firebrick4'), key='Exit')]]
|
||||
|
||||
window = sg.Window('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True).Layout(layout)
|
||||
|
||||
|
||||
# ---------------- main loop ----------------
|
||||
current_time = 0
|
||||
paused = False
|
||||
start_time = int(round(time.time() * 100))
|
||||
while (True):
|
||||
# --------- Read and update window --------
|
||||
if not paused:
|
||||
event, values = window.ReadNonBlocking()
|
||||
current_time = int(round(time.time() * 100)) - start_time
|
||||
else:
|
||||
event, values = window.Read()
|
||||
if event == 'button':
|
||||
button = window.FindElement(button).GetText()
|
||||
# --------- Do Button Operations --------
|
||||
if values is None or event == 'Exit':
|
||||
break
|
||||
if event is 'Reset':
|
||||
start_time = int(round(time.time() * 100))
|
||||
current_time = 0
|
||||
paused_time = start_time
|
||||
elif event == 'Pause':
|
||||
paused = True
|
||||
paused_time = int(round(time.time() * 100))
|
||||
element = window.FindElement('button')
|
||||
element.Update(text='Run')
|
||||
elif event == 'Run':
|
||||
paused = False
|
||||
start_time = start_time + int(round(time.time() * 100)) - paused_time
|
||||
element = window.FindElement('button')
|
||||
element.Update(text='Pause')
|
||||
|
||||
# --------- Display timer in window --------
|
||||
window.FindElement('text').Update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60,
|
||||
(current_time // 100) % 60,
|
||||
current_time % 100))
|
||||
time.sleep(.01)
|
||||
|
||||
# --------- After loop --------
|
||||
|
||||
# Broke out of main loop. Close the window.
|
||||
window.CloseNonBlocking()
|
||||
```python
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
import time
|
||||
|
||||
"""
|
||||
Timer Desktop Widget Creates a floating timer that is always on top of other windows You move it by grabbing anywhere on the window Good example of how to do a non-blocking, polling program using SimpleGUI Can be used to poll hardware when running on a Pi
|
||||
|
||||
While the timer ticks are being generated by PySimpleGUI's "timeout" mechanism, the actual value
|
||||
of the timer that is displayed comes from the system timer, time.time(). This guarantees an
|
||||
accurate time value is displayed regardless of the accuracy of the PySimpleGUI timer tick. If
|
||||
this design were not used, then the time value displayed would slowly drift by the amount of time
|
||||
it takes to execute the PySimpleGUI read and update calls (not good!)
|
||||
|
||||
NOTE - you will get a warning message printed when you exit using exit button.
|
||||
It will look something like: invalid command name \"1616802625480StopMove\"
|
||||
"""
|
||||
|
||||
|
||||
# ---------------- Create Form ----------------
|
||||
sg.ChangeLookAndFeel('Black')
|
||||
sg.SetOptions(element_padding=(0, 0))
|
||||
|
||||
layout = [[sg.Text('')],
|
||||
[sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='text')],
|
||||
[sg.Button('Pause', key='button', button_color=('white', '#001480')),
|
||||
sg.Button('Reset', button_color=('white', '#007339'), key='Reset'),
|
||||
sg.Exit(button_color=('white', 'firebrick4'), key='Exit')]]
|
||||
|
||||
window = sg.Window('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True).Layout(layout)
|
||||
|
||||
# ---------------- main loop ----------------
|
||||
current_time = 0
|
||||
paused = False
|
||||
start_time = int(round(time.time() * 100))
|
||||
while (True):
|
||||
# --------- Read and update window --------
|
||||
if not paused:
|
||||
event, values = window.Read(timeout=10)
|
||||
current_time = int(round(time.time() * 100)) - start_time
|
||||
else:
|
||||
event, values = window.Read()
|
||||
if event == 'button':
|
||||
event = window.FindElement(event).GetText()
|
||||
# --------- Do Button Operations --------
|
||||
if event is None or event == 'Exit': # ALWAYS give a way out of program
|
||||
break
|
||||
if event is 'Reset':
|
||||
start_time = int(round(time.time() * 100))
|
||||
current_time = 0
|
||||
paused_time = start_time
|
||||
elif event == 'Pause':
|
||||
paused = True
|
||||
paused_time = int(round(time.time() * 100))
|
||||
element = window.FindElement('button')
|
||||
element.Update(text='Run')
|
||||
elif event == 'Run':
|
||||
paused = False
|
||||
start_time = start_time + int(round(time.time() * 100)) - paused_time
|
||||
element = window.FindElement('button')
|
||||
element.Update(text='Pause')
|
||||
|
||||
# --------- Display timer in window --------
|
||||
window.FindElement('text').Update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60,
|
||||
(current_time // 100) % 60,
|
||||
current_time % 100))
|
||||
```
|
||||
|
||||
|
||||
## Desktop Floating Widget - CPU Utilization
|
||||
|
||||
Like the Timer widget above, this script can be kept running. You will need the package psutil installed in order to run this Recipe.
|
||||
Like the Timer widget above, this script can be kept running. You will need the package psutil installed in order to run this Recipe.
|
||||
|
||||
The spinner changes the number of seconds between reads. Note that you will get an error message printed when exiting because the window does not have have a titlebar. It's a known problem.
|
||||
|
||||
|
||||
|
@ -1105,39 +1163,42 @@ The spinner changes the number of seconds between reads. Note that you will get
|
|||
|
||||
|
||||
|
||||
import PySimpleGUI as sg
|
||||
import psutil
|
||||
|
||||
# ---------------- Create Window ----------------
|
||||
sg.ChangeLookAndFeel('Black')
|
||||
layout = [[sg.Text('')],
|
||||
[sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='text')],
|
||||
[sg.Exit(button_color=('white', 'firebrick4'), pad=((15,0), 0)), sg.Spin([x+1 for x in range(10)], 1, key='spin')]]
|
||||
|
||||
window = sg.Window('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True).Layout(layout)
|
||||
|
||||
|
||||
# ---------------- main loop ----------------
|
||||
while (True):
|
||||
# --------- Read and update window --------
|
||||
event, values = window.ReadNonBlocking()
|
||||
|
||||
# --------- Do Button Operations --------
|
||||
if values is None or event == 'Exit':
|
||||
break
|
||||
try:
|
||||
interval = int(values['spin'])
|
||||
except:
|
||||
interval = 1
|
||||
|
||||
cpu_percent = psutil.cpu_percent(interval=interval)
|
||||
|
||||
# --------- Display timer in window --------
|
||||
|
||||
window.FindElement('text').Update(f'CPU {cpu_percent:02.0f}%')
|
||||
|
||||
# Broke out of main loop. Close the window.
|
||||
window.CloseNonBlocking()
|
||||
```python
|
||||
import PySimpleGUI as sg
|
||||
import psutil
|
||||
|
||||
# ---------------- Create Window ----------------
|
||||
sg.ChangeLookAndFeel('Black')
|
||||
layout = [[sg.Text('')],
|
||||
[sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='text')],
|
||||
[sg.Exit(button_color=('white', 'firebrick4'), pad=((15, 0), 0)),
|
||||
sg.Spin([x + 1 for x in range(10)], 1, key='spin')]]
|
||||
|
||||
window = sg.Window('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True,
|
||||
grab_anywhere=True).Layout(layout)
|
||||
|
||||
# ---------------- main loop ----------------
|
||||
while (True):
|
||||
# --------- Read and update window --------
|
||||
event, values = window.Read(timeout=0)
|
||||
|
||||
# --------- Do Button Operations --------
|
||||
if event is None or event == 'Exit':
|
||||
break
|
||||
try:
|
||||
interval = int(values['spin'])
|
||||
except:
|
||||
interval = 1
|
||||
|
||||
cpu_percent = psutil.cpu_percent(interval=interval)
|
||||
|
||||
# --------- Display timer in window --------
|
||||
|
||||
window.FindElement('text').Update(f'CPU {cpu_percent:02.0f}%')
|
||||
|
||||
# Broke out of main loop. Close the window.
|
||||
window.Close()
|
||||
```
|
||||
|
||||
## Menus
|
||||
|
||||
|
@ -1145,7 +1206,7 @@ Menus are nothing more than buttons that live in a menu-bar. When you click on
|
|||
|
||||
Menu's are defined separately from the GUI window. To add one to your window, simply insert sg.Menu(menu_layout). The menu definition is a list of menu choices and submenus. They are a list of lists. Copy the Recipe and play with it. You'll eventually get when you're looking for.
|
||||
|
||||
If you double click the dashed line at the top of the list of choices, that menu will tear off and become a floating toolbar. How cool!
|
||||
If you double click the dashed line at the top of the list of choices, that menu will tear off and become a floating toolbar. How cool! To enable this feature, set the parameter `tearoff=True` in your call to `sg.Menu()`
|
||||
|
||||
|
||||

|
||||
|
@ -1164,7 +1225,7 @@ If you double click the dashed line at the top of the list of choices, that menu
|
|||
|
||||
# ------ GUI Defintion ------ #
|
||||
layout = [
|
||||
[sg.Menu(menu_def)],
|
||||
[sg.Menu(menu_def, )],
|
||||
[sg.Output(size=(60, 20))]
|
||||
]
|
||||
|
||||
|
@ -1247,7 +1308,7 @@ tab2_layout = [[sg.T('This is inside tab 2')],
|
|||
[sg.In(key='in')]]
|
||||
|
||||
layout = [[sg.TabGroup([[sg.Tab('Tab 1', tab1_layout, tooltip='tip'), sg.Tab('Tab 2', tab2_layout)]], tooltip='TIP2')],
|
||||
[sg.RButton('Read')]]
|
||||
[sg.Button('Read')]]
|
||||
|
||||
window = sg.Window('My window with tabs', default_element_size=(12,1)).Layout(layout)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -23,9 +24,9 @@
|
|||
|
||||
## Now supports both Python 2.7 & 3
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
|
||||
|
||||
|
@ -934,14 +935,10 @@ Isn't this what a Python programmer looking for a GUI wants? Something easy to w
|
|||
|
||||
### Two Return Values
|
||||
|
||||
All Window Read and ReadNonBlocking calls return 2 values. By convention a read statement is written:
|
||||
All Window Read calls return 2 values. By convention a read statement is written:
|
||||
```python
|
||||
event, values = window.Read()
|
||||
```
|
||||
All of the demo programs and the Cookbook recipes have this line of code for windows that are normal reads (not non-blocking). A similar line of code is used for non-blocking window reads:
|
||||
```python
|
||||
event, values = window.ReadNonBlocking()
|
||||
```
|
||||
|
||||
You don't HAVE to write your reads in this way. You can name your variables however you want. But if you want to code them in a way that other programmers using PySimpleGUI are used to, then use these statements.
|
||||
|
||||
|
@ -970,6 +967,15 @@ To check for a closed window use this line of code:
|
|||
|
||||
if event is None:
|
||||
|
||||
Putting it all together we end up with an "event loop" that looks something like this:
|
||||
```python
|
||||
while True:
|
||||
event, values = window.Read()
|
||||
if event is None:
|
||||
break
|
||||
|
||||
```
|
||||
|
||||
|
||||
### The 'values' Variable - Return values as a list
|
||||
|
||||
|
@ -1181,8 +1187,12 @@ You will find it ***much easier*** to write code using PySimpleGUI if you use an
|
|||
|
||||
## Synchronous windows
|
||||
The most common use of PySimpleGUI is to display and collect information from the user. The most straightforward way to do this is using a "blocking" GUI call. Execution is "blocked" while waiting for the user to close the GUI window/dialog box.
|
||||
You've already seen a number of examples above that use blocking windows. The call to look for that will show you non-blocking windows are calls to `ReadNonBlocking()`. You can read more about Async windows at the end of this document.
|
||||
You've already seen a number of examples above that use blocking windows. A truly non-blocking Read call looks like this:
|
||||
```python
|
||||
event, values = window.Read(timeout=0)
|
||||
```
|
||||
|
||||
You can learn more about these async / non-blocking windows toward the end of this document.
|
||||
|
||||
|
||||
# Window Object - Beginning a window
|
||||
|
@ -1287,12 +1297,12 @@ There are a few methods (functions) that you will see in this document that act
|
|||
window.Layout(layout) - Turns your definition of the Window into Window
|
||||
window.Finalize() - creates the tkinter objects for the Window. Normally you do not call this
|
||||
window.Read() - Read the Windows values and get the button / key that caused the Read to return. Can have an optional timeout
|
||||
window.ReadNonBlocking() - Same as Read but will return right away
|
||||
window.ReadNonBlocking() - NO LONGER USED!
|
||||
window.Refresh() - Use if updating elements and want to show the updates prior to the nex Read
|
||||
window.Fill(values_dict) - Fill each Element with entry from the dictionary passed in
|
||||
window.SaveToDisk(filename) - Save the Window's values to disk
|
||||
window.LoadFromDisk(filename) - Load the Window's values from disk
|
||||
window.Close() - To close your window, if a button hasn't already closed iit
|
||||
window.Close() - To close your window, if a button hasn't already closed it
|
||||
window.Disable() - Use to disable the window inpurt when opening another window on top of the primnary Window
|
||||
window.Enable() - Re-enable a Disabled window
|
||||
window.FindElement(key) - Returns the element that has a matching key value
|
||||
|
@ -2056,7 +2066,7 @@ The Types of buttons include:
|
|||
* Color Chooser
|
||||
|
||||
|
||||
Close window - Normal buttons like Submit, Cancel, Yes, No, etc, are "Close window" buttons. They cause the input values to be read and then the window is ***closed***, returning the values to the caller.
|
||||
Close window - Normal buttons like Submit, Cancel, Yes, No, do NOT close the window... they used to. Now to close a window you need to use a CloseButton / CButton.
|
||||
|
||||
Folder Browse - When clicked a folder browse dialog box is opened. The results of the Folder Browse dialog box are written into one of the input fields of the window.
|
||||
|
||||
|
@ -2070,17 +2080,20 @@ Read window - This is a window button that will read a snapshot of all of the in
|
|||
|
||||
Realtime - This is another async window button. Normal button clicks occur after a button's click is released. Realtime buttons report a click the entire time the button is held down.
|
||||
|
||||
Most programs will use a combination of shortcut button calls (Submit, Cancel, etc), plain buttons that close the window, and ReadButton buttons that keep the window open but returns control back to the caller.
|
||||
Most programs will use a combination of shortcut button calls (Submit, Cancel, etc), normal Buttons which leave the windows open and CloseButtons that close the window when clicked.
|
||||
|
||||
Sometimes there are multiple names for the same function. This is simply to make the job of the programmer quicker and easier.
|
||||
Sometimes there are multiple names for the same function. This is simply to make the job of the programmer quicker and easier. Or they are old names that are no longer used but kept around so that existing programs don't break.
|
||||
|
||||
The 3 primary windows of PySimpleGUI buttons and their names are:
|
||||
The 4 primary windows of PySimpleGUI buttons and their names are:
|
||||
|
||||
1. `Button` = `SimpleButton`
|
||||
2. `ReadButton` = `RButton` = `ReadFormButton` (old style... use ReadButton instead)
|
||||
1. `Button`= `ReadButton` = `RButton` = `ReadFormButton` (old style... use Button instead)
|
||||
2. `CloseButton` = `CButton`
|
||||
3. `RealtimeButton`
|
||||
4. `DummyButton`
|
||||
|
||||
You will find the long-form in the older programs.
|
||||
You will find the long-form names in the older programs. ReadButton for example.
|
||||
|
||||
In Oct 2018, the definition of Button changed. Previously Button would CLOSE the window when clicked. It has been changed so the Button calls will leave the window open in exactly the same way as a ReadButton. They are the same calls now. To enables windows to be closed using buttons, a new button was added... `CloseButton` or `CButton`.
|
||||
|
||||
The most basic Button element call to use is `Button`
|
||||
|
||||
|
@ -2152,9 +2165,10 @@ These Pre-made buttons are some of the most important elements of all because th
|
|||
**IMPORT NOTE ABOUT SHORTCUT BUTTONS**
|
||||
Prior to release 3.11.0, these buttons closed the window. Starting with 3.11 they will not close the window. They act like RButtons (return the button text and do not close the window)
|
||||
|
||||
If you are having trouble with these buttons closing your window, please check your installed version of PySimpleGUI by typing `pip list` at a command promt. Prior to 3.11 these buttons close your window.
|
||||
If you are having trouble with these buttons closing your window, please check your installed version of PySimpleGUI by typing `pip list` at a command prompt. Prior to 3.11 these buttons close your window.
|
||||
|
||||
Using older versions, if you want a Submit() button that does not close the window, then you would instead use RButton('Submit'). Using the new version, if you want a Submit button that closes the window like the sold Submit() call did, you would write that as `CloseButton('Submit')` or `CButton('Submit')`
|
||||
|
||||
Using older versions, if you want a Submit() button that does not close the window, then you would instead use RButton('Submit')
|
||||
|
||||
layout = [[sg.OK(), sg.Cancel()]]
|
||||
|
||||
|
@ -2299,22 +2313,22 @@ window = sg.Window('Robotics Remote Control', auto_size_text=True).Layout(gui_ro
|
|||
|
||||
#
|
||||
# Some place later in your code...
|
||||
# You need to perform a ReadNonBlocking on your window every now and then or
|
||||
# else it won't refresh.
|
||||
# You need to perform a Read or Refresh call on your window every now and then or
|
||||
# else it will apprear as if the program has locked up.
|
||||
#
|
||||
# your program's main loop
|
||||
while (True):
|
||||
# This is the code that reads and updates your window
|
||||
event, values = window.Read(timeout=0)
|
||||
event, values = window.Read(timeout=0)
|
||||
if event is not None:
|
||||
print(event)
|
||||
if event == 'Quit' or values is None:
|
||||
break
|
||||
break
|
||||
|
||||
window.Close() # Don't forget to close your window!
|
||||
```
|
||||
|
||||
This loop will read button values and print them. When one of the Realtime buttons is clicked, the call to `window.ReadNonBlocking` will return a button name matching the name on the button that was depressed or the key if there was a key assigned to the button. It will continue to return values as long as the button remains depressed. Once released, the ReadNonBlocking will return None for buttons until a button is again clicked.
|
||||
This loop will read button values and print them. When one of the Realtime buttons is clicked, the call to `window.Read` will return a button name matching the name on the button that was depressed or the key if there was a key assigned to the button. It will continue to return values as long as the button remains depressed. Once released, the Read will return timeout events until a button is again clicked.
|
||||
|
||||
**File Types**
|
||||
The `FileBrowse` & `SaveAs` buttons have an additional setting named `file_types`. This variable is used to filter the files shown in the file dialog box. The default value for this setting is
|
||||
|
@ -2679,7 +2693,7 @@ Let me say up front that the Table Element has Beta status. The reason is that s
|
|||
|
||||
### Read return values from Table Element
|
||||
|
||||
The values returned from a `Window.Read` or `Window.ReadNonBlocking` call for the Tree Element are a list of row numbers that are currently highlighted.
|
||||
The values returned from a `Window.Read` call for the Tree Element are a list of row numbers that are currently highlighted.
|
||||
|
||||
### Update Call
|
||||
|
||||
|
@ -2947,7 +2961,7 @@ There are 2 ways to keep a window open after the user has clicked a button. One
|
|||
|
||||
The `RButton` Element creates a button that when clicked will return control to the user, but will leave the window open and visible. This button is also used in Non-Blocking windows. The difference is in which call is made to read the window. The normal `Read` call with no parameters will block, a call with a `timeout` value of zero will not block.
|
||||
|
||||
Note that `InputText` and `MultiLine` Elements will be **cleared** when performing a `ReadNonBlocking`. If you do not want your input field to be cleared after a `ReadNonBlocking` then you can set the `do_not_clear` parameter to True when creating those elements. The clear is turned on and off on an element by element basis.
|
||||
Note that `InputText` and `MultiLine` Elements will be **cleared** when performing a `Read`. If you do not want your input field to be cleared after a `Read` then you can set the `do_not_clear` parameter to True when creating those elements. The clear is turned on and off on an element by element basis.
|
||||
|
||||
The reasoning behind this is that Persistent Windows are often "forms". When "submitting" a form you want to have all of the fields left blank so the next entry of data will start with a fresh window. Also, when implementing a "Chat Window" type of interface, after each read / send of the chat data, you want the input field cleared. Think of it as a Texting application. Would you want to have to clear your previous text if you want to send a second text?
|
||||
|
||||
|
@ -2986,7 +3000,7 @@ Let's say you had a device that you want to "poll" every 100ms. The "easy way
|
|||
```python
|
||||
# YOU SHOULD NOT DO THIS....
|
||||
while True: # Event Loop
|
||||
event, values = window.ReadNonBlocking()
|
||||
event, values = window.ReadNonBlocking() # DO NOT USE THIS CALL ANYMORE
|
||||
read_my_hardware() # process my device here
|
||||
time.sleep(.1) # sleep 1/10 second
|
||||
```
|
||||
|
@ -3518,6 +3532,7 @@ A MikeTheWatchGuy production... entirely responsible for this code.... unless it
|
|||
| 3.10.1 & 1.2.1 | Oct 20, 2018
|
||||
| 3.10.3 & 1.2.3 | Oct 23, 2018
|
||||
| 3.11.0 & 1.11.0 | Oct 28, 2018
|
||||
| 3.12.0 & 1.12.0 | Oct 28, 2018
|
||||
|
||||
|
||||
## Release Notes
|
||||
|
@ -3740,6 +3755,13 @@ Emergency patch release... going out same day as previous release
|
|||
* Shortcut buttons no longer close windows!
|
||||
* Added CloseButton, CButton that closes the windows
|
||||
|
||||
### 3.12.0 & 1.12.0
|
||||
* Changed Button to be the same as ReadButton which means it will no longer close the window
|
||||
* All shortcut buttons no longer close the window
|
||||
* Updating a table clears selected rows information in return values
|
||||
* Progress meter uses new CloseButton
|
||||
* Popups use new CloseButton
|
||||
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue