Compare commits

..

7 commits

Author SHA1 Message Date
PySimpleGUI
41fb096483 4.60.5 Release 2023-06-09 06:13:33 -04:00
PySimpleGUI
e59936e84c 4.60.4 Release 2023-06-09 06:10:36 -04:00
PySimpleGUI
b037e1426b Final 4.60.3 released to PyPI 2022-07-27 17:31:19 -04:00
PySimpleGUI
63f73c222b Trying 4.60.3 AGAIN... this time checking the mac_ver[1] and also checking for releases 13+ 2022-07-27 11:16:48 -04:00
PySimpleGUI
8e9b532657 4.60.3 - Another shot at the Mac OS 12.3+ problem - fixed the version checking 2022-07-27 08:34:19 -04:00
PySimpleGUI
45de5867fb 4.60.2 Candidate Release 2022-07-26 10:44:00 -04:00
PySimpleGUI
ca93e48ad4 4.60.1 patch that was released 22-May-2022 2022-07-26 08:45:57 -04:00
360 changed files with 9119 additions and 17596 deletions

View file

@ -60,13 +60,11 @@ Anything else you think would be helpful?
These items may solve your problem. Please check those you've done by changing - [ ] to - [X]
- [ ] Searched main docs for your problem www.PySimpleGUI.org
- [ ] Looked for Demo Programs that are similar to your goal. It is recommend you use the Demo Browser! Demos.PySimpleGUI.org
- [ ] None of your GUI code was generated by an AI algorithm like GPT
- [ ] Looked for Demo Programs that are similar to your goal Demos.PySimpleGUI.org
- [ ] If not tkinter - looked for Demo Programs for specific port
- [ ] For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
- [ ] Run your program outside of your debugger (from a command line)
- [ ] Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org
- [ ] Have upgraded to the latest release of PySimpleGUI on PyPI (lastest official version)
- [ ] Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released
#### Detailed Description

View file

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1,000 B

After

Width:  |  Height:  |  Size: 1,000 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before After
Before After

BIN
Chess/ChessPiecesArray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

View file

@ -0,0 +1,233 @@
import PySimpleGUI as sg
import os
import sys
import chess
import chess.pgn
import copy
import chess.uci
CHESS_PATH = '.' # path to the chess pieces
BLANK = 0 # piece names
PAWNB = 1
KNIGHTB = 2
BISHOPB = 3
ROOKB = 4
KINGB = 5
QUEENB = 6
PAWNW = 7
KNIGHTW = 8
BISHOPW = 9
ROOKW = 10
KINGW = 11
QUEENW = 12
initial_board = [[ROOKB, KNIGHTB, BISHOPB, QUEENB, KINGB, BISHOPB, KNIGHTB, ROOKB],
[PAWNB, ] * 8,
[BLANK, ] * 8,
[BLANK, ] * 8,
[BLANK, ] * 8,
[BLANK, ] * 8,
[PAWNW, ] * 8,
[ROOKW, KNIGHTW, BISHOPW, QUEENW, KINGW, BISHOPW, KNIGHTW, ROOKW]]
blank = os.path.join(CHESS_PATH, 'blank.png')
bishopB = os.path.join(CHESS_PATH, 'nbishopb.png')
bishopW = os.path.join(CHESS_PATH, 'nbishopw.png')
pawnB = os.path.join(CHESS_PATH, 'npawnb.png')
pawnW = os.path.join(CHESS_PATH, 'npawnw.png')
knightB = os.path.join(CHESS_PATH, 'nknightb.png')
knightW = os.path.join(CHESS_PATH, 'nknightw.png')
rookB = os.path.join(CHESS_PATH, 'nrookb.png')
rookW = os.path.join(CHESS_PATH, 'nrookw.png')
queenB = os.path.join(CHESS_PATH, 'nqueenb.png')
queenW = os.path.join(CHESS_PATH, 'nqueenw.png')
kingB = os.path.join(CHESS_PATH, 'nkingb.png')
kingW = os.path.join(CHESS_PATH, 'nkingw.png')
images = {BISHOPB: bishopB, BISHOPW: bishopW, PAWNB: pawnB, PAWNW: pawnW, KNIGHTB: knightB, KNIGHTW: knightW,
ROOKB: rookB, ROOKW: rookW, KINGB: kingB, KINGW: kingW, QUEENB: queenB, QUEENW: queenW, BLANK: blank}
def open_pgn_file(filename):
pgn = open(filename)
first_game = chess.pgn.read_game(pgn)
moves = [move for move in first_game.main_line()]
return moves
def render_square(image, key, location):
if (location[0] + location[1]) % 2:
color = '#B58863'
else:
color = '#F0D9B5'
return sg.RButton('', image_filename=image, size=(1, 1), button_color=('white', color), pad=(0, 0), key=key)
def redraw_board(window, board):
for i in range(8):
for j in range(8):
color = '#B58863' if (i + j) % 2 else '#F0D9B5'
piece_image = images[board[i][j]]
elem = window.FindElement(key=(i, j))
elem.Update(button_color=('white', color),
image_filename=piece_image, )
def PlayGame():
menu_def = [['&File', ['&Open PGN File', 'E&xit']],
['&Help', '&About...'], ]
# sg.SetOptions(margins=(0,0))
sg.ChangeLookAndFeel('GreenTan')
# create initial board setup
psg_board = copy.deepcopy(initial_board)
# the main board display layout
board_layout = [[sg.T(' ')] + [sg.T('{}'.format(a), pad=((23, 27), 0), font='Any 13') for a in 'abcdefgh']]
# loop though board and create buttons with images
for i in range(8):
row = [sg.T(str(8 - i) + ' ', font='Any 13')]
for j in range(8):
piece_image = images[psg_board[i][j]]
row.append(render_square(piece_image, key=(i, j), location=(i, j)))
row.append(sg.T(str(8 - i) + ' ', font='Any 13'))
board_layout.append(row)
# add the labels across bottom of board
board_layout.append([sg.T(' ')] + [sg.T('{}'.format(a), pad=((23, 27), 0), font='Any 13') for a in 'abcdefgh'])
# setup the controls on the right side of screen
openings = (
'Any', 'Defense', 'Attack', 'Trap', 'Gambit', 'Counter', 'Sicillian', 'English', 'French', 'Queen\'s openings',
'King\'s Openings', 'Indian Openings')
board_controls = [[sg.RButton('New Game', key='New Game'), sg.RButton('Draw')],
[sg.RButton('Resign Game'), sg.RButton('Set FEN')],
[sg.RButton('Player Odds'), sg.RButton('Training')],
[sg.Drop(openings), sg.Text('Opening/Style')],
[sg.CBox('Play As White', key='_white_')],
[sg.Drop([2, 3, 4, 5, 6, 7, 8, 9, 10], size=(3, 1), key='_level_'), sg.Text('Difficulty Level')],
[sg.Text('Move List')],
[sg.Multiline([], do_not_clear=True, autoscroll=True, size=(15, 10), key='_movelist_')],
]
# layouts for the tabs
controls_layout = [[sg.Text('Performance Parameters', font='_ 20')],
[sg.T('Put stuff like AI engine tuning parms on this tab')]]
statistics_layout = [[sg.Text('Statistics', font=('_ 20'))],
[sg.T('Game statistics go here?')]]
board_tab = [[sg.Column(board_layout)]]
# the main window layout
layout = [[sg.Menu(menu_def, tearoff=False)],
[sg.TabGroup([[sg.Tab('Board', board_tab),
sg.Tab('Controls', controls_layout),
sg.Tab('Statistics', statistics_layout)]], title_color='red'),
sg.Column(board_controls)],
[sg.Text('Click anywhere on board for next move', font='_ 14')]]
window = sg.Window('Chess',
default_button_element_size=(12, 1),
auto_size_buttons=False,
icon='kingb.ico').Layout(layout)
filename = sg.PopupGetFile('\n'.join(('To begin, set location of AI EXE file',
'If you have not done so already, download the engine',
'Download the StockFish Chess engine at: https://stockfishchess.org/download/')),
file_types=(('Chess AI Engine EXE File', '*.exe'),))
if filename is None:
sys.exit()
engine = chess.uci.popen_engine(filename)
engine.uci()
info_handler = chess.uci.InfoHandler()
engine.info_handlers.append(info_handler)
board = chess.Board()
move_count = 1
move_state = move_from = move_to = 0
# ---===--- Loop taking in user input --- #
while not board.is_game_over():
if board.turn == chess.WHITE:
engine.position(board)
# human_player(board)
move_state = 0
while True:
button, value = window.Read()
if button in (None, 'Exit'):
exit()
if button == 'New Game':
sg.Popup('You have to restart the program to start a new game... sorry....')
break
psg_board = copy.deepcopy(initial_board)
redraw_board(window, psg_board)
move_state = 0
break
level = value['_level_']
if type(button) is tuple:
if move_state == 0:
move_from = button
row, col = move_from
piece = psg_board[row][col] # get the move-from piece
button_square = window.FindElement(key=(row, col))
button_square.Update(button_color=('white', 'red'))
move_state = 1
elif move_state == 1:
move_to = button
row, col = move_to
if move_to == move_from: # cancelled move
color = '#B58863' if (row + col) % 2 else '#F0D9B5'
button_square.Update(button_color=('white', color))
move_state = 0
continue
picked_move = '{}{}{}{}'.format('abcdefgh'[move_from[1]], 8 - move_from[0],
'abcdefgh'[move_to[1]], 8 - move_to[0])
if picked_move in [str(move) for move in board.legal_moves]:
board.push(chess.Move.from_uci(picked_move))
else:
print('Illegal move')
move_state = 0
color = '#B58863' if (move_from[0] + move_from[1]) % 2 else '#F0D9B5'
button_square.Update(button_color=('white', color))
continue
psg_board[move_from[0]][move_from[1]] = BLANK # place blank where piece was
psg_board[row][col] = piece # place piece in the move-to square
redraw_board(window, psg_board)
move_count += 1
window.FindElement('_movelist_').Update(picked_move + '\n', append=True)
break
else:
engine.position(board)
best_move = engine.go(searchmoves=board.legal_moves, depth=level, movetime=(level * 100)).bestmove
move_str = str(best_move)
from_col = ord(move_str[0]) - ord('a')
from_row = 8 - int(move_str[1])
to_col = ord(move_str[2]) - ord('a')
to_row = 8 - int(move_str[3])
window.FindElement('_movelist_').Update(move_str + '\n', append=True)
piece = psg_board[from_row][from_col]
psg_board[from_row][from_col] = BLANK
psg_board[to_row][to_col] = piece
redraw_board(window, psg_board)
board.push(best_move)
move_count += 1
sg.Popup('Game over!', 'Thank you for playing')
# Download the StockFish Chess engine at: https://stockfishchess.org/download/
# engine = chess.uci.popen_engine(r'E:\DownloadsE\stockfish-9-win\Windows\stockfish_9_x64.exe')
# engine.uci()
# info_handler = chess.uci.InfoHandler()
# engine.info_handlers.append(info_handler)
# level = 2
PlayGame()

160
Chess/Demo_Chess_Board.py Normal file
View file

@ -0,0 +1,160 @@
import PySimpleGUI as sg
import os
import chess
import chess.pgn
import copy
import time
button_names = ('close', 'cookbook', 'cpu', 'github', 'pysimplegui', 'run', 'storage', 'timer')
CHESS_PATH = '.' # path to the chess pieces
BLANK = 0 # piece names
PAWNB = 1
KNIGHTB = 2
BISHOPB = 3
ROOKB = 4
KINGB = 5
QUEENB = 6
PAWNW = 7
KNIGHTW = 8
BISHOPW = 9
ROOKW = 10
KINGW = 11
QUEENW = 12
initial_board = [[ROOKB, KNIGHTB, BISHOPB, KINGB, QUEENB, BISHOPB, KNIGHTB, ROOKB ],
[PAWNB,]*8,
[BLANK,]*8,
[BLANK,]*8,
[BLANK,]*8,
[BLANK,]*8,
[PAWNW,]*8,
[ROOKW, KNIGHTW, BISHOPW, KINGW, QUEENW, BISHOPW, KNIGHTW, ROOKW]]
blank = os.path.join(CHESS_PATH, 'blank.png')
bishopB = os.path.join(CHESS_PATH, 'nbishopb.png')
bishopW = os.path.join(CHESS_PATH, 'nbishopw.png')
pawnB = os.path.join(CHESS_PATH, 'npawnb.png')
pawnW = os.path.join(CHESS_PATH, 'npawnw.png')
knightB = os.path.join(CHESS_PATH, 'nknightb.png')
knightW = os.path.join(CHESS_PATH, 'nknightw.png')
rookB = os.path.join(CHESS_PATH, 'nrookb.png')
rookW = os.path.join(CHESS_PATH, 'nrookw.png')
queenB = os.path.join(CHESS_PATH, 'nqueenB.png')
queenW = os.path.join(CHESS_PATH, 'nqueenW.png')
kingB = os.path.join(CHESS_PATH, 'nkingb.png')
kingW = os.path.join(CHESS_PATH, 'nkingw.png')
images = {BISHOPB: bishopB, BISHOPW: bishopW, PAWNB: pawnB, PAWNW: pawnW, KNIGHTB: knightB, KNIGHTW: knightW,
ROOKB: rookB, ROOKW: rookW, KINGB: kingB, KINGW: kingW, QUEENB: queenB, QUEENW: queenW, BLANK: blank}
def open_pgn_file(filename):
pgn = open(filename)
first_game = chess.pgn.read_game(pgn)
moves = [move for move in first_game.main_line()]
return moves
def render_square(image, key, location):
if (location[0] + location[1]) % 2:
color = '#B58863'
else:
color = '#F0D9B5'
return sg.RButton('', image_filename=image, size=(1, 1), button_color=('white', color), pad=(0, 0), key=key)
def redraw_board(window, board):
for i in range(8):
for j in range(8):
color = '#B58863' if (i+j) % 2 else '#F0D9B5'
piece_image = images[board[i][j]]
elem = window.FindElement(key=(i,j))
elem.Update(button_color = ('white', color),
image_filename=piece_image,)
def PlayGame():
menu_def = [['&File', ['&Open PGN File', 'E&xit' ]],
['&Help', '&About...'],]
# sg.SetOptions(margins=(0,0))
sg.ChangeLookAndFeel('GreenTan')
# create initial board setup
board = copy.deepcopy(initial_board)
# the main board display layout
board_layout = [[sg.T(' ')] + [sg.T('{}'.format(a), pad=((23,27),0), font='Any 13') for a in 'abcdefgh']]
# loop though board and create buttons with images
for i in range(8):
row = [sg.T(str(8-i)+' ', font='Any 13')]
for j in range(8):
piece_image = images[board[i][j]]
row.append(render_square(piece_image, key=(i,j), location=(i,j)))
row.append(sg.T(str(8-i)+' ', font='Any 13'))
board_layout.append(row)
# add the labels across bottom of board
board_layout.append([sg.T(' ')] + [sg.T('{}'.format(a), pad=((23,27),0), font='Any 13') for a in 'abcdefgh'])
# setup the controls on the right side of screen
openings = ('Any', 'Defense', 'Attack', 'Trap', 'Gambit','Counter', 'Sicillian', 'English','French', 'Queen\'s openings', 'King\'s Openings','Indian Openings')
board_controls = [[sg.RButton('New Game', key='Open PGN File'), sg.RButton('Draw')],
[sg.RButton('Resign Game'), sg.RButton('Set FEN')],
[sg.RButton('Player Odds'),sg.RButton('Training') ],
[sg.Drop(openings),sg.Text('Opening/Style')],
[sg.CBox('Play a White', key='_white_')],
[sg.Text('Move List')],
[sg.Multiline([], do_not_clear=True, autoscroll=True, size=(15,10),key='_movelist_')],]
# layouts for the tabs
controls_layout = [[sg.Text('Performance Parameters', font='_ 20')],
[sg.T('Put stuff like AI engine tuning parms on this tab')]]
statistics_layout = [[sg.Text('Statistics', font=('_ 20'))],
[sg.T('Game statistics go here?')]]
board_tab = [[sg.Column(board_layout)]]
# the main window layout
layout = [[sg.Menu(menu_def, tearoff=False)],
[sg.TabGroup([[sg.Tab('Board',board_tab),
sg.Tab('Controls', controls_layout),
sg.Tab('Statistics', statistics_layout)]], title_color='red'),
sg.Column(board_controls)],
[sg.Text('Click anywhere on board for next move', font='_ 14')]]
window = sg.Window('Chess', default_button_element_size=(12,1), auto_size_buttons=False, icon='kingb.ico').Layout(layout)
# ---===--- Loop taking in user input --- #
i = 0
moves = None
while True:
button, value = window.Read()
if button in (None, 'Exit'):
break
if button == 'Open PGN File':
filename = sg.PopupGetFile('', no_window=True)
if filename is not None:
moves = open_pgn_file(filename)
i = 0
board = copy.deepcopy(initial_board)
window.FindElement('_movelist_').Update(value='')
if button == 'About...':
sg.Popup('Powerd by Engine Kibitz Chess Engine')
if type(button) is tuple and moves is not None and i < len(moves):
move = moves[i] # get the current move
window.FindElement('_movelist_').Update(value='{} {}\n'.format(i+1, str(move)), append=True)
move_from = move.from_square # parse the move-from and move-to squares
move_to = move.to_square
row, col = move_from // 8, move_from % 8
piece = board[row][col] # get the move-from piece
button = window.FindElement(key=(row,col))
for x in range(3):
button.Update(button_color = ('white' , 'red' if x % 2 else 'white'))
window.Refresh()
time.sleep(.05)
board[row][col] = BLANK # place blank where piece was
row, col = move_to // 8, move_to % 8 # compute move-to square
board[row][col] = piece # place piece in the move-to square
redraw_board(window, board)
i += 1
PlayGame()

BIN
Chess/bishopb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
Chess/bishopw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
Chess/blank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

36
Chess/game.pgn Normal file
View file

@ -0,0 +1,36 @@
[Event "Wch U12"]
[Site "Duisburg"]
[Date "1992.??.??"]
[Round "1"]
[White "Malakhov, Vladimir"]
[Black "Ab Rahman, M."]
[Result "1-0"]
[WhiteElo ""]
[BlackElo ""]
[ECO "A05"]
1.Nf3 Nf6 2.b3 g6 3.Bb2 Bg7 4.g3 d6 5.Bg2 O-O 6.O-O c6 7.d3 e5 8.c4 Ne8 9.Nbd2 f5
10.Qc2 Na6 11.c5 Nxc5 12.Nxe5 Qe7 13.d4 Na6 14.Qc4+ Kh8 15.Nef3 Be6 16.Qc3 f4
17.gxf4 Rxf4 18.Qe3 Rf8 19.Ng5 Nec7 20.Nc4 Rae8 21.Nxe6 Qxe6 22.Qxe6 Rxe6
23.e3 d5 24.Ne5 g5 25.Ba3 Rff6 26.Bh3 Re8 27.Bd7 Rd8 28.Be7 Rxd7 29.Bxf6 1-0
[Event "Wch U12"]
[Site "Duisburg"]
[Date "1992.??.??"]
[Round "2"]
[White "Malakhov, Vladimir"]
[Black "Berescu, Alin"]
[Result "1-0"]
[WhiteElo ""]
[BlackElo ""]
[ECO "D05"]
1.d4 Nf6 2.Nd2 d5 3.Ngf3 e6 4.e3 c5 5.c3 Nbd7 6.Bd3 Bd6 7.O-O O-O 8.Re1 b6
9.e4 dxe4 10.Nxe4 Be7 11.Ne5 Bb7 12.Ng5 g6 13.Qe2 Nxe5 14.dxe5 Nh5 15.Ne4 Qd5
16.f4 Rfd8 17.Bc2 Qc6 18.Be3 Rd7 19.Rad1 Rad8 20.Rxd7 Rxd7 21.Nd2 Ng7 22.Be4 Qc8
23.g4 Qd8 24.Bxb7 Rxb7 25.Ne4 Rd7 26.c4 h5 27.h3 h4 28.Kh2 Ne8 29.f5 Qc7
30.Bf4 Rd4 31.Qf2 Rxc4 32.f6 Qb7 33.Ng5 Bf8 34.b3 Rc3 35.Qd2 Rf3 36.Nxf3 Qxf3
37.Qe3 Qd5 38.Qe4 Qd7 39.Qf3 Nc7 40.Rd1 Nd5 41.Bg5 Qc7 42.Re1 b5 43.Qd1 c4
44.Qc1 Bb4 45.Bd2 Bxd2 46.Qxd2 Nxf6 47.bxc4 bxc4 48.Qd6 Qa5 49.Rf1 Nd5 50.Qd7 Qd2+
51.Kh1 f5 52.exf6 1-0

BIN
Chess/kingb.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
Chess/kingb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
Chess/kingw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/knightb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
Chess/knightw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
Chess/nbishopb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
Chess/nbishopw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/nkingb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/nkingw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
Chess/nknightb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/nknightw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
Chess/npawnb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/npawnw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/nqueenb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
Chess/nqueenw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
Chess/nrookb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Chess/nrookw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
Chess/pawnb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

BIN
Chess/pawnw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
Chess/queenb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Chess/queenw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

16
Chess/readme.md Normal file
View file

@ -0,0 +1,16 @@
# PySimpleGUI-Chess A Chess Game Playback Program
![image](https://user-images.githubusercontent.com/46163555/64135781-4c58a600-cdba-11e9-968d-60ddfb4c8952.png)
## Introduction
This is the start of a front-end GUI for an AI engine that plays chess. It simply reads moves the a PGN file and steps through it showing each of the moves on the board.
To play against the AI run the program
Demo_Chess_AGAINST_AI.py
Locate where the pacakge was installed and run the programs from that folder. You need to run from the installed folder so that the images of the chess pieces are located.
## Home Page (GitHub)
[www.PySimpleGUI.com](www.PySimpleGUI.com)

2
Chess/requirements.txt Normal file
View file

@ -0,0 +1,2 @@
PySimpleGUI==3.9.1
python-chess==0.23.9

BIN
Chess/rookb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

BIN
Chess/rookw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

View file

@ -5,7 +5,7 @@ import warnings
import PySimpleGUI as sg
__version__ = '1.12.2'
__version__ = '1.7.0'
"""
PySimpleGUI Demo Program Browser
@ -33,15 +33,9 @@ __version__ = '1.12.2'
Keeps a "history" of the previously chosen folders to easy switching between projects
Versions:
1.8.0 - Addition of option to show ALL file types, not just Python files
1.12.0 - Fix for problem with spaces in filename and using an editor specified in the demo program settings
1.12.2 - Better error handling for no editor configured
Copyright 2021, 2022 PySimpleGUI.org
"""
python_only = True
def get_file_list_dict():
"""
Returns dictionary of files
@ -56,7 +50,7 @@ def get_file_list_dict():
demo_files_dict = {}
for dirname, dirnames, filenames in os.walk(demo_path):
for filename in filenames:
if python_only is not True or filename.endswith('.py') or filename.endswith('.pyw'):
if filename.endswith('.py') or filename.endswith('.pyw'):
fname_full = os.path.join(dirname, filename)
if filename not in demo_files_dict.keys():
demo_files_dict[filename] = fname_full
@ -462,7 +456,7 @@ def make_window():
left_col = sg.Column([
[sg.Listbox(values=get_file_list(), select_mode=sg.SELECT_MODE_EXTENDED, size=(50,20), bind_return_key=True, key='-DEMO LIST-', expand_x=True, expand_y=True)],
[sg.Listbox(values=get_file_list(), select_mode=sg.SELECT_MODE_EXTENDED, size=(50,20), bind_return_key=True, key='-DEMO LIST-')],
[sg.Text('Filter (F1):', tooltip=filter_tooltip), sg.Input(size=(25, 1), focus=True, enable_events=True, key='-FILTER-', tooltip=filter_tooltip),
sg.T(size=(15,1), k='-FILTER NUMBER-')],
[sg.Button('Run'), sg.B('Edit'), sg.B('Clear'), sg.B('Open Folder'), sg.B('Copy Path')],
@ -474,7 +468,7 @@ def make_window():
[sg.Text('Find (F3):', tooltip=find_re_tooltip), sg.Input(size=(25, 1),key='-FIND RE-', tooltip=find_re_tooltip),sg.B('Find RE')]], k='-RE COL-'))
right_col = [
[sg.Multiline(size=(70, 21), write_only=True, expand_x=True, expand_y=True, key=ML_KEY, reroute_stdout=True, echo_stdout_stderr=True, reroute_cprint=True)],
[sg.Multiline(size=(70, 21), write_only=True, key=ML_KEY, reroute_stdout=True, echo_stdout_stderr=True, reroute_cprint=True)],
[sg.B('Settings'), sg.Button('Exit')],
[sg.T('Demo Browser Ver ' + __version__)],
[sg.T('PySimpleGUI ver ' + sg.version.split(' ')[0] + ' tkinter ver ' + sg.tclversion_detailed, font='Default 8', pad=(0,0))],
@ -485,8 +479,7 @@ def make_window():
options_at_bottom = sg.pin(sg.Column([[sg.CB('Verbose', enable_events=True, k='-VERBOSE-', tooltip='Enable to see the matches in the right hand column'),
sg.CB('Show only first match in file', default=True, enable_events=True, k='-FIRST MATCH ONLY-', tooltip='Disable to see ALL matches found in files'),
sg.CB('Find ignore case', default=True, enable_events=True, k='-IGNORE CASE-'),
sg.CB('Wait for Runs to Complete', default=False, enable_events=True, k='-WAIT-'),
sg.CB('Show ALL file types', default=not python_only, enable_events=True, k='-SHOW ALL FILES-'),
sg.CB('Wait for Runs to Complete', default=False, enable_events=True, k='-WAIT-')
]],
pad=(0,0), k='-OPTIONS BOTTOM-', expand_x=True, expand_y=False), expand_x=True, expand_y=False)
@ -497,15 +490,16 @@ def make_window():
layout = [[sg.Text('PySimpleGUI Demo Program & Project Browser', font='Any 20')],
[choose_folder_at_top],
# [sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True)],
[sg.Pane([sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True) ], orientation='h', relief=sg.RELIEF_SUNKEN, expand_x=True, expand_y=True, k='-PANE-')],
[options_at_bottom, sg.Sizegrip()]]
[sg.Pane([sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True) ], orientation='h', relief=sg.RELIEF_SUNKEN, k='-PANE-')],
[options_at_bottom]]
# --------------------------------- Create Window ---------------------------------
window = sg.Window('PSG Demo & Project Browser', layout, finalize=True, resizable=True, use_default_focus=False, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window.set_min_size(window.size)
# window.bind("<Alt_L><x>", 'Exit') # matches the underscore shown on the Exit button (For now disabled this feature until buttons with underscore released to PyPI)
window['-DEMO LIST-'].expand(True, True, True)
window[ML_KEY].expand(True, True, True)
window['-PANE-'].expand(True, True, True)
window.bind('<F1>', '-FOCUS FILTER-')
window.bind('<F2>', '-FOCUS FIND-')
@ -527,12 +521,11 @@ def main():
The main program that contains the event loop.
It will call the make_window function to create the window.
"""
global python_only
try:
version = sg.version
version_parts = version.split('.')
major_version, minor_version = int(version_parts[0]), int(version_parts[1])
if major_version < 4 or (major_version== 4 and minor_version < 32):
if major_version < 4 or minor_version < 32:
sg.popup('Warning - Your PySimpleGUI version is less then 4.35.0',
'As a result, you will not be able to use the EDIT features of this program',
'Please upgrade to at least 4.35.0',
@ -577,16 +570,16 @@ def main():
sg.cprint(f'Editing using {editor_program}', c='white on red', end='')
sg.cprint('')
sg.cprint(f'{full_filename}', c='white on purple')
if not get_editor():
sg.popup_error_with_traceback('No editor has been configured', 'You need to configure an editor in order to use this feature', 'You can configure the editor in the Demo Brower Settings or the PySimpleGUI Global Settings')
else:
# if line != 1:
if using_local_editor():
sg.execute_command_subprocess(editor_program, f'"{full_filename}"')
sg.execute_command_subprocess(editor_program, full_filename)
else:
try:
sg.execute_editor(full_filename, line_number=int(line))
except:
sg.execute_command_subprocess(editor_program, f'"{full_filename}"')
sg.execute_command_subprocess(editor_program, full_filename)
# else:
# sg.execute_editor(full_filename)
else:
sg.cprint('Editing canceled')
elif event == 'Run':
@ -724,17 +717,6 @@ def main():
sg.clipboard_set(full_filename)
elif event == 'Version':
sg.popup_scrolled(sg.get_versions(), keep_on_top=True, non_blocking=True)
elif event == '-SHOW ALL FILES-':
python_only = not values[event]
file_list_dict = get_file_list_dict()
file_list = get_file_list()
window['-DEMO LIST-'].update(values=file_list)
window['-FILTER NUMBER-'].update(f'{len(file_list)} files')
window['-ML-'].update('')
window['-FIND NUMBER-'].update('')
window['-FIND-'].update('')
window['-FIND RE-'].update('')
window['-FILTER-'].update('')
window.close()

View file

@ -11,7 +11,7 @@
Displays the values dictionary entry for each element
And more!
Copyright 2021, 2022, 2023 PySimpleGUI
Copyright 2021 PySimpleGUI
"""
import PySimpleGUI as sg
@ -36,7 +36,7 @@ def make_window(theme):
sg.Image(data=sg.DEFAULT_BASE64_LOADING_GIF, enable_events=True, key='-GIF-IMAGE-'),],
[sg.Checkbox('Checkbox', default=True, k='-CB-')],
[sg.Radio('Radio1', "RadioDemo", default=True, size=(10,1), k='-R1-'), sg.Radio('Radio2', "RadioDemo", default=True, size=(10,1), k='-R2-')],
[sg.Combo(values=('Combo 1', 'Combo 2', 'Combo 3'), default_value='Combo 1', readonly=False, k='-COMBO-'),
[sg.Combo(values=('Combo 1', 'Combo 2', 'Combo 3'), default_value='Combo 1', readonly=True, k='-COMBO-'),
sg.OptionMenu(values=('Option 1', 'Option 2', 'Option 3'), k='-OPTION MENU-'),],
[sg.Spin([i for i in range(1,11)], initial_value=10, k='-SPIN-'), sg.Text('Spin')],
[sg.Multiline('Demo of a Multi-Line Text Element!\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nYou get the point.', size=(45,5), expand_x=True, expand_y=True, k='-MLINE-')],
@ -88,7 +88,9 @@ def make_window(theme):
]]
layout[-1].append(sg.Sizegrip())
window = sg.Window('All Elements Demo', layout, right_click_menu=right_click_menu_def, right_click_menu_tearoff=True, grab_anywhere=True, resizable=True, margins=(0,0), use_custom_titlebar=True, finalize=True, keep_on_top=True)
window = sg.Window('All Elements Demo', layout, right_click_menu=right_click_menu_def, right_click_menu_tearoff=True, grab_anywhere=True, resizable=True, margins=(0,0), use_custom_titlebar=True, finalize=True, keep_on_top=True,
# scaling=2.0,
)
window.set_min_size(window.size)
return window
@ -99,6 +101,7 @@ def main():
while True:
event, values = window.read(timeout=100)
# keep an animation running so show things are happening
window['-GIF-IMAGE-'].update_animation(sg.DEFAULT_BASE64_LOADING_GIF, time_between_frames=100)
if event not in (sg.TIMEOUT_EVENT, sg.WIN_CLOSED):
print('============ Event = ', event, ' ==============')
print('-------- Values Dictionary (key=value) --------')
@ -107,9 +110,7 @@ def main():
if event in (None, 'Exit'):
print("[LOG] Clicked Exit!")
break
window['-GIF-IMAGE-'].update_animation(sg.DEFAULT_BASE64_LOADING_GIF, time_between_frames=100)
if event == 'About':
elif event == 'About':
print("[LOG] Clicked About!")
sg.popup('PySimpleGUI Demo All Elements',
'Right click anywhere to see right click menu',
@ -150,7 +151,7 @@ def main():
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Versions':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
sg.popup(sg.get_versions(), keep_on_top=True)
window.close()
exit(0)

View file

@ -8,8 +8,7 @@ import PySimpleGUI as sg
Copyright 2022 PySimpleGUI
"""
use_custom_titlebar = True if sg.running_trinket() else False
use_custom_titlebar = False
def make_window(theme=None):
@ -51,7 +50,7 @@ def make_window(theme=None):
[name('Image'), sg.Image(sg.EMOJI_BASE64_HAPPY_THUMBS_UP)],
[name('Graph'), sg.Graph((125, 50), (0,0), (125,50), k='-GRAPH-')] ]
layout_r = [[name('Canvas'), sg.Canvas(background_color=sg.theme_button_color()[1], size=(125,40))],
layout_r = [[name('Canvas'), sg.Canvas(background_color=sg.theme_button_color()[1], size=(125,50))],
[name('ProgressBar'), sg.ProgressBar(100, orientation='h', s=(10,20), k='-PBAR-')],
[name('Table'), sg.Table([[1,2,3], [4,5,6]], ['Col 1','Col 2','Col 3'], num_rows=2)],
[name('Tree'), sg.Tree(treedata, ['Heading',], num_rows=3)],
@ -69,9 +68,9 @@ def make_window(theme=None):
# Note - LOCAL Menu element is used (see about for how that's defined)
layout = [[Menu([['File', ['Exit']], ['Edit', ['Edit Me', ]]], k='-CUST MENUBAR-',p=0)],
[sg.T('PySimpleGUI Elements - Use Combo to Change Themes', font='_ 14', justification='c', expand_x=True)],
[sg.Checkbox('Use Custom Titlebar & Menubar', use_custom_titlebar, enable_events=True, k='-USE CUSTOM TITLEBAR-', p=0)],
[sg.Col(layout_l, p=0), sg.Col(layout_r, p=0)]]
[sg.Checkbox('Use Custom Titlebar & Menubar', sg.theme_use_custom_titlebar(), enable_events=True, k='-USE CUSTOM TITLEBAR-')],
[sg.T('PySimpleGUI Elements - Use Combo to Change Themes', font='_ 18', justification='c', expand_x=True)],
[sg.Col(layout_l), sg.Col(layout_r)]]
window = sg.Window('The PySimpleGUI Element List', layout, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, keep_on_top=True, use_custom_titlebar=use_custom_titlebar)
@ -88,7 +87,8 @@ while True:
# sg.Print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Edit Me':
sg.execute_editor(__file__)
if values['-COMBO-'] != sg.theme():
sg.theme(values['-COMBO-'])
window.close()
@ -98,10 +98,8 @@ while True:
sg.set_options(use_custom_titlebar=use_custom_titlebar)
window.close()
window = make_window()
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
sg.popup_scrolled(sg.get_versions(), __file__, keep_on_top=True, non_blocking=True)
window.close()

View file

@ -1,21 +1,22 @@
import PySimpleGUI as sg
import random
"""
Demo - Using a Graph Element to make Bar Charts
The Graph Element is very versatile. Because you can define your own
coordinate system, it makes producing graphs of many lines (bar, line, etc) very
straightforward.
In this Demo a "bar" is nothing more than a rectangle drawn in a Graph Element (draw_rectangle).
To make things a little more interesting, this is a barchart with that data values
placed as labels atop each bar, another Graph element method (draw_text)
Copyright 2022 PySimpleGUI
"""
# Bars drawing in PySimpleGUI
#
# .--.
# | |
# .--.| |.--.
# | || || |
# | || || |
# | || || |
# .--.| || || |
# .--.| || || || |.--.
# | || || || || || |
# | || || || || || |
# .--.| || || || || || |.--.
# | || || || || || || || |.--.
# | || || || || || || || || |
# '--''--''--''--''--''--''--''--''--'
BAR_WIDTH = 50 # width of each bar
@ -37,13 +38,12 @@ while True:
graph.erase()
for i in range(7):
graph_value = random.randint(0, GRAPH_SIZE[1]-25) # choose an int just short of the max value to give room for the label
graph_value = random.randint(0, GRAPH_SIZE[1])
graph.draw_rectangle(top_left=(i * BAR_SPACING + EDGE_OFFSET, graph_value),
bottom_right=(i * BAR_SPACING + EDGE_OFFSET + BAR_WIDTH, 0),
fill_color='green')
# fill_color=sg.theme_button_color()[1])
fill_color=sg.theme_button_color()[1])
graph.draw_text(text=graph_value, location=(i*BAR_SPACING+EDGE_OFFSET+25, graph_value+10), font='_ 14')
graph.draw_text(text=graph_value, location=(i*BAR_SPACING+EDGE_OFFSET+25, graph_value+10))
# Normally at the top of the loop, but because we're drawing the graph first, making it at the bottom
event, values = window.read()

File diff suppressed because one or more lines are too long

View file

@ -1,79 +0,0 @@
import PySimpleGUI as sg
"""
Demo Program - Simulated Buttons with Mouseover Highlights
The purpose of this demo is to teach you 5 unique PySimpleGUI constructs that when combined
create a "Button" that highlights on mouseover regarless of the Operating System.
Because of how tktiner works, mouseover highlighting is inconsistent across operating systems for Buttons.
This is one (dare I say "clever") way to get this effect in your program
1. Binding the Enter and Leave tkinter events
2. Using Tuples as keys
3. Using List Comprehensions to build a layout
4. Using Text Elements to Simulate Buttons
5. Using a "User Defined Element" to make what appears to be a new type of Button in the layout
The KEY to making this work simply is these "Buttons" have a tuple as a key.
The format of the key is ('-B-', button_text)
An element's bind method will make a tuple if the original key is a tuple.
(('-B-', button_text), 'ENTER') will be the event when the mouse is moved over the "Button"
Copyright 2022 PySimpleGUI.org
"""
# sg.theme('dark red')
def TextButton(text):
"""
A User Defined Element. It looks like a Button, but is a Text element
:param text: The text that will be put on the "Button"
:return: A Text element with a tuple as the key
"""
return sg.Text(text, key=('-B-', text), relief='raised', enable_events=True, font='_ 15',text_color=sg.theme_button_color_text(), background_color=sg.theme_button_color_background())
def do_binds(window, button_text):
"""
This is magic code that enables the mouseover highlighting to work.
"""
for btext in button_text:
window[('-B-', btext)].bind('<Enter>', 'ENTER')
window[('-B-', btext)].bind('<Leave>', 'EXIT')
def main():
# Defines the text on the 3 buttons we're making
button_text = ('Button 1', 'Button 2', 'Button 3')
# The window's layout
layout = [[TextButton(text) for text in button_text],
[sg.Text(font='_ 14', k='-STATUS-')],
[sg.Ok(), sg.Exit()]]
window = sg.Window('Custom Mouseover Highlighting Buttons', layout, finalize=True)
# After the window is finalized, then can perform the bindings
do_binds(window, button_text)
# The Event Looop
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
# if the event is a tuple, it's one of our TextButtons
if isinstance(event, tuple):
# if second item is one of the bound strings, then do the mouseeover code
if event[1] in ('ENTER', 'EXIT'):
button_key = event[0]
if event[1] == 'ENTER':
window[button_key].update(text_color=sg.theme_button_color_background(), background_color=sg.theme_button_color_text())
if event[1] == 'EXIT':
window[button_key].update(text_color=sg.theme_button_color_text(), background_color=sg.theme_button_color_background())
else: # a "normal" button click (Text clicked) so print the text which we put into the tuple
window['-STATUS-'].update(f'Button pressed = {event[1]}')
window.close()
if __name__ == '__main__':
main()

View file

@ -1,12 +1,5 @@
#!/usr/bin/env python
import PySimpleGUI as sg
"""
Demo - Base64 Buttons with Images
This is perhaps the easiest, quickest, and safest way to use buttons with images in PySimpleGUI.
By putting the button into your code, then you only have to distribute a single file.
Copyright 2022 PySimpleGUI
"""
# First the button images
@ -14,19 +7,24 @@ play = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAA
stop = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAAaklEQVRoge3ZQQqAMAxFwSre/8p6AZFUiXzKzLqLPNJVOwYAvLcVzpztU9Q8zrr/NUW3Y+JsZXsdSjdimY0ISSMkjZA0QtIISSMkjZA0QtIISSMkjZA0QtIISSMkzcxrfMo/ya1lNgIAX1zq+ANHUjXZuAAAAABJRU5ErkJggg=='
eject = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAByklEQVRoge3YO2gUURSA4S+JRnyACIGADyxERAsb0UKrWIidWIidlSA2YpFWSauNVtrYiIU2YpFCLGwEEWwsBAsLEbFQFARFfKBZizkyK5pkZvZmZ7PeH05z595z/sPszpxdMplMJpMZbDZFLGsm8CxiomWXxqzBQ3QiHmNdq0YNGMc9RQOvIjqxNt6iVy1GcF0h/h47sR1vY+0mRluzq8ElhfBn7O9a34tPce1KC161OK8Q/Y7D/7h+EF9jz7k+etXilELwJ44vsO8ofsTeM33wqsURpdzZCvtPK5s+toRetZjCF4XYTI1zM3HmGw4lt6rJbnxQCF1tcP5ynP2IPQm9arENb0LkDsYa5BjFrcjxDjuS2VVkI16EwH2s6iHXStxVvjy39GxXkfV4Iu3Y0T3OPMWGBDkXZDUeRMHnmEyY+/eA2cEjrE2Y+w/GcDsKvcbWJaixGS+jxixWpC4wgmvK+WlX6gJddM9lN6J2Mi4q56cDKRPPwz7lXHYhVdJp5W+KtmK61yZOYG4AGpnDyV6byWT+ZxZ7Rnf6YlGdeX2XxZ8AVag6AiR9uzZg0U/G0NyR3MigUfU7MmhPr78YmjuSyWQymUxmmPgFokSdfYSQKDwAAAAASUVORK5CYII='
sg.theme('Light Green 3')
sg.theme('Light Green 3') # Set a color theme
bg = sg.LOOK_AND_FEEL_TABLE[sg.CURRENT_LOOK_AND_FEEL]['BACKGROUND'] # Get the background for the current theme
# Define the window's layout
layout = [[sg.Button(image_data=play, key='-PLAY-', button_color=sg.theme_background_color(), border_width=0),
sg.Button(image_data=stop, key='-STOP-', button_color=sg.theme_background_color(), border_width=0),
sg.Button(image_data=eject, key='-EXIT-', button_color=sg.theme_background_color(), border_width=0)] ]
layout = [ [sg.Text('Your Application', font='Any 15')],
[sg.Text('Event = '), sg.Text(size=(12,1), key='-OUT-')],
[sg.Button(image_data=play, key='Play', border_width=0, button_color=(bg, bg)),
sg.Button(image_data=stop, key='Stop', button_color=(bg, bg), border_width=0),
sg.Button(image_data=eject, key='Exit', button_color=(bg, bg), border_width=0)] ]
# Create the window
window = sg.Window('Simple Base64 Buttons', layout)
window = sg.Window('Window Title', layout)
while True: # Event Loop
event, values = window.read() # type: str, dict
print(event, values)
if event in (sg.WIN_CLOSED, '-EXIT-'): # If the user exits
if event in (sg.WIN_CLOSED, 'Exit'): # If the user exits
break
window.close() # Exiting so clean up
window['-OUT-'].Update(event) # Output the event to the window
window.close(); del window # Exiting so clean up

View file

@ -26,7 +26,7 @@ def resize_base64_image(image64, size):
'''
image_file = io.BytesIO(base64.b64decode(image64))
img = Image.open(image_file)
img.thumbnail(size, Image.LANCZOS)
img.thumbnail(size, Image.ANTIALIAS)
bio = io.BytesIO()
img.save(bio, format='PNG')
imgbytes = bio.getvalue()

View file

@ -1,26 +0,0 @@
"""
Demo Command Line Application or GUI Application
If your program is run with arguments, then a command line version is used.
If no arguments are given, then a GUI is shown that asks for a filename.
http://www.PySimpleGUI.org
Copyright 2022 PySimpleGUI
"""
import PySimpleGUI as sg
import sys
def main_cli(filename):
print(f'Your filename = {filename}')
def main_gui():
filename = sg.popup_get_file('Please enter a filename:')
main_cli(filename)
if __name__ == '__main__':
if len(sys.argv) < 2:
main_gui()
else:
main_cli(sys.argv[1])

View file

@ -4,27 +4,24 @@ import PySimpleGUI as sg
'''
A simple send/response chat window. Add call to your send-routine and print the response
If async responses can come in, then will need to use a different design that uses PySimpleGUI async design pattern
Copyright 2023 PySimpleGUI
'''
sg.theme('GreenTan') # give our window a spiffy set of colors
layout = [[sg.Text('Your output will go here', size=(40, 1))],
[sg.Output(size=(110, 20), font=('Helvetica 10'))],
[sg.Multiline(size=(70, 5), enter_submits=True, key='-QUERY-', do_not_clear=False),
[sg.Multiline(size=(70, 5), enter_submits=False, key='-QUERY-', do_not_clear=False),
sg.Button('SEND', button_color=(sg.YELLOWS[0], sg.BLUES[0]), bind_return_key=True),
sg.Button('EXIT', button_color=(sg.YELLOWS[0], sg.GREENS[0]))]]
window = sg.Window('Chat window', layout, font=('Helvetica', ' 13'), default_button_element_size=(8,2), use_default_focus=False)
while True: # The Event Loop
event, values = window.read()
event, value = window.read()
if event in (sg.WIN_CLOSED, 'EXIT'): # quit if exit button or X
break
if event == 'SEND':
query = values['-QUERY-'].rstrip()
query = value['-QUERY-'].rstrip()
# EXECUTE YOUR COMMAND HERE
print('The command you entered was {}'.format(query), flush=True)

View file

@ -1,45 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Custom Checkboxes done simply
The Base64 Image encoding feature of PySimpleGUI makes it possible to create beautiful GUIs very simply
These 2 checkboxes required 3 extra lines of code than a normal checkbox.
1. Keep track of the current value using the Image Element's Metadata
2. Changle / Update the image when clicked
3. The Base64 image definition
Enable the event on the Image with the checkbox so that you can take action (flip the value)
Copyright 2022 PySimpleGUI
"""
def main():
layout = [[sg.Text('Fancy Checkboxes... Simply')],
[sg.Image(checked, key=('-IMAGE-', 1), metadata=True, enable_events=True), sg.Text(True, enable_events=True, k=('-TEXT-', 1))],
[sg.Image(unchecked, key=('-IMAGE-', 2), metadata=False, enable_events=True), sg.Text(False, enable_events=True, k=('-TEXT-', 2))],
[sg.Button('Go'), sg.Button('Exit')]]
window = sg.Window('Custom Checkboxes', layout, font="_ 14")
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
# if a checkbox is clicked, flip the vale and the image
if event[0] in ('-IMAGE-', '-TEXT-'):
cbox_key = ('-IMAGE-', event[1])
text_key = ('-TEXT-', event[1])
window[cbox_key].metadata = not window[cbox_key].metadata
window[cbox_key].update(checked if window[cbox_key].metadata else unchecked)
# Update the string next to the checkbox
window[text_key].update(window[cbox_key].metadata)
window.close()
if __name__ == '__main__':
checked = b'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'
unchecked = b'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'
main()

View file

@ -5,37 +5,9 @@ import PySimpleGUI as sg
Using a class to encapsulate PySimpleGUI Window creation & event loop
This is NOT a recommended design pattern. It mimics the object oriented design that many OO-based
GUI frameworks use, but there is no advantage to structuring you code in his manner. It adds
confusion, not clarity.
The class version is 18 lines of code. The plain version is 13 lines of code.
Two things about the class wrapper jump out as adding confusion:
1. Unneccessary fragmentation of the event loop - the button click code is pulled out of the loop entirely
2. "self" clutters the code without adding value
Copyright 2022, 2023 PySimpleGUI
Copyright 2022 PySimpleGUI
"""
'''
MM'""""'YMM dP
M' .mmm. `M 88
M MMMMMooM 88 .d8888b. .d8888b. .d8888b.
M MMMMMMMM 88 88' `88 Y8ooooo. Y8ooooo.
M. `MMM' .M 88 88. .88 88 88
MM. .dM dP `88888P8 `88888P' `88888P'
MMMMMMMMMMM
M""MMMMM""M oo
M MMMMM M
M MMMMP M .d8888b. 88d888b. .d8888b. dP .d8888b. 88d888b.
M MMMM' .M 88ooood8 88' `88 Y8ooooo. 88 88' `88 88' `88
M MMP' .MM 88. ... 88 88 88 88. .88 88 88
M .dMMM `88888P' dP `88888P' dP `88888P' dP dP
MMMMMMMMMMM
'''
class SampleGUI():
def __init__(self):
@ -63,41 +35,3 @@ class SampleGUI():
my_gui = SampleGUI()
# run the event loop
my_gui.run()
'''
M"""""""`YM dP
M mmmm. M 88
M MMMMM M .d8888b. 88d888b. 88d8b.d8b. .d8888b. 88
M MMMMM M 88' `88 88' `88 88'`88'`88 88' `88 88
M MMMMM M 88. .88 88 88 88 88 88. .88 88
M MMMMM M `88888P' dP dP dP dP `88888P8 dP
MMMMMMMMMMM
M""MMMMM""M oo
M MMMMM M
M MMMMP M .d8888b. 88d888b. .d8888b. dP .d8888b. 88d888b.
M MMMM' .M 88ooood8 88' `88 Y8ooooo. 88 88' `88 88' `88
M MMP' .MM 88. ... 88 88 88 88. .88 88 88
M .dMMM `88888P' dP `88888P' dP `88888P' dP dP
MMMMMMMMMMM
'''
def gui_function():
layout = [ [sg.Text('My layout')],
[sg.Input(key='-IN-')],
[sg.Button('Go'), sg.Button('Exit')] ]
window = sg.Window('My new window', layout)
while True: # Event Loop
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
if event == 'Go':
sg.popup('Go button clicked', 'Input value:', values['-IN-'])
window.close()
gui_function()

View file

@ -1,48 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Preview tkinter cursors
Shows the standard tkinter cursors using Buttons
The name of the cursor is on the Button. Mouse over the Button and you'll see
what that cursor looks like.
This list of cursors is a constant defined in PySimpleGUI. The constant name is:
sg.TKINTER_CURSORS
Copyright 2022 PySimpleGUI
"""
cursors = sg.TKINTER_CURSORS
# Make a layout that's 10 buttons across
NUM_BUTTONS_PER_ROW = 10
layout = [[]]
row = []
for i, c in enumerate(cursors):
# print(i, c)
row.append(sg.Button(c, size=(14,3), k=c))
if ((i+1) % NUM_BUTTONS_PER_ROW) == 0:
layout.append(row)
row = []
# print(row)
# Add on the last, partial row
start = len(cursors)//NUM_BUTTONS_PER_ROW * NUM_BUTTONS_PER_ROW
row = []
for i in range(start, len(cursors)):
row.append(sg.Button(cursors[i], size=(14,3), k=cursors[i]))
layout.append(row)
window = sg.Window('Cursor Previewer',layout, finalize=True)
# set the cursor on each of the buttons that has the name of the cursor as the text
for c in cursors:
window[c].set_cursor(c)
# The ubiquitous event loop...
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
window.close()

View file

@ -9,11 +9,11 @@ import webbrowser
If you want no cursor, set the cursor to the string 'none'.
Copyright 2021, 2022 PySimpleGUI
Copyright 2021 PySimpleGUI
"""
# Here is a more complete list of cursors you can choose from
cursors = sg.TKINTER_CURSORS
cursors = ('X_cursor', 'no', 'arrow','based_arrow_down','based_arrow_up','boat','bogosity','bottom_left_corner','bottom_right_corner','bottom_side','bottom_tee','box_spiral','center_ptr','circle','clock','coffee_mug','cross','cross_reverse','crosshair','diamond_cross','dot','dotbox','double_arrow','draft_large','draft_small','draped_box','exchange','fleur','gobbler','gumby','hand1','hand2','heart','icon','iron_cross','left_ptr','left_side','left_tee','leftbutton','ll_angle','lr_angle','man','middlebutton','mouse','no','pencil','pirate','plus','question_arrow','right_ptr','right_side','right_tee','rightbutton','rtl_logo','sailboat','sb_down_arrow','sb_h_double_arrow','sb_left_arrow','sb_right_arrow','sb_up_arrow','sb_v_double_arrow','shuttle','sizing','spider','spraycan','star','target','tcross','top_left_arrow','top_left_corner','top_right_corner','top_side','top_tee','trek','ul_angle','umbrella','ur_angle','watch','xterm','arrow','center_ptr','crosshair','fleur','ibeam','icon','sb_h_double_arrow','sb_v_double_arrow','watch','xterm','no','starting','size','size_ne_sw','size_ns','size_nw_se','size_we','uparrow','wait','arrow','cross','crosshair','ibeam','plus','watch','xterm')
sg.theme('Light Blue 2')

View file

@ -274,7 +274,7 @@ def main(location):
[sg.T(size=(5, 1), font='Any 20', justification='c', background_color='black', k='-gauge VALUE-')]]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True)
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True)
gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(),
minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45,
@ -298,8 +298,6 @@ def main(location):
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close()

View file

@ -23,7 +23,7 @@ def main(location):
layout = [[graph]]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True)
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True)
text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
@ -46,8 +46,6 @@ def main(location):
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
# erase figures so they can be redrawn
graph.delete_figure(rect_id)
graph.delete_figure(text_id1)

View file

@ -1,12 +1,8 @@
import PySimpleGUI as sg
import datetime
import PIL
from PIL import Image
import PIL.Image, PIL.ImageTk
import random
import os
import io
import base64
"""
Another simple Desktop Widget using PySimpleGUI
@ -20,76 +16,17 @@ import base64
* How long to show the image and if you wnt this time to vary semi-randomly
* Folder containing your images
Copyright 2021, 2023 PySimpleGUI
Copyright 2021 PySimpleGUI
"""
ALPHA = 0.9 # Initial alpha until user changes
refresh_font = sg.user_settings_get_entry('-refresh font-', 'Courier 8')
def make_square(im, fill_color=(0, 0, 0, 0)):
x, y = im.size
size = max(x, y)
new_im = Image.new('RGBA', (size, size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def get_image_size(source):
if isinstance(source, str):
image = PIL.Image.open(source)
elif isinstance(source, bytes):
image = PIL.Image.open(io.BytesIO(base64.b64decode(source)))
else:
image = PIL.Image.open(io.BytesIO(source))
width, height = image.size
return (width, height)
def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill=False):
"""
Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
Turns into PNG format in the process so that can be displayed by tkinter
:param source: either a string filename or a bytes base64 image object
:type source: (Union[str, bytes])
:param size: optional new size (width, height)
:type size: (Tuple[int, int] or None)
:param subsample: change the size by multiplying width and height by 1/subsample
:type subsample: (int)
:param zoom: change the size by multiplying width and height by zoom
:type zoom: (int)
:param fill: If True then the image is filled/padded so that the image is square
:type fill: (bool)
:return: (bytes) a byte-string object
:rtype: (bytes)
"""
# print(f'converting {source} {size}')
if isinstance(source, str):
image = PIL.Image.open(source)
elif isinstance(source, bytes):
image = PIL.Image.open(io.BytesIO(base64.b64decode(source)))
else:
image = PIL.Image.open(io.BytesIO(source))
width, height = image.size
scale = None
if size != (None, None):
new_width, new_height = size
scale = min(new_height/height, new_width/width)
elif subsample is not None:
scale = 1/subsample
elif zoom is not None:
scale = zoom
resized_image = image.resize((int(width * scale), int(height * scale)), Image.LANCZOS) if scale is not None else image
if fill and scale is not None:
resized_image = make_square(resized_image)
# encode a PNG formatted version of image into BASE64
with io.BytesIO() as bio:
resized_image.save(bio, format="PNG")
contents = bio.getvalue()
encoded = base64.b64encode(contents)
return encoded
def convert_to_bytes(file_or_bytes, resize=None):
image = PIL.Image.open(file_or_bytes)
image.thumbnail(resize)
photo_img = PIL.ImageTk.PhotoImage(image)
return photo_img
def choose_theme(location):
@ -106,15 +43,6 @@ def choose_theme(location):
else:
return None
def reset_settings():
sg.user_settings_set_entry('-time per image-', 60)
sg.user_settings_set_entry('-random time-', False)
sg.user_settings_set_entry('-image size-', (None, None))
sg.user_settings_set_entry('-image_folder-', None)
sg.user_settings_set_entry('-location-', (None, None))
sg.user_settings_set_entry('-single image-', None)
sg.user_settings_set_entry('-alpha-', ALPHA)
def make_window(location):
alpha = sg.user_settings_get_entry('-alpha-', ALPHA)
@ -133,7 +61,7 @@ def make_window(location):
layout = [[sg.Image(k='-IMAGE-', enable_events=True)],
[sg.pin(sg.Column(refresh_info, key='-REFRESH INFO-', element_justification='c', visible=sg.user_settings_get_entry('-show refresh-', True)))]]
window = sg.Window('Photo Frame', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=alpha, finalize=True, right_click_menu=right_click_menu, keep_on_top=True, enable_close_attempted_event=True, enable_window_config_events=True)
window = sg.Window('Photo Frame', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=alpha, finalize=True, right_click_menu=right_click_menu, keep_on_top=True, enable_close_attempted_event=True)
return window
@ -141,10 +69,11 @@ def make_window(location):
def main():
loc = sg.user_settings_get_entry('-location-', (None, None))
sg.theme(sg.user_settings_get_entry('-theme-', None))
window = make_window(loc)
time_per_image = sg.user_settings_get_entry('-time per image-', 60)
vary_randomly = sg.user_settings_get_entry('-random time-', False)
width, height = sg.user_settings_get_entry('-image size-', (None, None))
width, height = sg.user_settings_get_entry('-image size-', (400,300))
image_folder = sg.user_settings_get_entry('-image_folder-', None)
try:
@ -153,26 +82,36 @@ def main():
image_folder = None
sg.user_settings_set_entry('-image_folder-', None)
image_name = single_image = sg.user_settings_get_entry('-single image-', None)
single_image = sg.user_settings_get_entry('-single image-', None)
if image_folder is None and single_image is None:
image_name = single_image = sg.popup_get_file('Choose a starting image', keep_on_top=True)
if not single_image:
while True:
images = None
image_folder = sg.popup_get_folder('Choose location of your images', location=window.current_location(), keep_on_top=True)
if image_folder is not None:
sg.user_settings_set_entry('-image_folder-', image_folder)
break
else:
if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes':
exit()
if image_folder is not None and single_image is None:
elif single_image is None:
images = os.listdir(image_folder)
images = [i for i in images if i.lower().endswith(('.png', '.jpg', '.gif'))]
image_name = os.path.join(image_folder, random.choice(images))
else: # means single image is not none
images = None
image_name = single_image
window = make_window(loc)
window_size = window.size
image_data = convert_to_bytes(image_name, (width, height))
while True: # Event Loop
# First update the status information
# for debugging show the last update date time
if single_image is None:
image_name =random.choice(images)
image_data = convert_to_bytes(os.path.join(image_folder, image_name), (width, height))
window['-FOLDER-'].update(image_folder)
else:
image_name = single_image
image_data = convert_to_bytes(single_image, (width, height))
window['-FILENAME-'].update(image_name)
window['-IMAGE-'].update(data=image_data)
window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p"))
# -------------- Start of normal event loop --------------
timeout = time_per_image * 1000 + (random.randint(int(-time_per_image * 500), int(time_per_image * 500)) if vary_randomly else 0) if single_image is None else None
event, values = window.read(timeout=timeout)
@ -181,28 +120,6 @@ def main():
elif event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break
# First update the status information
# for debugging show the last update date time
if event == sg.TIMEOUT_EVENT:
if single_image is None:
image_name =random.choice(images)
image_data = convert_to_bytes(os.path.join(image_folder, image_name))
window['-FOLDER-'].update(image_folder)
else:
image_name = single_image
image_data = convert_to_bytes(single_image, (width, height))
window['-FILENAME-'].update(image_name)
window['-IMAGE-'].update(data=image_data)
window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p"))
if event == sg.WINDOW_CONFIG_EVENT:
new_size = window.size
if new_size != window_size:
print(f'resizing {new_size}')
(width, height) = new_size
image_data = convert_to_bytes(image_data, (width, height))
window['-IMAGE-'].update(data=image_data)
window.size = get_image_size(image_data)
window_size = window.size
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Choose Image Folder':
@ -258,15 +175,12 @@ def main():
window.close()
window = make_window(loc)
elif event == 'Choose Single Image':
image_name = single_image = sg.popup_get_file('Choose single image to show', history=True)
single_image = sg.popup_get_file('Choose single image to show', history=True)
sg.user_settings_set_entry('-single image-', single_image)
(width, height) = get_image_size(single_image)
sg.user_settings_set_entry('-image size-', (width, height))
image_data = convert_to_bytes(image_name, (width, height))
window['-IMAGE-'].update(data=image_data)
window.size = window_size = (width, height)
window.close()
if __name__ == '__main__':
# reset_settings() # if get corrupted problems, uncomment this
main()

View file

@ -275,7 +275,7 @@ def main(location):
[sg.T(size=(8, 1), font='Any 14', justification='c', background_color='black', k='-RAM USED-')],
]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True)
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(),
minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45,
@ -290,7 +290,7 @@ def main(location):
if gauge.change():
new_angle = ram_percent*180/100
window['-gauge VALUE-'].update(f'{ram_percent}%')
window['-gauge VALUE-'].update(f'{ram_percent}')
window['-RAM USED-'].update(f'{human_size(ram.used)}')
gauge.change(degree=new_angle, step=180)
gauge.change()
@ -298,13 +298,10 @@ def main(location):
# update the window, wait for a while, then check for exit
event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS)
if event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close()
@ -314,5 +311,5 @@ if __name__ == '__main__':
location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1]))
else:
location = sg.user_settings_get_entry('-location-', (None, None))
location = (None, None)
main(location)

View file

@ -30,7 +30,7 @@ def main(location):
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True)
layout = [[graph]]
window = sg.Window('RAM Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True, keep_on_top=True)
window = sg.Window('RAM Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True)
while True: # Event Loop
@ -47,10 +47,8 @@ def main(location):
if event != sg.WIN_CLOSED:
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break
if event == 'Edit Me':
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
graph.delete_figure(rect_id)
graph.delete_figure(text_id1)

View file

@ -1,74 +0,0 @@
#!/usr/bin/env python
import PySimpleGUI as sg
import time
"""
Demo Program - Timer Desktop Widget using Window.timer_start and Window.timer_stop
This is a re-implementation of the original timer desktop widget that used window.read timeouts as
the means of getting timer events.
This program uses the new Window.timer_start to get timer events. It is simpler because:
There is only 1 call to window.read and it's in the standard location in the event loop
The timer pause/run button uses the timer_start and timer_stop calls - perhaps more intuitive
Note that this Demo Program requires PySimpleGUI 4.60.4.132 and greater
Copyright 2022 PySimpleGUI
"""
def time_as_int():
return int(round(time.time() * 100))
# ---------------- Create Form ----------------
sg.theme('Black')
layout = [[sg.Text('')],
[sg.Text('', size=(8, 2), font=('Helvetica', 20),
justification='center', key='text')],
[sg.Button('Pause', key='-RUN-PAUSE-', 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', layout,
no_titlebar=True,
auto_size_buttons=False,
keep_on_top=True,
grab_anywhere=True,
element_padding=(0, 0),
finalize=True,
element_justification='c',
right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
current_time, paused_time, paused = 0, 0, False
start_time = time_as_int()
timer_id = window.timer_start(10)
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'): # ALWAYS give a way out of program
break
# --------- Handle events --------
if event == '-RUN-PAUSE-':
paused = not paused
if paused:
window.timer_stop(timer_id)
paused_time = time_as_int()
else:
timer_id = window.timer_start(10)
start_time = start_time + time_as_int() - paused_time
window['-RUN-PAUSE-'].update('Run' if paused else 'Pause')
elif event == sg.EVENT_TIMER:
current_time = time_as_int() - start_time
if event == '-RESET-':
current_time = 0
start_time = paused_time = time_as_int()
elif event == 'Edit Me':
sg.execute_editor(__file__)
# --------- Display timer_id in window --------
window['text'].update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60,
(current_time // 100) % 60,
current_time % 100))
window.close()

View file

@ -75,9 +75,8 @@ def change_settings(settings, window_location=(None, None)):
nearest_postal = ''
layout = [[sg.T('Enter Zipcode or City for your location')],
[sg.I(settings.get('-location-', nearest_postal), size=(15, 1), key='-LOCATION-'), sg.T('City')],
[sg.I(settings.get('-country-', 'US'), size=(15, 1), key='-COUNTRY-'), sg.T('Country')],
[sg.I(settings.get('-friends name-', ''), size=(15, 1), key='-FRIENDS NAME-'), sg.T('Who')],
[sg.I(settings.get('-location-', nearest_postal), size=(15, 1), key='-LOCATION-')],
[sg.I(settings.get('-country-', 'US'), size=(15, 1), key='-COUNTRY-')],
[sg.I(settings.get('-api key-', ''), size=(32, 1), key='-API KEY-')],
[sg.CBox('Use Metric For Temperatures', default=settings.get('-celsius-', False),key='-CELSIUS-')],
[sg.B('Ok', border_width=0, bind_return_key=True), sg.B('Register For a Key', border_width=0, k='-REGISTER-'), sg.B('Cancel', border_width=0)], ]
@ -97,7 +96,6 @@ def change_settings(settings, window_location=(None, None)):
settings['-country-'] = values['-COUNTRY-']
API_KEY = settings['-api key-'] = values['-API KEY-']
settings['-celsius-'] = values['-CELSIUS-']
settings['-friends name-'] = values['-FRIENDS NAME-']
else:
API_KEY = settings['-api key-']
user_location = settings['-location-']
@ -188,19 +186,20 @@ def metric_row(metric):
sg.Text(APP_DATA[metric], font=('Arial', 10, 'bold'), pad=(0, 0), size=(9, 1), key=metric)]
def create_window(win_location, settings):
def create_window(win_location):
""" Create the application window """
friends_name = settings.get('-friends name-', '')
col1 = sg.Column(
[[sg.Text(APP_DATA['City'], font=('Arial Rounded MT Bold', 18), background_color=BG_COLOR, text_color=TXT_COLOR, key='City'),
sg.Text(f' - {friends_name}' if friends_name else '', background_color=BG_COLOR, text_color=TXT_COLOR, font=('Arial Rounded MT Bold', 18),)],
[[sg.Text(APP_DATA['City'], font=('Arial Rounded MT Bold', 18), pad=((10, 0), (50, 0)), size=(18, 1), background_color=BG_COLOR, text_color=TXT_COLOR, key='City')],
[sg.Text(APP_DATA['Description'], font=('Arial', 12), pad=(10, 0), background_color=BG_COLOR, text_color=TXT_COLOR, key='Description')]],
background_color=BG_COLOR, key='COL1')
col2 = sg.Column([[sg.Image(data=APP_DATA['Icon'], size=(100, 100), background_color=BG_COLOR, key='Icon')]],
col2 = sg.Column(
[[sg.Text('×', font=('Arial Black', 16), pad=(0, 0), justification='right', background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-QUIT-')],
[sg.Image(data=APP_DATA['Icon'], pad=((5, 10), (0, 0)), size=(100, 100), background_color=BG_COLOR, key='Icon')]],
element_justification='center', background_color=BG_COLOR, key='COL2')
col3 = sg.Column([[sg.Text(APP_DATA['Updated'], font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, key='Updated')]],
col3 = sg.Column(
[[sg.Text(APP_DATA['Updated'], font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, key='Updated')]],
pad=(10, 5), element_justification='left', background_color=BG_COLOR, key='COL3')
col4 = sg.Column(
@ -208,22 +207,22 @@ def create_window(win_location, settings):
sg.Text('Refresh', font=('Arial', 8, 'italic'), background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-REFRESH-')]],
pad=(10, 5), element_justification='right', background_color=BG_COLOR, key='COL4')
top_col = sg.Column([[col1, sg.Push(background_color=BG_COLOR), col2, sg.Text('×', font=('Arial Black', 16), pad=(0, 0), justification='right', background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-QUIT-')]], pad=(0, 0), background_color=BG_COLOR, key='TopCOL')
top_col = sg.Column([[col1, col2]], pad=(0, 0), background_color=BG_COLOR, key='TopCOL')
bot_col = sg.Column([[col3, col4]],
pad=(0, 0), background_color=BG_COLOR, key='BotCOL')
bot_col = sg.Column([[col3, col4]], pad=(0, 0), background_color=BG_COLOR, key='BotCOL')
lf_col = sg.Column(
[[sg.Text(APP_DATA['Temp'], font=('Haettenschweiler', 90), pad=((10, 0), (0, 0)), justification='center', key='Temp')]],
pad=(10, 0), element_justification='center', key='LfCOL')
rt_col = sg.Column([metric_row('Feels Like'), metric_row('Wind'), metric_row('Humidity'), metric_row('Precip 1hr'), metric_row('Pressure')],
rt_col = sg.Column(
[metric_row('Feels Like'), metric_row('Wind'), metric_row('Humidity'), metric_row('Precip 1hr'), metric_row('Pressure')],
pad=((15, 0), (25, 5)), key='RtCOL')
layout = [[top_col],
[lf_col, rt_col],
[bot_col],
[sg.Text(f'PSG: {sg.ver} Tk:{sg.framework_version} Py:{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}', font=('Arial', 8), justification='c', background_color=BG_COLOR, text_color=TXT_COLOR, pad=(0,0), expand_x=True)]]
[sg.Text(f'{sg.ver} {sg.framework_version} {sys.version}', font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, pad=(0,0))]]
window = sg.Window(layout=layout, title='Weather Widget', margins=(0, 0), finalize=True, location=win_location,
element_justification='center', keep_on_top=True, no_titlebar=True, grab_anywhere=True, alpha_channel=ALPHA,
@ -278,20 +277,16 @@ def main(refresh_rate, win_location):
sg.popup_error('Having trouble with location. Your location: ', location)
exit()
window = create_window(win_location, settings)
window = create_window(win_location)
while True: # Event Loop
event, values = window.read(timeout=refresh_in_milliseconds)
if event in (None, '-QUIT-', 'Exit', sg.WIN_CLOSE_ATTEMPTED_EVENT):
sg.user_settings_set_entry('-win location-', window.current_location()) # The line of code to save the position before exiting
break
try:
if event == '-CHANGE-':
x, y = window.current_location()
settings = change_settings(settings, (x + 200, y+50))
window.close()
window = create_window(win_location, settings)
elif event == '-REFRESH-':
sg.popup_quick_message('Refreshing...', keep_on_top=True, background_color='red', text_color='white',
auto_close_duration=3, non_blocking=False, location=(window.current_location()[0]+window.size[0]//2-30, window.current_location()[1]+window.size[1]//2-10))
@ -304,10 +299,6 @@ def main(refresh_rate, win_location):
update_weather()
update_metrics(window)
except Exception as e:
sg.Print('*** GOT Exception in event loop ***', c='white on red', location=window.current_location(), keep_on_top=True)
sg.Print('File = ', __file__, f'Window title: {window.Title}')
sg.Print('Exception = ', e, wait=True) # IMPORTANT to add a wait/blocking so that the print pauses execution. Otherwise program continue and exits
window.close()

View file

@ -12,7 +12,6 @@
* If-Else
* Dictionaries
* Functions as keys
* Lambda as key (callable like functions are)
The handlers in this demo are all functions that are called once the event is detected
@ -23,7 +22,7 @@
event loop rather than functions, then do it in the event loop.
http://www.PySimpleGUI.org
Copyright 2021, 2022, 2023 PySimpleGUI
Copyright 2021 PySimpleGUI
"""
import PySimpleGUI as sg
@ -77,7 +76,7 @@ def main():
[sg.Text('Status:'), sg.Text(size=(3, 1), key='-STATUS-')],
[sg.Text(size=(50, 1), key='-OUT-')],
[sg.Button('Simple'), sg.Button('Go'), sg.Button('Stop'), sg.Button('Other', key=do_other),
sg.Button('Tuple', key=(1,2)), sg.Button('Lambda', key= lambda window: do_other(window)), sg.Button('Bad')]]
sg.Button('Tuple', key=(1,2)), sg.Button('Bad')]]
window = sg.Window('Dispatchers', layout, font='Default 16', keep_on_top=True)

View file

@ -1,7 +1,7 @@
import PySimpleGUI as sg
"""
Demo "Edit Me" (and Version)
Demo "Edit Me"
More and more of these Demos are getting an "Edit me" option added.
@ -12,18 +12,20 @@ import PySimpleGUI as sg
You can add this capability to your program by adding a right click menu to your window and calling the
editor that you set up in the global PySimpleGUI options.
A constant MENU_RIGHT_CLICK_EDITME_VER_EXIT, when set at the right click menu shows a "Version" and "Edit Me" meny item.
You need to do 2 things to make this work:
1. Add a right click menu - requires you to add 1 parameter to your Window creation
2. Add 1 if statement to your event loop.
You will need to have first set up your editor by using the menu in sg.main()
Copyright 2021, 2022, 2023 PySimpleGUI.org
Copyright 2021 PySimpleGUI.org
"""
layout = [[sg.Text('Edit this program by right clicking and choosing "Edit me"')],
[sg.Button('Exit')]]
window = sg.Window('Edit Me Right Click Menu Demo', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window = sg.Window('Edit Me Right Click Menu Demo', layout, right_click_menu=[[''], ['Edit Me', 'Exit',]])
while True: # Event Loop
event, values = window.read()
@ -31,7 +33,5 @@ while True: # Event Loop
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close()

View file

@ -1,36 +1,38 @@
import PySimpleGUI as sg
# import PySimpleGUIWeb as sg
# import PySimpleGUIWx as sg
# import PySimpleGUIQt as sg
'''
Learn how to send emails from PySimpleGUI using the smtplib and email modules
The GUI portion is simple
Copyright 2019 PySimpleGUI.org
Based on a send-email script originally written by by Israel Dryer
(Thank you Israel for figuring out the hard part of the stmp and email module calls!)
Copyright 2019, 2022 PySimpleGUI
'''
# If you are using a mail service that's not gmail, hotmail, live or yahoo:
# then you can enter the smtp server address here so you don't have to keep typing it into the GUI
smtp_host_default = ''
# used for sending the email
import smtplib as smtp
# used to build the email
from email.message import EmailMessage
# create and send email
def send_an_email(from_address, to_address, subject, message_text, user, password, smtp_host, smtp_port):
def send_an_email(from_address, to_address, subject, message_text, user, password):
# SMTP Servers for popular free services... add your own if needed. Format is: address, port
google_smtp_server = 'smtp.gmail.com', 587
microsoft_smtp_server = 'smtp.office365.com', 587
yahoo_smtp_server = 'smtp.mail.yahoo.com', 587 # or port 465
# open the email server connection
if 'gmail' in user:
smtp_host, smtp_port = google_smtp_server
elif 'hotmail' in user or 'live' in user:
smtp_host, smtp_port = microsoft_smtp_server
elif 'yahoo' in user:
smtp_host, smtp_port = yahoo_smtp_server
else:
sg.popup('Username does not contain a supported email provider')
return
server = smtp.SMTP(host=smtp_host, port=smtp_port)
server.starttls()
try:
server.login(user=user, password=password)
except Exception as e:
sg.popup_error('Error authenticaing your email credentials', e, image=sg.EMOJI_BASE64_WEARY)
server.close()
return
# create the email message headers and set the payload
msg = EmailMessage()
@ -40,15 +42,9 @@ def send_an_email(from_address, to_address, subject, message_text, user, passwor
msg.set_payload(message_text)
# open the email server and send the message
try:
server.send_message(msg)
except Exception as e:
sg.popup_error('Error sending your email', e, image=sg.EMOJI_BASE64_WEARY)
server.close()
return
server.close()
sg.popup('Email sent successfully!', image=sg.EMOJI_BASE64_HAPPY_JOY)
'''
important notes about using gmail
@ -65,47 +61,33 @@ def send_an_email(from_address, to_address, subject, message_text, user, passwor
'''
def main():
smtp_server_dict = {'gmail.com':'smtp.gmail.com','hotmail.com':'smtp.office365.com', 'live.com': 'smtp.office365.com', 'yahoo.com':'smtp.mail.yahoo.com'}
sg.theme('Dark Blue 3')
layout = [[sg.Text('Send an Email', font='Default 18')],
[sg.T('From:', size=(8,1)), sg.Input(key='-EMAIL FROM-', size=(35,1))],
[sg.T('To:', size=(8,1)), sg.Input(key='-EMAIL TO-', size=(35,1))],
[sg.T('Subject:', size=(8,1)), sg.Input(key='-EMAIL SUBJECT-', size=(35,1))],
[sg.T('Mail login information', font='Default 18')],
[sg.T('User:', size=(8,1)), sg.Input(key='-USER-', size=(35,1), enable_events=True)],
[sg.T('User:', size=(8,1)), sg.Input(key='-USER-', size=(35,1))],
[sg.T('Password:', size=(8,1)), sg.Input(password_char='*', key='-PASSWORD-', size=(35,1))],
[sg.T('SMTP Server Info', font='_ 14')],
[sg.T('SMTP Hostname'), sg.Input(smtp_host_default, s=20, key='-SMTP HOST-'), sg.T('SMTP Port'), sg.In(587, s=4, key='-SMTP PORT-') ],
[sg.Multiline('Type your message here', size=(60,10), key='-EMAIL TEXT-')],
[sg.Button('Send'), sg.Button('Exit')]]
window = sg.Window('Send An Email', layout)
while True:
while True: # Event Loop
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
if event == 'Send':
if values['-SMTP HOST-']:
if sg.__name__ != 'PySimpleGUIWeb': # auto close popups not yet supported in PySimpleGUIWeb
sg.popup_quick_message('Sending your message... this will take a moment...', background_color='red')
send_an_email(from_address=values['-EMAIL FROM-'],
to_address=values['-EMAIL TO-'],
subject=values['-EMAIL SUBJECT-'],
message_text=values['-EMAIL TEXT-'],
user=values['-USER-'],
password=values['-PASSWORD-'],
smtp_host=values['-SMTP HOST-'],
smtp_port = values['-SMTP PORT-'])
else:
sg.popup_error('Missing SMTP Hostname... you have to supply a hostname (gmail, hotmail, live, yahoo are autofilled)')
elif event == '-USER-': # as the email sender is typed in, try to fill in the smtp hostname automatically
for service in smtp_server_dict.keys():
if service in values[event].lower():
window['-SMTP HOST-'].update(smtp_server_dict[service])
break
password=values['-PASSWORD-'])
window.close()
if __name__ == '__main__':
main()

File diff suppressed because one or more lines are too long

View file

@ -1,60 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Navigating a window's focus using arrow keys
This Demo Program has 2 features of PySimpleGUI in use:
1. Binding the arrow keys
2. Navigating a window's elements using focus
The first step is to bind the left, right and down arrows to an event.
The call to window.bind will cause events to be generated when these keys are pressed
The next step is to add the focus navigation to your event loop.
When the right key is pressed, the focus moves to the element that should get focus next
When the left arrow key is pressed, the focus moves to the previous element
And when the down arrow is pressed the program exits
Copyright 2022 PySimpleGUI
"""
def main():
layout = [ [sg.Text('My Window')],
[sg.Input(key='-IN-')],
[sg.Input(key='-IN2-')],
[sg.Input(key='-IN3-')],
[sg.Input(key='-IN4-')],
[sg.Input(key='-IN5-')],
[sg.Input(key='-IN6-')],
[sg.Input(key='-IN7-')],
[sg.Button('Go'), sg.Button('Exit')]]
window = sg.Window('Window Title', layout, finalize=True)
# Bind the Left, Right and Down arrow keys to events
window.bind('<Right>', '-NEXT-')
window.bind('<Left>', '-PREV-')
window.bind('<Down>', 'Exit')
while True: # Event Loop
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
# Right arrow pressed, so move to the next element that should get focus
if event == '-NEXT-':
next_element = window.find_element_with_focus().get_next_focus()
next_element.set_focus()
# Left arrow pressed, so move to the previous element that should get focus
if event == '-PREV-':
prev_element = window.find_element_with_focus().get_previous_focus()
prev_element.set_focus()
window.close()
if __name__ == '__main__':
main()

View file

@ -1,6 +1,5 @@
import pyglet
import PySimpleGUI as sg
import os
"""
Demo - Using pyglet to get custom fonts into PySimpleGUI
@ -18,11 +17,8 @@ import os
http://scripts.sil.org/OFL
"""
font_file = os.path.join(os.path.dirname(__file__), "OpenFlame.ttf")
pyglet.font.add_file(r".\OpenFlame.ttf")
pyglet.font.add_file(font_file)
# sg.execute_command_subprocess(font_file)
font1 = ("Open Flame", 40) # Note - use the font "face name" not the filename when specifying the font
font2 = ("Courier New", 40)
font3 = ("Helvetica", 40)

View file

@ -1,47 +0,0 @@
import PySimpleGUI as sg
"""
Demo Frame For Screen Captures
This program can be used to help you record videos.
Because it relies on the "transparent color" feature that's only available on Windows, this Demo is only going
to work the indended way on Windows.
Some video recorders that record a portion of the screen do not show you, at all times, what portion of the screen
is being recorded. This can make it difficult for you to stay within the bounds being recorded.
This demo program is meant to help the situation by showing a thin line that is 20 pixels larger than the area
being recorded.
The top edge of the window has the controls. There's an exit button, a solid "bar" for you to grab with your mouse to move
the frame around your window, and 2 inputs with a "resize" button that enables you to set the frame to the size you want to stay
within.
Copyright 2022 PySimpleGUI.org
"""
def main():
offset = (20, 20) # Number of extra pixels to add to the recording area
default_size = (1920, 1080) # The default size of the recording
location = (None, None) # A specific location to place the window if you want a specific spot
window = sg.Window('Window Title',
[[sg.Button('Exit'), sg.T(sg.SYMBOL_SQUARE * 10, grab=True), sg.I(default_size[0], s=4, k='-W-'), sg.I(default_size[1], s=4, k='-H-'), sg.B('Resize')],
[sg.Frame('', [[]], s=(default_size[0] + offset[0], default_size[1] + offset[1]), k='-FRAME-')]], transparent_color=sg.theme_background_color(),
right_click_menu=['', ['Edit Me', 'Exit']], location=location, no_titlebar=True, keep_on_top=True)
while True: # Event Loop
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Resize':
window['-FRAME-'].set_size((int(values['-W-']) + offset[0], int(values['-H-']) + offset[1]))
window.close()
if __name__ == '__main__':
main()

View file

@ -1,44 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Drag a rectangle and move
This demo shows how to use a Graph Element to draw a square and move it with the mouse.
It's a very simple, single element program. Like many Demo Programs, it started as
a "Test Harness" that demonstrated a bug that happened with a timeout of 0
was added to the window.read()
Original code comes courtesy of user @davesmivers .... Thanks Dave!!
Copyright 2022 PySimpleGUI
"""
GRAPH_SIZE = (400, 400)
START = (200, 200) # We'll assume X and Y are both this value
SQ_SIZE = 40 # Both width and height will be this value
layout = [[sg.Graph(
canvas_size=GRAPH_SIZE, graph_bottom_left=(0, 0), graph_top_right=GRAPH_SIZE, # Define the graph area
change_submits=True, # mouse click events
drag_submits=True, # mouse move events
background_color='lightblue',
key="-GRAPH-",
pad=0)]]
window = sg.Window("Simple Square Movement", layout, finalize=True, margins=(0,0))
# draw the square we'll move around
square = window["-GRAPH-"].draw_rectangle(START, (START[0]+SQ_SIZE, START[1]+SQ_SIZE), fill_color='black')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
print(event, values) if event != sg.TIMEOUT_EVENT else None # our normal debug print, but for this demo, don't spam output with timeouts
if event == "-GRAPH-": # if there's a "Graph" event, then it's a mouse movement. Move the square
x, y = values["-GRAPH-"] # get mouse position
window["-GRAPH-"].relocate_figure(square, x - SQ_SIZE // 2, y + SQ_SIZE // 2) # Move using center of square to mouse pos
window.close()

View file

@ -1,4 +1,5 @@
import PySimpleGUI as sg
from PIL import ImageGrab
"""
Demo - Drawing and moving demo
@ -6,9 +7,22 @@ import PySimpleGUI as sg
This demo shows how to use a Graph Element to (optionally) display an image and then use the
mouse to "drag" and draw rectangles and circles.
Copyright 2020, 2021, 2022, 2023 PySimpleGUI.org
Copyright 2020 PySimpleGUI.org
"""
def save_element_as_file(element, filename):
"""
Saves any element as an image file. Element needs to have an underlyiong Widget available (almost if not all of them do)
:param element: The element to save
:param filename: The filename to save to. The extension of the filename determines the format (jpg, png, gif, ?)
"""
widget = element.Widget
box = (widget.winfo_rootx(), widget.winfo_rooty(), widget.winfo_rootx() + widget.winfo_width(), widget.winfo_rooty() + widget.winfo_height())
grab = ImageGrab.grab(bbox=box)
grab.save(filename)
def main():
sg.theme('Dark Blue 3')
@ -24,6 +38,7 @@ def main():
[sg.R('Bring to front', 1, key='-FRONT-', enable_events=True)],
[sg.R('Move Everything', 1, key='-MOVEALL-', enable_events=True)],
[sg.R('Move Stuff', 1, key='-MOVE-', enable_events=True)],
[sg.B('Save Image', key='-SAVE-')],
]
layout = [[sg.Graph(
@ -34,8 +49,7 @@ def main():
enable_events=True,
background_color='lightblue',
drag_submits=True,
motion_events=True,
right_click_menu=[[''],['Erase item','Send to back']]
right_click_menu=[[],['Erase item',]]
), sg.Col(col, key='-COL-') ],
[sg.Text(key='-INFO-', size=(60, 1))]]
@ -44,9 +58,11 @@ def main():
# get the graph element for ease of use later
graph = window["-GRAPH-"] # type: sg.Graph
graph.draw_image(data=logo200, location=(0,400))
dragging = False
start_point = end_point = prior_rect = None
crosshair_lines = []
# graph.bind('<Button-3>', '+RIGHT+')
while True:
event, values = window.read()
print(event, values)
@ -57,14 +73,7 @@ def main():
graph.set_cursor(cursor='fleur') # not yet released method... coming soon!
elif not event.startswith('-GRAPH-'):
graph.set_cursor(cursor='left_ptr') # not yet released method... coming soon!
if event.endswith('+MOVE'):
window["-INFO-"].update(value=f"mouse {values['-GRAPH-']}")
# Delete crosshairs if any exists
if len(crosshair_lines):
for fig in crosshair_lines:
graph.delete_figure(fig)
crosshair_lines = []
window.refresh()
if event == "-GRAPH-": # if there's a "Graph" event, then it's a mouse
x, y = values["-GRAPH-"]
if not dragging:
@ -110,23 +119,20 @@ def main():
start_point, end_point = None, None # enable grabbing a new rect
dragging = False
prior_rect = None
# elif event.endswith('+RIGHT+'): # Right click
# window["-INFO-"].update(value=f"Right clicked location {values['-GRAPH-']}")
# elif event.endswith('+MOTION+'): # Right click
# window["-INFO-"].update(value=f"mouse freely moving {values['-GRAPH-']}")
elif event == 'Send to back': # Right clicked menu item
figures = graph.get_figures_at_location(values["-GRAPH-"]) # get items in front-to-back order
if figures: # make sure at least 1 item found
graph.send_figure_to_back(figures[-1]) # get the last item which will be the top-most
elif event.endswith('+RIGHT+'): # Righ click
window["-INFO-"].update(value=f"Right clicked location {values['-GRAPH-']}")
elif event.endswith('+MOTION+'): # Righ click
window["-INFO-"].update(value=f"mouse freely moving {values['-GRAPH-']}")
elif event == '-SAVE-':
# filename = sg.popup_get_file('Choose file (PNG, JPG, GIF) to save to', save_as=True)
filename=r'test.jpg'
save_element_as_file(window['-GRAPH-'], filename)
elif event == 'Erase item':
window["-INFO-"].update(value=f"Right click erase at {values['-GRAPH-']}")
if values['-GRAPH-'] != (None, None):
figures = graph.get_figures_at_location(values['-GRAPH-'])
if figures:
graph.delete_figure(figures[-1]) # delete the one on top
location = values['-GRAPH-']
crosshair_lines = [graph.draw_line((location[0], 0), (location[0], 800), color='red'),
graph.draw_line((0, location[1]), (800, location[1]), color='red')]
drag_figures = graph.get_figures_at_location(values['-GRAPH-'])
for figure in drag_figures:
graph.delete_figure(figure)
window.close()

File diff suppressed because one or more lines are too long

View file

@ -44,7 +44,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize:
new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS)
bio = io.BytesIO()
img.save(bio, format="PNG")
del img

View file

@ -1,30 +1,11 @@
import PySimpleGUI as sg
import math
"""
Demo - Graph Element used to plot a mathematical formula
The Graph element has a flexible coordinate system that you define.
Thie makes is possible for you to work in your coordinates instead of an
arbitrary system.
For example, in a typical mathematics graph, (0,0) is located at the center
of the graph / page / diagram.
This Demo Program shows a graph with (0,0) being at the center of the Graph
area rather than at one of the corners.
It graphs the formula:
y = sine(x/x2) * x1
The values of x1 and x2 can be changed using 2 sliders
Copyright 2018, 2019, 2020, 2021, 2022 PySimpleGUI
"""
# Yet another usage of Graph element.
SIZE_X = 200
SIZE_Y = 200
NUMBER_MARKER_FREQUENCY = SIZE_X//8 # How often to put tick marks on the axis
SIZE_Y = 100
NUMBER_MARKER_FREQUENCY = 25
def draw_axis():
@ -32,43 +13,42 @@ def draw_axis():
graph.draw_line((0, -SIZE_Y), (0, SIZE_Y))
for x in range(-SIZE_X, SIZE_X+1, NUMBER_MARKER_FREQUENCY):
graph.draw_line((x, -SIZE_Y/66), (x, SIZE_Y/66)) # tick marks
graph.draw_line((x, -3), (x, 3)) # tick marks
if x != 0:
# numeric labels
graph.draw_text(str(x), (x, -SIZE_Y/15), color='green', font='courier 10')
graph.draw_text(str(x), (x, -10), color='green')
for y in range(-SIZE_Y, SIZE_Y+1, NUMBER_MARKER_FREQUENCY):
graph.draw_line((-SIZE_X/66, y), (SIZE_X/66, y))
graph.draw_line((-3, y), (3, y))
if y != 0:
graph.draw_text(str(y), (-SIZE_X/11, y), color='blue', font='courier 10')
graph.draw_text(str(y), (-10, y), color='blue')
# Create the graph that will be put into the window. Making outside of layout so have element in a variable
graph = sg.Graph(canvas_size=(500, 500),
sg.theme('DarkAmber')
# Create the graph that will be put into the window
graph = sg.Graph(canvas_size=(400, 400),
graph_bottom_left=(-(SIZE_X+5), -(SIZE_Y+5)),
graph_top_right=(SIZE_X+5, SIZE_Y+5),
background_color='white', expand_x=True, expand_y=True,
key='-GRAPH-')
background_color='white',
key='graph')
# Window layout
layout = [[sg.Text('Graph Element Combined with Math!', justification='center', relief=sg.RELIEF_SUNKEN, expand_x=True, font='Courier 18')],
layout = [[sg.Text('Example of Using Math with a Graph', justification='center', size=(50, 1), relief=sg.RELIEF_SUNKEN)],
[graph],
[sg.Text('y = sin(x / x2) * x1', font='COURIER 18')],
[sg.Text('x1', font='Courier 14'), sg.Slider((0, SIZE_Y), orientation='h', enable_events=True, key='-SLIDER-', expand_x=True)],
[sg.Text('x2', font='Courier 14'), sg.Slider((1, SIZE_Y), orientation='h', enable_events=True, key='-SLIDER2-', expand_x=True)]]
[sg.Text('y = sin(x / x2 * x1)', font='COURIER 18')],
[sg.Text('x1'), sg.Slider((0, 200), orientation='h',
enable_events=True, key='-SLIDER-')],
[sg.Text('x2'), sg.Slider((1, 200), orientation='h', enable_events=True, key='-SLIDER2-')]]
window = sg.Window('Graph of Sine Function', layout, finalize=True)
draw_axis() # draw the axis (an empty graph)
window = sg.Window('Graph of Sine Function', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
graph.erase() # erase entire graph every time there's a change to a slider
draw_axis() # redraw the axis
# plot the function by drawing short line segments
graph.erase()
draw_axis()
prev_x = prev_y = None
for x in range(-SIZE_X, SIZE_X):
y = math.sin(x/int(values['-SLIDER2-']))*int(values['-SLIDER-'])
if prev_x is not None:

View file

@ -1,45 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Graph Element Rescale Figures When Window Resizes
This demo shows how you can redraw your Graph element's figures so that when
you resize the window, all of the figures on the graph resize.
There may be a tkinter method to help do this?
Copyright 2022 PySimpleGUI
"""
gsize = (400,400)
layout = [ [sg.Text('Rescaling a Graph Element When Window is Resized')],
[sg.Graph(gsize, (0,0),gsize, expand_x=True, expand_y=True, k='-G-', background_color='green')],
[sg.Button('Exit'), sg.Sizegrip()] ]
window = sg.Window('Graph Element Scale With Window', layout, finalize=True, resizable=True, enable_window_config_events=True)
graph = window['-G-'] #type: sg.Graph
orig_win_size = window.current_size_accurate()
# Draw the figure desired (will repeat this code later)
fig = window['-G-'].draw_circle((200, 200), 50, fill_color='blue')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == sg.WINDOW_CONFIG_EVENT: # if get a window resized event
# Determine how much the window was resized by and tell the Graph element the new size for the Canvas
new_size = window.current_size_accurate()
dx = orig_win_size[0]-new_size[0]
dy = orig_win_size[1]-new_size[1]
gsize = (gsize[0] - dx, gsize[1] - dy)
orig_win_size = new_size
graph.CanvasSize = gsize
# Erase entire Graph and redraw all figures0
graph.erase()
# Redraw your figures here
fig = window['-G-'].draw_circle((200, 200), 50, fill_color='blue')
window.close()

View file

@ -45,7 +45,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize:
new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS)
with io.BytesIO() as bio:
img.save(bio, format="PNG")
del img

View file

@ -1,32 +0,0 @@
import PySimpleGUI as sg
import urllib.request
"""
Display an Image Located at a URL
Downloads and displays a PNG (or GIF) image given a URL
NOTE:
Early versions of tkinter (for example 8.6.6 found in Python 3.6) have trouble with some PNG formats.
Moving to Python 3.7 fixes this or you can use a tool to re-encode the image (e.g. psgresizer) save it and
it will then work OK in Python 3.6.
Example of one of these images - https://www.python.org/static/community_logos/python-logo-master-v3-TM.png
Copyright 2022 PySimpleGUI.org
"""
image_URL = r'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'
layout = [[sg.Image(urllib.request.urlopen(image_URL).read())]]
window = sg.Window('Image From URL', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
window.close()

View file

@ -1,5 +1,6 @@
import PySimpleGUI as sg
from PIL import Image
import PIL
import os
import base64
import io
@ -24,19 +25,12 @@ import webbrowser
Copyright 2021 PySimpleGUI
"""
version = '1.6.0'
version = '1.3.1'
__version__ = version.split()[0]
'''
Change log
1.6.0 12-July-2022
Fixed output filename to match the size indicated under the filename.
1.5.4 10-May-2022
Had to mess around with the entry point due to setuptools
1.5.0 10-May-2022
Moved icon to bottom of file and called set_global_icon so all windows in this application (including popups) will use this icon
1.4.0 16-Nov-2021
Explicitly set the settings filename. I'm still learning about these PyPI .EXE releases. Need to be explicit rather than default
1.3.1 16-Nov-2021
Added correct readme to PyPI
1.3.0 16-Nov-2021
@ -55,7 +49,7 @@ def resize(input_file, size, output_file=None, encode_format='PNG'):
new_width, new_height = size
if new_width != width or new_height != height: # if the requested size is different than original size
scale = min(new_height / height, new_width / width)
resized_image = image.resize((int(width * scale), int(height * scale)), Image.LANCZOS)
resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS)
else:
resized_image = image
@ -71,6 +65,7 @@ def resize(input_file, size, output_file=None, encode_format='PNG'):
def main():
image_resize_icon = b'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'
def update_outfilename():
infile = values['-IN-']
@ -81,12 +76,8 @@ def main():
window['-ORIG WIDTH-'].update(image.size[0])
if not values['-WIDTH-']:
window['-WIDTH-'].update(image.size[0])
else:
width = values['-WIDTH-']
if not values['-HEIGHT-']:
window['-HEIGHT-'].update(image.size[1])
else:
height = values['-HEIGHT-']
window['-ORIG HEIGHT-'].update(image.size[1])
infilename = os.path.basename(infile)
@ -97,7 +88,7 @@ def main():
outfileext = 'jpg'
else:
outfileext = infileext[1:] # strip off the .
outfile = f'{infilenameonly}_{width}x{height}.{outfileext}'
outfile = f'{infilenameonly}{width}x{height}.{outfileext}'
outfullfilename = os.path.join(os.path.dirname(infile), outfile)
if values['-DO NOT SAVE-']:
@ -113,9 +104,6 @@ def main():
# window['-HEIGHT-'].update('')
window['-NEW FILENAME-'].update()
sg.user_settings_filename(filename='psgresizer.json')
format_list = ('', 'PNG', 'JPEG', 'BMP', 'ICO', 'GIF', 'TIFF')
new_format_layout = [
[sg.Combo(format_list, default_value=sg.user_settings_get_entry('-new format-', ''), readonly=True, enable_events=True, key='-NEW FORMAT-')]]
@ -124,8 +112,8 @@ def main():
[sg.Frame('Input Filename', [[sg.Input(key='-IN-', enable_events=True, s=80), sg.FileBrowse(), ],
[sg.T('Original size'), sg.T(k='-ORIG WIDTH-'), sg.T('X'), sg.T(k='-ORIG HEIGHT-')]])],
[sg.Frame('Output Filename', [[sg.In(k='-NEW FILENAME-', s=80), sg.FileBrowse(), ],
[sg.In(default_text=sg.user_settings_get_entry('-width-', ''), s=4, k='-WIDTH-', enable_events=True), sg.T('X'),
sg.In(default_text=sg.user_settings_get_entry('-height-', ''), s=4, k='-HEIGHT-', enable_events=True)]])],
[sg.In(default_text=sg.user_settings_get_entry('-width-', ''), s=4, k='-WIDTH-'), sg.T('X'),
sg.In(default_text=sg.user_settings_get_entry('-height-', ''), s=4, k='-HEIGHT-')]])],
[sg.Frame('Convert To New Format', new_format_layout)],
[sg.CBox('Encode to Base64 and leave on Clipboard', k='-BASE64-', default=sg.user_settings_get_entry('-base64-', True))],
# [sg.CBox('Use PNG for all Base64 Encoding', default=True, k='-PNG CONVERT-')],
@ -140,7 +128,7 @@ def main():
sg.T('A PySimpleGUI Application - Go to PySimpleGUI home', font='_ 8', enable_events=True, k='-PYSIMPLEGUI-')],
]
window = sg.Window('Resize Image', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_LOC_EXIT,
window = sg.Window('Resize Image', layout, icon=image_resize_icon, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_LOC_EXIT,
enable_close_attempted_event=True, finalize=True)
window['-PSGRESIZER-'].set_cursor('hand1')
window['-PYSIMPLEGUI-'].set_cursor('hand1')
@ -194,8 +182,6 @@ def main():
webbrowser.open_new_tab(r'http://www.PySimpleGUI.com')
elif event == '-PSGRESIZER-':
webbrowser.open_new_tab(r'https://github.com/PySimpleGUI/psgresizer')
elif event in ('-WIDTH-', '-HEIGHT-'):
update_outfilename()
if event != sg.WIN_CLOSED:
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
@ -207,11 +193,5 @@ def main():
window.close()
def main_entry_point():
image_resize_icon = b'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'
sg.set_global_icon(image_resize_icon)
main()
if __name__ == '__main__':
main_entry_point()
main()

View file

@ -56,7 +56,7 @@ def convert_to_bytes(file_or_bytes, resize=None, fill=False):
if resize:
new_width, new_height = resize
scale = min(new_height / cur_height, new_width / cur_width)
img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS)
img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.ANTIALIAS)
if fill:
img = make_square(img, THUMBNAIL_SIZE[0])
with io.BytesIO() as bio:

View file

@ -1,31 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Save previously entered value in Input element by using user_settings calls
Tired of typing in the same value or entering the same filename into an Input element?
If so, this may be exactly what you need.
It simply saves the last value you entered so that the next time you start your program, that will be the default
Copyright 2022 PySimpleGUI.org
"""
def main():
sg.user_settings_filename(path='.') # The settings file will be in the same folder as this program
layout = [[sg.T('This is your layout')],
[sg.T('Remembers last value for this:'), sg.In(sg.user_settings_get_entry('-input-', ''), k='-INPUT-')],
[sg.OK(), sg.Button('Exit')]]
# make a window, read it, and automatically close after 1 event happens (button or X to close window)
event, values = sg.Window('Save Input Element Last Value', layout).read(close=True)
# only save the value if OK was clicked
if event == 'OK':
sg.user_settings_set_entry('-input-', values['-INPUT-'])
if __name__ == '__main__':
main()

View file

@ -19,12 +19,13 @@ import PySimpleGUI as sg
For other ports of PySimpleGUI such as the Qt port, the position is remembered by Qt and as a
result this technique using "pin" is not needed.
Copyright 2020, 2022 PySimpleGUI.org
Copyright 2020 PySimpleGUI.org
"""
layout = [ [sg.Text('Hide Button or Multiline. Buttons 1 & 2 hide Button 2')],
[sg.pin(sg.Multiline(size=(60, 10), key='-MLINE-'))],
[sg.pin(sg.Button('Button1')), sg.pin(sg.Button('Button2'), shrink=False), sg.B('Toggle Multiline')],
layout = [ [sg.Text('Hide Button or Input. Button3 hides Input. Buttons 1 & 2 hide Button 2')],
[sg.pin(sg.Input(key='-IN-'))],
[sg.pin(sg.Button('Button1')), sg.pin(sg.Button('Button2')), sg.B('Button3')],
]
window = sg.Window('Visible / Invisible Element Demo', layout)
@ -39,6 +40,7 @@ while True: # Event Loop
if event in ('Button1', 'Button2'):
window['Button2'].update(visible=toggle)
toggle = not toggle
elif event == 'Toggle Multiline':
window['-MLINE-'].update(visible=not window['-MLINE-'].visible)
if event == 'Button3':
window['-IN-'].update(visible=toggle_in)
toggle_in = not toggle_in
window.close()

View file

@ -1,65 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Add and "Delete" Rows from a window
This is cut-down version of the Fed-Ex package tracking demo
The purpose is to show a technique for making windows that grow by clicking an "Add Row" button
Each row can be individually "deleted".
The reason for using the quotes are "deleted" is that the elements are simply hidden. The effect is the same as deleting them.
Copyright 2022 PySimpleGUI
"""
def item_row(item_num):
"""
A "Row" in this case is a Button with an "X", an Input element and a Text element showing the current counter
:param item_num: The number to use in the tuple for each element
:type: int
:return: List
"""
row = [sg.pin(sg.Col([[sg.B(sg.SYMBOL_X, border_width=0, button_color=(sg.theme_text_color(), sg.theme_background_color()), k=('-DEL-', item_num), tooltip='Delete this item'),
sg.In(size=(20,1), k=('-DESC-', item_num)),
sg.T(f'Key number {item_num}', k=('-STATUS-', item_num))]], k=('-ROW-', item_num)))]
return row
def make_window():
layout = [ [sg.Text('Add and "Delete" Rows From a Window', font='_ 15')],
[sg.Col([item_row(0)], k='-TRACKING SECTION-')],
[sg.pin(sg.Text(size=(35,1), font='_ 8', k='-REFRESHED-',))],
[sg.T(sg.SYMBOL_X, enable_events=True, k='Exit', tooltip='Exit Application'), sg.T('', enable_events=True, k='Refresh', tooltip='Save Changes & Refresh'), sg.T('+', enable_events=True, k='Add Item', tooltip='Add Another Item')]]
right_click_menu = [[''], ['Add Item', 'Edit Me', 'Version']]
window = sg.Window('Window Title', layout, right_click_menu=right_click_menu, use_default_focus=False, font='_ 15', metadata=0)
return window
def main():
window = make_window()
while True:
event, values = window.read() # wake every hour
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Add Item':
window.metadata += 1
window.extend_layout(window['-TRACKING SECTION-'], [item_row(window.metadata)])
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
elif event[0] == '-DEL-':
window[('-ROW-', event[1])].update(visible=False)
window.close()
if __name__ == '__main__':
main()

View file

@ -1,43 +0,0 @@
import PySimpleGUI as sg
"""
Demo - Listbox Using Objects
Several elements can take not just strings, but objects. The Listsbox is one of them.
This demo show how you can use objects directly in a Listbox in a way that you can access
information about each object that is different than what is shown in the Window.
The important part of this design pattern is the use of the __str__ method in your item objects.
This method is what determines what is shown in the window.
Copyright 2022 PySimpleGUI
"""
class Item():
def __init__(self, internal, shown):
self.internal = internal
self.shown = shown
def __str__(self):
return self.shown
# make list of some objects
my_item_list = [Item(f'Internal {i}', f'shown {i}') for i in range(100)]
layout = [ [sg.Text('Select 1 or more items and click "Go"')],
[sg.Listbox(my_item_list, key='-LB-', s=(20,20), select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED)],
[sg.Output(s=(40,10))],
[sg.Button('Go'), sg.Button('Exit')] ]
window = sg.Window('Listbox Using Objects', layout)
while True:
event, values = window.read()
# print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
elif event == 'Go':
print('You selected:')
for item in values['-LB-']:
print(item.internal)
window.close()

View file

@ -824,26 +824,15 @@ def AxesGrid():
# The magic function that makes it possible.... glues together tkinter and pyplot using Canvas Widget
def draw_figure(canvas, figure):
if not hasattr(draw_figure, 'canvas_packed'):
draw_figure.canvas_packed = {}
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw()
widget = figure_canvas_agg.get_tk_widget()
if widget not in draw_figure.canvas_packed:
draw_figure.canvas_packed[widget] = figure
widget.pack(side='top', fill='both', expand=1)
figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
return figure_canvas_agg
def delete_figure_agg(figure_agg):
figure_agg.get_tk_widget().forget()
try:
draw_figure.canvas_packed.pop(figure_agg.get_tk_widget())
except Exception as e:
print(f'Error removing {figure_agg} from list', e)
plt.close('all')
# -------------------------------- GUI Starts Here -------------------------------#
# fig = your figure you want to display. Assumption is that 'fig' holds the #
# information to display. #
@ -884,9 +873,6 @@ while True:
choice = values['-LISTBOX-'][0] # get first listbox item chosen (returned as a list)
func = fig_dict[choice] # get function to call from the dictionary
window['-MULTILINE-'].update(inspect.getsource(func)) # show source code to function in multiline
try:
fig = func() # call function to get the figure
figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig) # draw the figure
except Exception as e:
print('Exception in fucntion', e)
window.close()

View file

@ -837,23 +837,14 @@ def AxesGrid():
def draw_figure(canvas, figure):
if not hasattr(draw_figure, 'canvas_packed'):
draw_figure.canvas_packed = {}
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw()
widget = figure_canvas_agg.get_tk_widget()
if widget not in draw_figure.canvas_packed:
draw_figure.canvas_packed[widget] = figure
widget.pack(side='top', fill='both', expand=1)
figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
return figure_canvas_agg
def delete_figure_agg(figure_agg):
figure_agg.get_tk_widget().forget()
try:
draw_figure.canvas_packed.pop(figure_agg.get_tk_widget())
except Exception as e:
print(f'Error removing {figure_agg} from list', e)
plt.close('all')
@ -890,11 +881,13 @@ layout = [[sg.Text('Matplotlib Plot Test', font=('ANY 18'))],
[sg.Col(col_listbox), col_instructions], ]
# create the form and show it without the plot
window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, resizable=True, finalize=True)
window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI',
layout, resizable=True, finalize=True)
canvas_elem = window['-CANVAS-']
multiline_elem = window['-MULTILINE-']
figure_agg = None
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
@ -909,8 +902,6 @@ while True:
func = fig_dict[choice]
# show source code to function in multiline
window['-MULTILINE-'].update(inspect.getsource(func))
try:
fig = func() # call function to get the figure
figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig) # draw the figure
except Exception as e:
print('Error in plotting', e)
figure_agg = draw_figure(
window['-CANVAS-'].TKCanvas, fig) # draw the figure

View file

@ -890,7 +890,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize:
new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS)
with io.BytesIO() as bio:
img.save(bio, format="PNG")
del img

View file

@ -39,7 +39,7 @@ def main():
# sg.theme('black')
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['Edit Me', 'Special', 'Normal',['Normal1', 'Normal2'] , 'Undo']],
['&Edit', ['Me', 'Special', 'Normal',['Normal1', 'Normal2'] , 'Undo']],
['!Disabled', ['Special', 'Normal',['Normal1', 'Normal2'], 'Undo']],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
['&Help', ['&About...']], ]
@ -47,7 +47,7 @@ def main():
layout = [[sg.MenubarCustom(menu_def, pad=(0,0), k='-CUST MENUBAR-')],
[sg.Multiline(size=(70, 20), reroute_cprint=True, write_only=True, no_scrollbar=True, k='-MLINE-')]]
window = sg.Window("Custom Titlebar with Custom (Simulated) Menubar", layout, use_custom_titlebar=True, keep_on_top=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window = sg.Window("Custom Titlebar with Custom (Simulated) Menubar", layout, use_custom_titlebar=True, keep_on_top=True)
# ------ Event Loop ------ #
while True:
@ -66,10 +66,8 @@ def main():
sg.popup('About this program', 'Simulated Menubar to accompany a simulated Titlebar',
'PySimpleGUI Version', sg.get_versions(), grab_anywhere=True, keep_on_top=True)
window.reappear()
elif event == 'Edit Me':
elif event == 'Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
elif event.startswith('Open'):
filename = sg.popup_get_file('file to open', no_window=True)
print(filename)

View file

@ -51,8 +51,10 @@ def Menubar(menu_def, text_color, background_color, pad=(0, 0)):
def main():
sg.theme('dark green 7')
sg.theme('dark amber')
# sg.theme('dark purple 3')
menu_def = [['&File', ['&Open & Ctrl-O', '&Save & Ctrl-S', '&Properties', 'E&xit']],
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ],
['!Disabled', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
@ -76,13 +78,13 @@ def main():
layout3 = [[sg.Multiline(size=(70, 20), reroute_stdout=True, reroute_cprint=True, write_only=True)],]
window = sg.Window("Custom Titlebar and Menu", layout, use_custom_titlebar=True, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window = sg.Window("Custom Titlebar and Menu", layout, use_custom_titlebar=True, finalize=True)
win_loc = window.current_location()
window2 = sg.Window("Traditional Titlebar and Menu", layout2, finalize=True, location=(win_loc[0]-window.size[0]-40, win_loc[1]), right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window2 = sg.Window("Traditional Titlebar and Menu", layout2, finalize=True, location=(win_loc[0]-window.size[0]-40, win_loc[1]))
window3 = sg.Window("Output Window", layout3, finalize=True, location=(int(win_loc[0]-window.size[0]//1.5), int(win_loc[1]+window.size[1]+30)), use_custom_titlebar=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window3 = sg.Window("Output Window", layout3, finalize=True, location=(win_loc[0]-window.size[0]//1.5, win_loc[1]+window.size[1]+30), use_custom_titlebar=True)
# ------ Event Loop ------ #
@ -95,10 +97,6 @@ def main():
if event in (sg.WIN_CLOSED, 'Exit'):
break
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
sg.cprint(f'event = {event}', c='white on red')
sg.cprint(f'values = {values}', c='white on green')

View file

@ -1,13 +1,10 @@
#!/usr/bin/env python
import PySimpleGUI as sg
"""
Demo of Menu element, ButtonMenu element and right-click menus
The same basic structure is used for all menus in PySimpleGUI.
Each entry is a list of items to display. If any of those items is a list, then a cancade menu is added.
Copyright 2018, 2019, 2020, 2021, 2022 PySimpleGUI
Demonstration of MENUS!
How do menus work? Like buttons is how.
Check out the variable menu_def for a hint on how to
define menus
"""
@ -27,22 +24,20 @@ def test_menus():
sg.set_options(element_padding=(0, 0))
# ------ Menu Definition ------ #
menu_def = [
['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['&Paste', ['Special', 'Normal', ], 'Undo', 'Options::this_is_a_menu_key'], ],
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['&Paste', ['Special', 'Normal', ], 'Undo'], ],
['&Toolbar', ['---', 'Command &1', 'Command &2',
'---', 'Command &3', 'Command &4']],
['&Help', ['&About...']]
]
['&Help', '&About...'], ]
right_click_menu = ['Unused', ['Right', '!&Click', '&Menu', 'E&xit', 'Properties']]
# ------ GUI Defintion ------ #
layout = [
[sg.Menu(menu_def, tearoff=True, font='_ 12', key='-MENUBAR-')],
[sg.Menu(menu_def, tearoff=False, pad=(200, 1))],
[sg.Text('Right click me for a right click menu example')],
[sg.Output(size=(60, 20))],
[sg.ButtonMenu('ButtonMenu', right_click_menu, key='-BMENU-', text_color='red', disabled_text_color='green'), sg.Button('Plain Button')],
[sg.ButtonMenu('ButtonMenu', right_click_menu, key='-BMENU-'), sg.Button('Plain Button')],
]
window = sg.Window("Windows-like program",
@ -60,7 +55,8 @@ def test_menus():
# ------ Process menu choices ------ #
if event == 'About...':
window.disappear()
sg.popup('About this program', 'Version 1.0', 'PySimpleGUI Version', sg.get_versions())
sg.popup('About this program', 'Version 1.0',
'PySimpleGUI Version', sg.version, grab_anywhere=True)
window.reappear()
elif event == 'Open':
filename = sg.popup_get_file('file to open', no_window=True)

View file

@ -1,46 +0,0 @@
import PySimpleGUI as sg
"""
Read all windows example
The input elements are shown as output on the other window when "Go" is pressed
The checkboxes on window 1 are mirrored on window 2 if "mirror" checkbox is set
Copyright 2022 PySimpleGUI
"""
layout1 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(k='-OUT-')],
[sg.CB('Check 1', k='-CB1-', enable_events=True), sg.CB('Check 2', k='-CB2-', enable_events=True), sg.CB('Mirror on Window 2', enable_events=True, k='-CB3-')],
[sg.Button('Go'), sg.Button('Exit')] ]
window1 = sg.Window('Window 1 Title', layout1, finalize=True, grab_anywhere=True, relative_location=(-600, 0))
layout2 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(k='-OUT-')],
[sg.CB('Check 1', k='-CB1-'), sg.CB('Check 2', k='-CB2-')],
[sg.Button('Go'), sg.Button('Exit')] ]
window2 = sg.Window('Window 2 Title', layout2, finalize=True, grab_anywhere=True)
while True: # Event Loop
window, event, values = sg.read_all_windows()
if window is None:
print('exiting because no windows are left')
break
print(window.Title, event, values) if window is not None else None
if event == sg.WIN_CLOSED or event == 'Exit':
window.close()
if event == 'Go':
# Output the input element to the other windwow
try: # try to update the other window
if window == window1:
window2['-OUT-'].update(values['-IN-'])
else:
window1['-OUT-'].update(values['-IN-'])
except:
pass
try:
if window == window1 and values['-CB3-']:
window2['-CB1-'].update(values['-CB1-'])
window2['-CB2-'].update(values['-CB2-'])
except:
pass

Some files were not shown because too many files have changed in this diff Show more