Compare commits
7 commits
master
...
4.60.0-dot
Author | SHA1 | Date | |
---|---|---|---|
|
41fb096483 | ||
|
e59936e84c | ||
|
b037e1426b | ||
|
63f73c222b | ||
|
8e9b532657 | ||
|
45de5867fb | ||
|
ca93e48ad4 |
|
@ -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
|
||||
|
|
Before Width: | Height: | Size: 8 KiB After Width: | Height: | Size: 8 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 1,000 B After Width: | Height: | Size: 1,000 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
Chess/ChessPiecesArray.png
Normal file
After Width: | Height: | Size: 184 KiB |
233
Chess/Demo_Chess_AGAINST_AI.py
Normal 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
|
@ -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
After Width: | Height: | Size: 1.2 KiB |
BIN
Chess/bishopw.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
Chess/blank.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
36
Chess/game.pgn
Normal 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
After Width: | Height: | Size: 15 KiB |
BIN
Chess/kingb.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
Chess/kingw.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/knightb.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Chess/knightw.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Chess/nbishopb.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Chess/nbishopw.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/nkingb.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/nkingw.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
Chess/nknightb.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/nknightw.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Chess/npawnb.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/npawnw.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/nqueenb.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
Chess/nqueenw.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Chess/nrookb.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Chess/nrookw.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Chess/pawnb.png
Normal file
After Width: | Height: | Size: 797 B |
BIN
Chess/pawnw.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Chess/queenb.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
Chess/queenw.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
16
Chess/readme.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# PySimpleGUI-Chess A Chess Game Playback Program
|
||||
|
||||

|
||||
|
||||
|
||||
## 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
|
@ -0,0 +1,2 @@
|
|||
PySimpleGUI==3.9.1
|
||||
python-chess==0.23.9
|
BIN
Chess/rookb.png
Normal file
After Width: | Height: | Size: 725 B |
BIN
Chess/rookw.png
Normal file
After Width: | Height: | Size: 933 B |
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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])
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
main()
|
|
@ -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()
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,45 +13,44 @@ 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-'])
|
||||
y = math.sin(x/int(values['-SLIDER2-']))*int(values['-SLIDER-'])
|
||||
if prev_x is not None:
|
||||
graph.draw_line((prev_x, prev_y), (x, y), color='red')
|
||||
prev_x, prev_y = x, y
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
@ -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()
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|