Compare commits
No commits in common. "master" and "revert-1572-Dev-latest" have entirely different histories.
master
...
revert-157
3
.github/FUNDING.yml
vendored
|
@ -1,3 +0,0 @@
|
|||
# These are supported funding model platforms
|
||||
custom: ["https://www.paypal.me/pythongui", "https://www.buymeacoffee.com/PySimpleGUI"]
|
||||
github: PySimpleGUI
|
1
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1 +0,0 @@
|
|||
blank_issues_enabled: false
|
18
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
name: Custom issue template
|
||||
about: Describe this issue template's purpose here.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Type of Issues (Enhancement, Error, Bug, Question)
|
||||
|
||||
### Operating System
|
||||
|
||||
### Python version
|
||||
|
||||
### PySimpleGUI Port and Version
|
||||
|
||||
### Code or partial code causing the problem
|
|
@ -1,96 +0,0 @@
|
|||
---
|
||||
name: Issue Form - **Must fill in this form** with every new issue submitted.
|
||||
about: This form contains the information needed to help you solve your problem
|
||||
title: "[ Enhancement/Bug/Question] NOTE - you can also call sg.main() or sg.main_open_github_issue() to post an issue"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Type of Issue (Enhancement, Error, Bug, Question)
|
||||
|
||||
|
||||
----------------------------------------
|
||||
|
||||
#### Operating System
|
||||
|
||||
|
||||
|
||||
#### PySimpleGUI Port (tkinter, Qt, Wx, Web)
|
||||
|
||||
|
||||
|
||||
----------------------------------------
|
||||
|
||||
## Versions
|
||||
|
||||
Version information can be obtained by calling `sg.main_get_debug_data()`
|
||||
Or you can print each version shown in ()
|
||||
|
||||
|
||||
#### Python version (`sg.sys.version`)
|
||||
|
||||
|
||||
|
||||
#### PySimpleGUI Version (`sg.__version__`)
|
||||
|
||||
|
||||
|
||||
#### GUI Version (tkinter (`sg.tclversion_detailed`), PySide2, WxPython, Remi)
|
||||
|
||||
|
||||
|
||||
---------------------
|
||||
|
||||
#### Your Experience In Months or Years (optional)
|
||||
|
||||
Years Python programming experience
|
||||
|
||||
Years Programming experience overall
|
||||
|
||||
Have used another Python GUI Framework? (tkinter, Qt, etc) (yes/no is fine)
|
||||
|
||||
Anything else you think would be helpful?
|
||||
|
||||
|
||||
---------------------
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
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
|
||||
- [ ] 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
|
||||
|
||||
|
||||
|
||||
|
||||
#### Code To Duplicate
|
||||
|
||||
A **short** program that isolates and demonstrates the problem (Do not paste your massive program, but instead 10-20 lines that clearly show the problem)
|
||||
|
||||
This pre-formatted code block is all set for you to paste in your bit of code:
|
||||
|
||||
```python
|
||||
|
||||
# Paste your code here
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### Screenshot, Sketch, or Drawing
|
||||
|
||||
---------------------
|
||||
|
||||
### Watcha Makin?
|
||||
|
||||
If you care to share something about your project, it would be awesome to hear what you're building.
|
|
@ -1,3 +0,0 @@
|
|||
## Pull Request Instructions
|
||||
|
||||
**Pull requests are not currently accepted for the project including the core PySimpleGUI code, the Demo Programs and documentation **
|
2
.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
|
||||
readme_creator/psg_gui.py
|
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 |
|
@ -1,39 +0,0 @@
|
|||
## Contributing to PySimpleGUI
|
||||
|
||||
Hi there! Mike here....thank you for taking time to read this document.
|
||||
|
||||
### Open Source License, but Private Development
|
||||
|
||||
PySimpleGUI is different than most projects on GitHub. It is licensed using the "Open Source License" LGPL3. However, the coding and development of the project is not structured in the same way most open source projects are structured.
|
||||
|
||||
This project/account does not accept user submitted code nor documentation.
|
||||
|
||||
### You Can Still Contribute
|
||||
|
||||
#### Write Applications, Use PySimpleGUI, Make Repos, Post Screenshots, Write Tutorials, Teach Others
|
||||
|
||||
These are a few of the ways you can directly contribute to PySimpleGUI. Using the package to make cool stuff and helping others learn how to use it to make cool stuff is a big help to PySimpleGUI. **Everyone** learns from seeing other people's implementations. It's through user's creating applications that new problems and needs are discovered. These have had a profound and positive impact on the project in the past.
|
||||
|
||||
#### Make Suggestions
|
||||
|
||||
There are 100's of open issues in the main PySimpleGUI GitHub account that are actively worked, daily. There are 1,000s that have been completed. The evolution of PySimpleGUI over the years has been a combination of my vision for the product and ideas from users. So many people have helped make PySimpleGUI better.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Pull requests are *not being accepted* for the project. This includes sending code changes via other means than "pull requests". Plainly put, code you send will not be used.
|
||||
|
||||
I don't mean to be ugly. This isn't personal. Heck, I don't know "you",the reader personally. It's not about ego. It's complicated. The result is that it allows me to dedicate my life to this project. It's what's required, for whatever reason, for me to do this. That's the best explanation I have. I love and respect the users of this work.
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
If you file an Issue for a bug, have located the bug, and found a fix in 10 lines of code or less.... and you wish to share your fix with the community, then feel free to include it with the filed Issue. If it's longer than 10 lines and wish to discuss it, then send an email to help@PySimpleGUI.org.
|
||||
|
||||
## Thank You
|
||||
|
||||
This project comes from a well-meaning, love of computing, and helping others place. It's not about "me", it's about ***you***.
|
||||
|
||||
The support from the user community has been ***amazing***. Your passion for creating PySimpleGUI applications is infectious. Every "thank you" is noticed and appreciated! Your passion for wanting to see PySimpleGUI improve is neither ignored nor unappreciated. At a time when the Internet can feel toxic, there's been expressions of appreciation, gratitude, and encouragement that's unbelievable. I'm touched on a very frequent basis and am filled with gratitude myself as a result.
|
||||
|
||||
It's understood that this way of development of a Python package is unorthodox. You may find it frustrating and slow, but hope you can respect the decision for it to operate in this manner and be supportive.
|
||||
|
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 |
13
Chess/readme.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# 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 |
|
@ -1,747 +0,0 @@
|
|||
import os.path
|
||||
import sys
|
||||
import mmap, re
|
||||
import warnings
|
||||
|
||||
import PySimpleGUI as sg
|
||||
|
||||
__version__ = '1.12.2'
|
||||
|
||||
"""
|
||||
PySimpleGUI Demo Program Browser
|
||||
|
||||
Originaly written for PySimpleGUI Demo Programs, but expanded to
|
||||
be a general purpose tool. Enable Advanced Mode in settings for more fun
|
||||
|
||||
Use to filter and search your source code tree.
|
||||
Then run or edit your files
|
||||
|
||||
Filter the list of :
|
||||
* Search using filename
|
||||
* Searching within the programs' source code (like grep)
|
||||
|
||||
The basic file operations are
|
||||
* Edit a file in your editor
|
||||
* Run a file
|
||||
* Filter file list
|
||||
* Search in files
|
||||
* Run a regular expression search on all files
|
||||
* Display the matching line in a file
|
||||
|
||||
Additional operations
|
||||
* Edit this file in editor
|
||||
|
||||
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
|
||||
Key is short filename
|
||||
Value is the full filename and path
|
||||
|
||||
:return: Dictionary of demo files
|
||||
:rtype: Dict[str:str]
|
||||
"""
|
||||
|
||||
demo_path = get_demo_path()
|
||||
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'):
|
||||
fname_full = os.path.join(dirname, filename)
|
||||
if filename not in demo_files_dict.keys():
|
||||
demo_files_dict[filename] = fname_full
|
||||
else:
|
||||
# Allow up to 100 dupicated names. After that, give up
|
||||
for i in range(1, 100):
|
||||
new_filename = f'{filename}_{i}'
|
||||
if new_filename not in demo_files_dict:
|
||||
demo_files_dict[new_filename] = fname_full
|
||||
break
|
||||
|
||||
return demo_files_dict
|
||||
|
||||
|
||||
def get_file_list():
|
||||
"""
|
||||
Returns list of filenames of files to display
|
||||
No path is shown, only the short filename
|
||||
|
||||
:return: List of filenames
|
||||
:rtype: List[str]
|
||||
"""
|
||||
return sorted(list(get_file_list_dict().keys()))
|
||||
|
||||
|
||||
def get_demo_path():
|
||||
"""
|
||||
Get the top-level folder path
|
||||
:return: Path to list of files using the user settings for this file. Returns folder of this file if not found
|
||||
:rtype: str
|
||||
"""
|
||||
demo_path = sg.user_settings_get_entry('-demos folder-', os.path.dirname(__file__))
|
||||
|
||||
return demo_path
|
||||
|
||||
|
||||
def get_global_editor():
|
||||
"""
|
||||
Get the path to the editor based on user settings or on PySimpleGUI's global settings
|
||||
|
||||
:return: Path to the editor
|
||||
:rtype: str
|
||||
"""
|
||||
try: # in case running with old version of PySimpleGUI that doesn't have a global PSG settings path
|
||||
global_editor = sg.pysimplegui_user_settings.get('-editor program-')
|
||||
except:
|
||||
global_editor = ''
|
||||
return global_editor
|
||||
|
||||
|
||||
def get_editor():
|
||||
"""
|
||||
Get the path to the editor based on user settings or on PySimpleGUI's global settings
|
||||
|
||||
:return: Path to the editor
|
||||
:rtype: str
|
||||
"""
|
||||
try: # in case running with old version of PySimpleGUI that doesn't have a global PSG settings path
|
||||
global_editor = sg.pysimplegui_user_settings.get('-editor program-')
|
||||
except:
|
||||
global_editor = ''
|
||||
user_editor = sg.user_settings_get_entry('-editor program-', '')
|
||||
if user_editor == '':
|
||||
user_editor = global_editor
|
||||
|
||||
return user_editor
|
||||
|
||||
def using_local_editor():
|
||||
user_editor = sg.user_settings_get_entry('-editor program-', None)
|
||||
return get_editor() == user_editor
|
||||
|
||||
|
||||
def get_explorer():
|
||||
"""
|
||||
Get the path to the file explorer program
|
||||
|
||||
:return: Path to the file explorer EXE
|
||||
:rtype: str
|
||||
"""
|
||||
try: # in case running with old version of PySimpleGUI that doesn't have a global PSG settings path
|
||||
global_explorer = sg.pysimplegui_user_settings.get('-explorer program-', '')
|
||||
except:
|
||||
global_explorer = ''
|
||||
explorer = sg.user_settings_get_entry('-explorer program-', '')
|
||||
if explorer == '':
|
||||
explorer = global_explorer
|
||||
return explorer
|
||||
|
||||
|
||||
def advanced_mode():
|
||||
"""
|
||||
Returns True is advanced GUI should be shown
|
||||
|
||||
:return: True if user indicated wants the advanced GUI to be shown (set in the settings window)
|
||||
:rtype: bool
|
||||
"""
|
||||
return sg.user_settings_get_entry('-advanced mode-', True)
|
||||
|
||||
|
||||
|
||||
def get_theme():
|
||||
"""
|
||||
Get the theme to use for the program
|
||||
Value is in this program's user settings. If none set, then use PySimpleGUI's global default theme
|
||||
:return: The theme
|
||||
:rtype: str
|
||||
"""
|
||||
# First get the current global theme for PySimpleGUI to use if none has been set for this program
|
||||
try:
|
||||
global_theme = sg.theme_global()
|
||||
except:
|
||||
global_theme = sg.theme()
|
||||
# Get theme from user settings for this program. Use global theme if no entry found
|
||||
user_theme = sg.user_settings_get_entry('-theme-', '')
|
||||
if user_theme == '':
|
||||
user_theme = global_theme
|
||||
return user_theme
|
||||
|
||||
# We handle our code properly. But in case the user types in a flag, the flags are now in the middle of a regex. Ignore this warning.
|
||||
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
|
||||
# New function
|
||||
def get_line_number(file_path, string, dupe_lines):
|
||||
lmn = 0
|
||||
with open(file_path, encoding="utf-8") as f:
|
||||
for num, line in enumerate(f, 1):
|
||||
if string.strip() == line.strip() and num not in dupe_lines:
|
||||
lmn = num
|
||||
return lmn
|
||||
|
||||
def kill_ascii(s):
|
||||
return "".join([x if ord(x) < 128 else '?' for x in s])
|
||||
|
||||
def find_in_file(string, demo_files_dict, regex=False, verbose=False, window=None, ignore_case=True, show_first_match=True):
|
||||
"""
|
||||
Search through the demo files for a string.
|
||||
The case of the string and the file contents are ignored
|
||||
|
||||
:param string: String to search for
|
||||
:param verbose: if True print the FIRST match
|
||||
:type verbose: bool
|
||||
:param find_all_matches: if True, then return all matches in the dictionary
|
||||
:type find_all_matches: bool
|
||||
:return: List of files containing the string
|
||||
:rtype: List[str]
|
||||
"""
|
||||
|
||||
|
||||
# So you face a predicament here. You wish to read files, both small and large; however the bigger the file/bigger the list, the longer to read the file.
|
||||
# This probably isn't what you want, right?
|
||||
# Well, we can't use a direct command line to run grep and parse. But it is an option. The user may not have it.
|
||||
# We could check if grep exists and if not use our method; but it isn't the best way.
|
||||
# So using background knowldge, we know that grep is *very* fast.
|
||||
#
|
||||
# Why?
|
||||
# Grep reads a *ton* of files into memory then searches through the memory to find the string or regex/pattern corresponding to the file.
|
||||
# (This is useful if you ever accidently delete a file, grep may be able to get you the contents of it again!)
|
||||
# How can we load a file into memory on python as fast as grep whilst keeping it universal?
|
||||
# memory mapping (mmap).
|
||||
# We can't load a lot of files into memory as we may face issues with watchdog on other operating systems. So we load one file at a time and search though there.
|
||||
# This will allow the fastest searching and loading of a file without sacrificing read times.
|
||||
# 2.8 seconds on the highend for both small and large files in memory.
|
||||
# We also don't have to iterate over lines this way.
|
||||
file_list = []
|
||||
num_files = 0
|
||||
matched_dict = {}
|
||||
for file in demo_files_dict:
|
||||
try:
|
||||
full_filename = demo_files_dict[file]
|
||||
if not demo_files_dict == get_file_list_dict():
|
||||
full_filename = full_filename[0]
|
||||
matches = None
|
||||
|
||||
with open(full_filename, 'rb', 0) as f, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as s:
|
||||
if regex:
|
||||
window['-FIND NUMBER-'].update(f'{num_files} files')
|
||||
window.refresh()
|
||||
matches = re.finditer(bytes("^.*(" + string + ").*$", 'utf-8'), s, re.MULTILINE)
|
||||
if matches:
|
||||
for match in matches:
|
||||
if match is not None:
|
||||
if file not in file_list:
|
||||
file_list.append(file)
|
||||
num_files += 1
|
||||
if verbose:
|
||||
sg.cprint(f"{file}:", c = 'white on green')
|
||||
sg.cprint(f"{match.group(0).decode('utf-8')}\n")
|
||||
else:
|
||||
window['-FIND NUMBER-'].update(f'{num_files} files')
|
||||
window.refresh()
|
||||
matches = None
|
||||
if ignore_case:
|
||||
if show_first_match:
|
||||
matches = re.search(br'(?i)^' + bytes(".*("+re.escape(string.lower()) + ").*$", 'utf-8'), s, re.MULTILINE)
|
||||
else:
|
||||
matches = re.finditer(br'(?i)^' + bytes(".*("+re.escape(string.lower()) + ").*$", 'utf-8'), s, re.MULTILINE)
|
||||
else:
|
||||
if show_first_match:
|
||||
matches = re.search(br'^' + bytes(".*("+re.escape(string) + ").*$", 'utf-8'), s, re.MULTILINE)
|
||||
else:
|
||||
matches = re.finditer(br'^' + bytes(".*("+re.escape(string) + ").*$", 'utf-8'), s, re.MULTILINE)
|
||||
if matches:
|
||||
if show_first_match:
|
||||
#file_list.append(file)
|
||||
#num_files += 1
|
||||
match_array = []
|
||||
|
||||
matched_str = matches.group(0).decode('utf-8')
|
||||
if not all(x in matched_str for x in ("b'", '=')) and len(matched_str) < 500:
|
||||
# safe to assume this is not a base64 string as it does not contain the proper ending
|
||||
match_array.append(matches.group(0).decode('utf-8'))
|
||||
matched_dict[full_filename] = match_array
|
||||
file_list.append(file)
|
||||
num_files += 1
|
||||
else:
|
||||
# We need to do this because strings are "falsy" in Python, but empty matches still return True...
|
||||
append_file = False
|
||||
match_array = []
|
||||
for match_ in matches:
|
||||
matched_str = match_.group(0).decode('utf-8')
|
||||
if matched_str:
|
||||
if not all(x in matched_str for x in ("b'", '=')) and len(matched_str) < 500:
|
||||
# if len(match_str) < 500 and "=" not in match_str and "b'" not in match_str:
|
||||
match_array.append(matched_str)
|
||||
append_file = True
|
||||
if append_file:
|
||||
file_list.append(file)
|
||||
num_files += 1
|
||||
matched_dict[full_filename] = match_array
|
||||
|
||||
# del matches
|
||||
except ValueError:
|
||||
del matches
|
||||
except Exception as e:
|
||||
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
||||
print(exc_type, fname, exc_tb.tb_lineno)
|
||||
print(f'{file}', e, file=sys.stderr)
|
||||
|
||||
# Format of the matches dictionary
|
||||
# Filename, [num1, num2, num3]
|
||||
file_lines_dict = {}
|
||||
list_of_matches = []
|
||||
if not regex:
|
||||
for key in matched_dict:
|
||||
head, tail = os.path.split(key)
|
||||
# Tails. Don't wanna put Washington in places he doesn't want to be.
|
||||
file_array_old = [key]
|
||||
|
||||
file_array_new = []
|
||||
|
||||
file_match_list = []
|
||||
|
||||
if verbose:
|
||||
sg.cprint(f"{tail}:", c='white on green')
|
||||
try:
|
||||
dupe_lines = []
|
||||
for _match in matched_dict[key]:
|
||||
line_num_match = get_line_number(key, _match, dupe_lines)
|
||||
dupe_lines.append(line_num_match)
|
||||
file_array_new.append(line_num_match)
|
||||
file_match_list.append(_match) # I *really* overthinked this.
|
||||
if verbose:
|
||||
sg.cprint(f"Line: {line_num_match} ", c='white on purple', end='')
|
||||
sg.cprint(f"{_match.strip()}\n")
|
||||
# Make a list of the matches found in this file to add to the dictionry
|
||||
list_of_matches.append(_match.strip())
|
||||
file_array_old.append(file_array_new)
|
||||
file_array_old.append(file_match_list)
|
||||
|
||||
if tail in file_lines_dict:
|
||||
for i in range(1, 100):
|
||||
new_tail = f'{tail}_{i}'
|
||||
if new_tail not in file_lines_dict:
|
||||
file_lines_dict[new_tail] = file_array_old
|
||||
break
|
||||
else:
|
||||
file_lines_dict[tail] = file_array_old
|
||||
except Exception as e:
|
||||
pass
|
||||
find_in_file.file_list_dict = file_lines_dict
|
||||
|
||||
file_list = list(set(file_list))
|
||||
return file_list
|
||||
|
||||
|
||||
def window_choose_line_to_edit(filename, full_filename, line_num_list, match_list):
|
||||
# sg.popup('matches previously found for this file:', filename, line_num_list)
|
||||
i = 0
|
||||
if len(line_num_list) == 1:
|
||||
return full_filename, line_num_list[0]
|
||||
layout = [[sg.T(f'Choose line from {filename}', font='_ 14')]]
|
||||
for line in sorted(set(line_num_list)):
|
||||
match_text = match_list[i]
|
||||
layout += [[sg.Text(f'Line {line} : {match_text}', key=('-T-', line), enable_events=True, size=(min(len(match_text), 90), None))]]
|
||||
i += 1
|
||||
layout += [[sg.B('Cancel')]]
|
||||
|
||||
window = sg.Window('Open Editor', layout)
|
||||
|
||||
line_chosen = line_num_list[0]
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event in ('Cancel', sg.WIN_CLOSED):
|
||||
line_chosen = None
|
||||
break
|
||||
# At this point we know a line was chosen
|
||||
line_chosen = event[1]
|
||||
break
|
||||
|
||||
window.close()
|
||||
return full_filename, line_chosen
|
||||
|
||||
|
||||
def settings_window():
|
||||
"""
|
||||
Show the settings window.
|
||||
This is where the folder paths and program paths are set.
|
||||
Returns True if settings were changed
|
||||
|
||||
:return: True if settings were changed
|
||||
:rtype: (bool)
|
||||
"""
|
||||
|
||||
try:
|
||||
global_editor = sg.pysimplegui_user_settings.get('-editor program-')
|
||||
except:
|
||||
global_editor = ''
|
||||
try:
|
||||
global_explorer = sg.pysimplegui_user_settings.get('-explorer program-')
|
||||
except:
|
||||
global_explorer = ''
|
||||
try: # in case running with old version of PySimpleGUI that doesn't have a global PSG settings path
|
||||
global_theme = sg.theme_global()
|
||||
except:
|
||||
global_theme = ''
|
||||
|
||||
layout = [[sg.T('Program Settings', font='DEFAULT 25')],
|
||||
[sg.T('Path to Tree', font='_ 16')],
|
||||
[sg.Combo(sorted(sg.user_settings_get_entry('-folder names-', [])), default_value=sg.user_settings_get_entry('-demos folder-', get_demo_path()), size=(50, 1), key='-FOLDERNAME-'),
|
||||
sg.FolderBrowse('Folder Browse', target='-FOLDERNAME-'), sg.B('Clear History')],
|
||||
[sg.T('Editor Program', font='_ 16')],
|
||||
[sg.T('Leave blank to use global default'), sg.T(global_editor)],
|
||||
[ sg.In(sg.user_settings_get_entry('-editor program-', ''),k='-EDITOR PROGRAM-'), sg.FileBrowse()],
|
||||
[sg.T('File Explorer Program', font='_ 16')],
|
||||
[sg.T('Leave blank to use global default'), sg.T(global_explorer)],
|
||||
[ sg.In(sg.user_settings_get_entry('-explorer program-'), k='-EXPLORER PROGRAM-'), sg.FileBrowse()],
|
||||
[sg.T('Theme', font='_ 16')],
|
||||
[sg.T('Leave blank to use global default'), sg.T(global_theme)],
|
||||
[sg.Combo(['']+sg.theme_list(),sg.user_settings_get_entry('-theme-', ''), readonly=True, k='-THEME-')],
|
||||
[sg.T('Double-click a File Will:'), sg.R('Run', 2, sg.user_settings_get_entry('-dclick runs-', False), k='-DCLICK RUNS-'), sg.R('Edit', 2, sg.user_settings_get_entry('-dclick edits-', False), k='-DCLICK EDITS-'), sg.R('Nothing', 2, sg.user_settings_get_entry('-dclick none-', False), k='-DCLICK NONE-')],
|
||||
[sg.CB('Use Advanced Interface', default=advanced_mode() ,k='-ADVANCED MODE-')],
|
||||
[sg.B('Ok', bind_return_key=True), sg.B('Cancel')],
|
||||
]
|
||||
|
||||
window = sg.Window('Settings', layout)
|
||||
|
||||
settings_changed = False
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event in ('Cancel', sg.WIN_CLOSED):
|
||||
break
|
||||
if event == 'Ok':
|
||||
sg.user_settings_set_entry('-demos folder-', values['-FOLDERNAME-'])
|
||||
sg.user_settings_set_entry('-editor program-', values['-EDITOR PROGRAM-'])
|
||||
sg.user_settings_set_entry('-theme-', values['-THEME-'])
|
||||
sg.user_settings_set_entry('-folder names-', list(set(sg.user_settings_get_entry('-folder names-', []) + [values['-FOLDERNAME-'], ])))
|
||||
sg.user_settings_set_entry('-explorer program-', values['-EXPLORER PROGRAM-'])
|
||||
sg.user_settings_set_entry('-advanced mode-', values['-ADVANCED MODE-'])
|
||||
sg.user_settings_set_entry('-dclick runs-', values['-DCLICK RUNS-'])
|
||||
sg.user_settings_set_entry('-dclick edits-', values['-DCLICK EDITS-'])
|
||||
sg.user_settings_set_entry('-dclick nothing-', values['-DCLICK NONE-'])
|
||||
settings_changed = True
|
||||
break
|
||||
elif event == 'Clear History':
|
||||
sg.user_settings_set_entry('-folder names-', [])
|
||||
sg.user_settings_set_entry('-last filename-', '')
|
||||
window['-FOLDERNAME-'].update(values=[], value='')
|
||||
|
||||
window.close()
|
||||
return settings_changed
|
||||
|
||||
ML_KEY = '-ML-' # Multline's key
|
||||
|
||||
# --------------------------------- Create the window ---------------------------------
|
||||
def make_window():
|
||||
"""
|
||||
Creates the main window
|
||||
:return: The main window object
|
||||
:rtype: (sg.Window)
|
||||
"""
|
||||
theme = get_theme()
|
||||
if not theme:
|
||||
theme = sg.OFFICIAL_PYSIMPLEGUI_THEME
|
||||
sg.theme(theme)
|
||||
# First the window layout...2 columns
|
||||
|
||||
find_tooltip = "Find in file\nEnter a string in box to search for string inside of the files.\nFile list will update with list of files string found inside."
|
||||
filter_tooltip = "Filter files\nEnter a string in box to narrow down the list of files.\nFile list will update with list of files with string in filename."
|
||||
find_re_tooltip = "Find in file using Regular Expression\nEnter a string in box to search for string inside of the files.\nSearch is performed after clicking the FindRE button."
|
||||
|
||||
|
||||
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.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')],
|
||||
[sg.Text('Find (F2):', tooltip=find_tooltip), sg.Input(size=(25, 1), enable_events=True, key='-FIND-', tooltip=find_tooltip),
|
||||
sg.T(size=(15,1), k='-FIND NUMBER-')],
|
||||
], element_justification='l', expand_x=True, expand_y=True)
|
||||
|
||||
lef_col_find_re = sg.pin(sg.Col([
|
||||
[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.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))],
|
||||
[sg.T('Python ver ' + sys.version, font='Default 8', pad=(0,0))],
|
||||
[sg.T('Interpreter ' + sg.execute_py_get_interpreter(), font='Default 8', pad=(0,0))],
|
||||
]
|
||||
|
||||
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-'),
|
||||
]],
|
||||
pad=(0,0), k='-OPTIONS BOTTOM-', expand_x=True, expand_y=False), expand_x=True, expand_y=False)
|
||||
|
||||
choose_folder_at_top = sg.pin(sg.Column([[sg.T('Click settings to set top of your tree or choose a previously chosen folder'),
|
||||
sg.Combo(sorted(sg.user_settings_get_entry('-folder names-', [])), default_value=sg.user_settings_get_entry('-demos folder-', ''), size=(50, 30), key='-FOLDERNAME-', enable_events=True, readonly=True)]], pad=(0,0), k='-FOLDER CHOOSE-'))
|
||||
# ----- Full layout -----
|
||||
|
||||
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()]]
|
||||
|
||||
# --------------------------------- 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.bind('<F1>', '-FOCUS FILTER-')
|
||||
window.bind('<F2>', '-FOCUS FIND-')
|
||||
window.bind('<F3>', '-FOCUS RE FIND-')
|
||||
if not advanced_mode():
|
||||
window['-FOLDER CHOOSE-'].update(visible=False)
|
||||
window['-RE COL-'].update(visible=False)
|
||||
window['-OPTIONS BOTTOM-'].update(visible=False)
|
||||
|
||||
# sg.cprint_set_output_destination(window, ML_KEY)
|
||||
window.bring_to_front()
|
||||
return window
|
||||
|
||||
|
||||
# --------------------------------- Main Program Layout ---------------------------------
|
||||
|
||||
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):
|
||||
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',
|
||||
f'You are currently running version:',
|
||||
sg.version,
|
||||
background_color='red', text_color='white')
|
||||
except Exception as e:
|
||||
print(f'** Warning Exception parsing version: {version} ** ', f'{e}')
|
||||
icon = sg.EMOJI_BASE64_HAPPY_IDEA
|
||||
sg.user_settings_filename('psgdemos.json')
|
||||
sg.set_options(icon=icon)
|
||||
find_in_file.file_list_dict = None
|
||||
|
||||
old_typed_value = None
|
||||
|
||||
file_list_dict = get_file_list_dict()
|
||||
file_list = get_file_list()
|
||||
window = make_window()
|
||||
window['-FILTER NUMBER-'].update(f'{len(file_list)} files')
|
||||
window.force_focus()
|
||||
counter = 0
|
||||
while True:
|
||||
event, values = window.read()
|
||||
# print(event, values)
|
||||
|
||||
counter += 1
|
||||
if event in (sg.WINDOW_CLOSED, 'Exit'):
|
||||
break
|
||||
if event == '-DEMO LIST-': # if double clicked (used the bind return key parm)
|
||||
if sg.user_settings_get_entry('-dclick runs-'):
|
||||
event = 'Run'
|
||||
elif sg.user_settings_get_entry('-dclick edits-'):
|
||||
event = 'Edit'
|
||||
if event == 'Edit':
|
||||
editor_program = get_editor()
|
||||
for file in values['-DEMO LIST-']:
|
||||
if find_in_file.file_list_dict is not None:
|
||||
full_filename, line = window_choose_line_to_edit(file, find_in_file.file_list_dict[file][0], find_in_file.file_list_dict[file][1], find_in_file.file_list_dict[file][2])
|
||||
else:
|
||||
full_filename, line = get_file_list_dict()[file], 1
|
||||
if line is not None:
|
||||
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 using_local_editor():
|
||||
sg.execute_command_subprocess(editor_program, f'"{full_filename}"')
|
||||
else:
|
||||
try:
|
||||
sg.execute_editor(full_filename, line_number=int(line))
|
||||
except:
|
||||
sg.execute_command_subprocess(editor_program, f'"{full_filename}"')
|
||||
else:
|
||||
sg.cprint('Editing canceled')
|
||||
elif event == 'Run':
|
||||
sg.cprint('Running....', c='white on green', end='')
|
||||
sg.cprint('')
|
||||
for file in values['-DEMO LIST-']:
|
||||
file_to_run = str(file_list_dict[file])
|
||||
sg.cprint(file_to_run,text_color='white', background_color='purple')
|
||||
try:
|
||||
sp = sg.execute_py_file(file_to_run, pipe_output=values['-WAIT-'])
|
||||
except Exception as e:
|
||||
sg.cprint(f'Error trying to run python file. Error info:', e, c='white on red')
|
||||
try:
|
||||
if values['-WAIT-']:
|
||||
sg.cprint(f'Waiting on results..', text_color='white', background_color='red', end='')
|
||||
while True:
|
||||
results = sg.execute_get_results(sp)
|
||||
sg.cprint(f'STDOUT:', text_color='white', background_color='green')
|
||||
sg.cprint(results[0])
|
||||
sg.cprint(f'STDERR:', text_color='white', background_color='green')
|
||||
sg.cprint(results[1])
|
||||
if not sg.execute_subprocess_still_running(sp):
|
||||
break
|
||||
except AttributeError:
|
||||
sg.cprint('Your version of PySimpleGUI needs to be upgraded to fully use the "WAIT" feature.', c='white on red')
|
||||
elif event.startswith('Edit Me'):
|
||||
editor_program = get_editor()
|
||||
sg.cprint(f'opening using {editor_program}:')
|
||||
sg.cprint(f'{__file__}', text_color='white', background_color='red', end='')
|
||||
sg.execute_command_subprocess(f'{editor_program}', f'"{__file__}"')
|
||||
elif event == '-FILTER-':
|
||||
new_list = [i for i in file_list if values['-FILTER-'].lower() in i.lower()]
|
||||
window['-DEMO LIST-'].update(new_list)
|
||||
window['-FILTER NUMBER-'].update(f'{len(new_list)} files')
|
||||
window['-FIND NUMBER-'].update('')
|
||||
window['-FIND-'].update('')
|
||||
window['-FIND RE-'].update('')
|
||||
elif event == '-FOCUS FIND-':
|
||||
window['-FIND-'].set_focus()
|
||||
elif event == '-FOCUS FILTER-':
|
||||
window['-FILTER-'].set_focus()
|
||||
elif event == '-FOCUS RE FIND-':
|
||||
window['-FIND RE-'].set_focus()
|
||||
elif event == '-FIND-' or event == '-FIRST MATCH ONLY-' or event == '-VERBOSE-' or event == '-FIND RE-':
|
||||
is_ignore_case = values['-IGNORE CASE-']
|
||||
old_ignore_case = False
|
||||
current_typed_value = str(values['-FIND-'])
|
||||
if len(values['-FIND-']) == 1:
|
||||
window[ML_KEY].update('')
|
||||
window['-VERBOSE-'].update(False)
|
||||
values['-VERBOSE-'] = False
|
||||
if values['-VERBOSE-']:
|
||||
window[ML_KEY].update('')
|
||||
if values['-FIND-']:
|
||||
if find_in_file.file_list_dict is None or old_typed_value is None or old_ignore_case is not is_ignore_case:
|
||||
# New search.
|
||||
old_typed_value = current_typed_value
|
||||
file_list = find_in_file(values['-FIND-'], get_file_list_dict(), verbose=values['-VERBOSE-'], window=window, ignore_case=is_ignore_case, show_first_match=values['-FIRST MATCH ONLY-'])
|
||||
elif current_typed_value.startswith(old_typed_value) and old_ignore_case is is_ignore_case:
|
||||
old_typed_value = current_typed_value
|
||||
file_list = find_in_file(values['-FIND-'], find_in_file.file_list_dict, verbose=values['-VERBOSE-'], window=window, ignore_case=is_ignore_case, show_first_match=values['-FIRST MATCH ONLY-'])
|
||||
else:
|
||||
old_typed_value = current_typed_value
|
||||
file_list = find_in_file(values['-FIND-'], get_file_list_dict(), verbose=values['-VERBOSE-'], window=window, ignore_case=is_ignore_case, show_first_match=values['-FIRST MATCH ONLY-'])
|
||||
window['-DEMO LIST-'].update(sorted(file_list))
|
||||
window['-FIND NUMBER-'].update(f'{len(file_list)} files')
|
||||
window['-FILTER NUMBER-'].update('')
|
||||
window['-FIND RE-'].update('')
|
||||
window['-FILTER-'].update('')
|
||||
elif values['-FIND RE-']:
|
||||
window['-ML-'].update('')
|
||||
file_list = find_in_file(values['-FIND RE-'], get_file_list_dict(), regex=True, verbose=values['-VERBOSE-'],window=window)
|
||||
window['-DEMO LIST-'].update(sorted(file_list))
|
||||
window['-FIND NUMBER-'].update(f'{len(file_list)} files')
|
||||
window['-FILTER NUMBER-'].update('')
|
||||
window['-FIND-'].update('')
|
||||
window['-FILTER-'].update('')
|
||||
elif event == 'Find RE':
|
||||
window['-ML-'].update('')
|
||||
file_list = find_in_file(values['-FIND RE-'], get_file_list_dict(), regex=True, verbose=values['-VERBOSE-'],window=window)
|
||||
window['-DEMO LIST-'].update(sorted(file_list))
|
||||
window['-FIND NUMBER-'].update(f'{len(file_list)} files')
|
||||
window['-FILTER NUMBER-'].update('')
|
||||
window['-FIND-'].update('')
|
||||
window['-FILTER-'].update('')
|
||||
sg.cprint('Regular expression find completed')
|
||||
elif event == 'Settings':
|
||||
if settings_window() is True:
|
||||
window.close()
|
||||
window = make_window()
|
||||
file_list_dict = get_file_list_dict()
|
||||
file_list = get_file_list()
|
||||
window['-FILTER NUMBER-'].update(f'{len(file_list)} files')
|
||||
elif event == 'Clear':
|
||||
file_list = get_file_list()
|
||||
window['-FILTER-'].update('')
|
||||
window['-FILTER NUMBER-'].update(f'{len(file_list)} files')
|
||||
window['-FIND-'].update('')
|
||||
window['-DEMO LIST-'].update(file_list)
|
||||
window['-FIND NUMBER-'].update('')
|
||||
window['-FIND RE-'].update('')
|
||||
window['-ML-'].update('')
|
||||
elif event == '-FOLDERNAME-':
|
||||
sg.user_settings_set_entry('-demos folder-', values['-FOLDERNAME-'])
|
||||
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('')
|
||||
elif event == 'Open Folder':
|
||||
explorer_program = get_explorer()
|
||||
if explorer_program:
|
||||
sg.cprint(f'Opening Folder using {explorer_program}...', c='white on green', end='')
|
||||
sg.cprint('')
|
||||
for file in values['-DEMO LIST-']:
|
||||
file_selected = str(file_list_dict[file])
|
||||
file_path = os.path.dirname(file_selected)
|
||||
if sg.running_windows():
|
||||
file_path = file_path.replace('/', '\\')
|
||||
sg.cprint(file_path, text_color='white', background_color='purple')
|
||||
sg.execute_command_subprocess(explorer_program, file_path)
|
||||
elif event == 'Copy Path':
|
||||
for file in values['-DEMO LIST-']:
|
||||
sg.cprint('Copying the last highlighted filename in your list')
|
||||
if find_in_file.file_list_dict is not None:
|
||||
full_filename, line = window_choose_line_to_edit(file, find_in_file.file_list_dict[file][0], find_in_file.file_list_dict[file][1], find_in_file.file_list_dict[file][2])
|
||||
else:
|
||||
full_filename, line = get_file_list_dict()[file], 1
|
||||
if line is not None:
|
||||
sg.cprint(f'Added to Clipboard Full Path {full_filename}', c='white on purple')
|
||||
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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
main()
|
BIN
DemoPrograms/Color-Guide.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
DemoPrograms/Color-names.png
Normal file
After Width: | Height: | Size: 298 KiB |
|
@ -1,163 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
Example of (almost) all Elements, that you can use in PySimpleGUI.
|
||||
Shows you the basics including:
|
||||
Naming convention for keys
|
||||
Menubar format
|
||||
Right click menu format
|
||||
Table format
|
||||
Running an async event loop
|
||||
Theming your application (requires a window restart)
|
||||
Displays the values dictionary entry for each element
|
||||
And more!
|
||||
|
||||
Copyright 2021, 2022, 2023 PySimpleGUI
|
||||
"""
|
||||
|
||||
import PySimpleGUI as sg
|
||||
|
||||
def make_window(theme):
|
||||
sg.theme(theme)
|
||||
menu_def = [['&Application', ['E&xit']],
|
||||
['&Help', ['&About']] ]
|
||||
right_click_menu_def = [[], ['Edit Me', 'Versions', 'Nothing','More Nothing','Exit']]
|
||||
graph_right_click_menu_def = [[], ['Erase','Draw Line', 'Draw',['Circle', 'Rectangle', 'Image'], 'Exit']]
|
||||
|
||||
# Table Data
|
||||
data = [["John", 10], ["Jen", 5]]
|
||||
headings = ["Name", "Score"]
|
||||
|
||||
input_layout = [
|
||||
|
||||
# [sg.Menu(menu_def, key='-MENU-')],
|
||||
[sg.Text('Anything that requires user-input is in this tab!')],
|
||||
[sg.Input(key='-INPUT-')],
|
||||
[sg.Slider(orientation='h', key='-SKIDER-'),
|
||||
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.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-')],
|
||||
[sg.Button('Button'), sg.Button('Popup'), sg.Button(image_data=sg.DEFAULT_BASE64_ICON, key='-LOGO-')]]
|
||||
|
||||
asthetic_layout = [[sg.T('Anything that you would use for asthetics is in this tab!')],
|
||||
[sg.Image(data=sg.DEFAULT_BASE64_ICON, k='-IMAGE-')],
|
||||
[sg.ProgressBar(100, orientation='h', size=(20, 20), key='-PROGRESS BAR-'), sg.Button('Test Progress bar')]]
|
||||
|
||||
logging_layout = [[sg.Text("Anything printed will display here!")],
|
||||
[sg.Multiline(size=(60,15), font='Courier 8', expand_x=True, expand_y=True, write_only=True,
|
||||
reroute_stdout=True, reroute_stderr=True, echo_stdout_stderr=True, autoscroll=True, auto_refresh=True)]
|
||||
# [sg.Output(size=(60,15), font='Courier 8', expand_x=True, expand_y=True)]
|
||||
]
|
||||
|
||||
graphing_layout = [[sg.Text("Anything you would use to graph will display here!")],
|
||||
[sg.Graph((200,200), (0,0),(200,200),background_color="black", key='-GRAPH-', enable_events=True,
|
||||
right_click_menu=graph_right_click_menu_def)],
|
||||
[sg.T('Click anywhere on graph to draw a circle')],
|
||||
[sg.Table(values=data, headings=headings, max_col_width=25,
|
||||
background_color='black',
|
||||
auto_size_columns=True,
|
||||
display_row_numbers=True,
|
||||
justification='right',
|
||||
num_rows=2,
|
||||
alternating_row_color='black',
|
||||
key='-TABLE-',
|
||||
row_height=25)]]
|
||||
|
||||
popup_layout = [[sg.Text("Popup Testing")],
|
||||
[sg.Button("Open Folder")],
|
||||
[sg.Button("Open File")]]
|
||||
|
||||
theme_layout = [[sg.Text("See how elements look under different themes by choosing a different theme here!")],
|
||||
[sg.Listbox(values = sg.theme_list(),
|
||||
size =(20, 12),
|
||||
key ='-THEME LISTBOX-',
|
||||
enable_events = True)],
|
||||
[sg.Button("Set Theme")]]
|
||||
|
||||
layout = [ [sg.MenubarCustom(menu_def, key='-MENU-', font='Courier 15', tearoff=True)],
|
||||
[sg.Text('Demo Of (Almost) All Elements', size=(38, 1), justification='center', font=("Helvetica", 16), relief=sg.RELIEF_RIDGE, k='-TEXT HEADING-', enable_events=True)]]
|
||||
layout +=[[sg.TabGroup([[ sg.Tab('Input Elements', input_layout),
|
||||
sg.Tab('Asthetic Elements', asthetic_layout),
|
||||
sg.Tab('Graphing', graphing_layout),
|
||||
sg.Tab('Popups', popup_layout),
|
||||
sg.Tab('Theming', theme_layout),
|
||||
sg.Tab('Output', logging_layout)]], key='-TAB GROUP-', expand_x=True, expand_y=True),
|
||||
|
||||
]]
|
||||
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.set_min_size(window.size)
|
||||
return window
|
||||
|
||||
def main():
|
||||
window = make_window(sg.theme())
|
||||
|
||||
# This is an Event Loop
|
||||
while True:
|
||||
event, values = window.read(timeout=100)
|
||||
# keep an animation running so show things are happening
|
||||
if event not in (sg.TIMEOUT_EVENT, sg.WIN_CLOSED):
|
||||
print('============ Event = ', event, ' ==============')
|
||||
print('-------- Values Dictionary (key=value) --------')
|
||||
for key in values:
|
||||
print(key, ' = ',values[key])
|
||||
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':
|
||||
print("[LOG] Clicked About!")
|
||||
sg.popup('PySimpleGUI Demo All Elements',
|
||||
'Right click anywhere to see right click menu',
|
||||
'Visit each of the tabs to see available elements',
|
||||
'Output of event and values can be see in Output tab',
|
||||
'The event and values dictionary is printed after every event', keep_on_top=True)
|
||||
elif event == 'Popup':
|
||||
print("[LOG] Clicked Popup Button!")
|
||||
sg.popup("You pressed a button!", keep_on_top=True)
|
||||
print("[LOG] Dismissing Popup!")
|
||||
elif event == 'Test Progress bar':
|
||||
print("[LOG] Clicked Test Progress Bar!")
|
||||
progress_bar = window['-PROGRESS BAR-']
|
||||
for i in range(100):
|
||||
print("[LOG] Updating progress bar by 1 step ("+str(i)+")")
|
||||
progress_bar.update(current_count=i + 1)
|
||||
print("[LOG] Progress bar complete!")
|
||||
elif event == "-GRAPH-":
|
||||
graph = window['-GRAPH-'] # type: sg.Graph
|
||||
graph.draw_circle(values['-GRAPH-'], fill_color='yellow', radius=20)
|
||||
print("[LOG] Circle drawn at: " + str(values['-GRAPH-']))
|
||||
elif event == "Open Folder":
|
||||
print("[LOG] Clicked Open Folder!")
|
||||
folder_or_file = sg.popup_get_folder('Choose your folder', keep_on_top=True)
|
||||
sg.popup("You chose: " + str(folder_or_file), keep_on_top=True)
|
||||
print("[LOG] User chose folder: " + str(folder_or_file))
|
||||
elif event == "Open File":
|
||||
print("[LOG] Clicked Open File!")
|
||||
folder_or_file = sg.popup_get_file('Choose your file', keep_on_top=True)
|
||||
sg.popup("You chose: " + str(folder_or_file), keep_on_top=True)
|
||||
print("[LOG] User chose file: " + str(folder_or_file))
|
||||
elif event == "Set Theme":
|
||||
print("[LOG] Clicked Set Theme!")
|
||||
theme_chosen = values['-THEME LISTBOX-'][0]
|
||||
print("[LOG] User Chose Theme: " + str(theme_chosen))
|
||||
window.close()
|
||||
window = make_window(theme_chosen)
|
||||
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)
|
||||
|
||||
window.close()
|
||||
exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sg.theme('black')
|
||||
sg.theme('dark red')
|
||||
sg.theme('dark green 7')
|
||||
# sg.theme('DefaultNoMoreNagging')
|
||||
main()
|
|
@ -1,107 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
|
||||
"""
|
||||
Demo - Element List
|
||||
|
||||
All elements shown in 1 window as simply as possible.
|
||||
|
||||
Copyright 2022 PySimpleGUI
|
||||
"""
|
||||
|
||||
|
||||
use_custom_titlebar = True if sg.running_trinket() else False
|
||||
|
||||
def make_window(theme=None):
|
||||
|
||||
NAME_SIZE = 23
|
||||
|
||||
|
||||
def name(name):
|
||||
dots = NAME_SIZE-len(name)-2
|
||||
return sg.Text(name + ' ' + '•'*dots, size=(NAME_SIZE,1), justification='r',pad=(0,0), font='Courier 10')
|
||||
|
||||
sg.theme(theme)
|
||||
|
||||
# NOTE that we're using our own LOCAL Menu element
|
||||
if use_custom_titlebar:
|
||||
Menu = sg.MenubarCustom
|
||||
else:
|
||||
Menu = sg.Menu
|
||||
|
||||
treedata = sg.TreeData()
|
||||
|
||||
treedata.Insert("", '_A_', 'Tree Item 1', [1234], )
|
||||
treedata.Insert("", '_B_', 'B', [])
|
||||
treedata.Insert("_A_", '_A1_', 'Sub Item 1', ['can', 'be', 'anything'], )
|
||||
|
||||
layout_l = [
|
||||
[name('Text'), sg.Text('Text')],
|
||||
[name('Input'), sg.Input(s=15)],
|
||||
[name('Multiline'), sg.Multiline(s=(15,2))],
|
||||
[name('Output'), sg.Output(s=(15,2))],
|
||||
[name('Combo'), sg.Combo(sg.theme_list(), default_value=sg.theme(), s=(15,22), enable_events=True, readonly=True, k='-COMBO-')],
|
||||
[name('OptionMenu'), sg.OptionMenu(['OptionMenu',],s=(15,2))],
|
||||
[name('Checkbox'), sg.Checkbox('Checkbox')],
|
||||
[name('Radio'), sg.Radio('Radio', 1)],
|
||||
[name('Spin'), sg.Spin(['Spin',], s=(15,2))],
|
||||
[name('Button'), sg.Button('Button')],
|
||||
[name('ButtonMenu'), sg.ButtonMenu('ButtonMenu', sg.MENU_RIGHT_CLICK_EDITME_EXIT)],
|
||||
[name('Slider'), sg.Slider((0,10), orientation='h', s=(10,15))],
|
||||
[name('Listbox'), sg.Listbox(['Listbox', 'Listbox 2'], no_scrollbar=True, s=(15,2))],
|
||||
[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))],
|
||||
[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)],
|
||||
[name('Horizontal Separator'), sg.HSep()],
|
||||
[name('Vertical Separator'), sg.VSep()],
|
||||
[name('Frame'), sg.Frame('Frame', [[sg.T(s=15)]])],
|
||||
[name('Column'), sg.Column([[sg.T(s=15)]])],
|
||||
[name('Tab, TabGroup'), sg.TabGroup([[sg.Tab('Tab1',[[sg.T(s=(15,2))]]), sg.Tab('Tab2', [[]])]])],
|
||||
[name('Pane'), sg.Pane([sg.Col([[sg.T('Pane 1')]]), sg.Col([[sg.T('Pane 2')]])])],
|
||||
[name('Push'), sg.Push(), sg.T('Pushed over')],
|
||||
[name('VPush'), sg.VPush()],
|
||||
[name('Sizer'), sg.Sizer(1,1)],
|
||||
[name('StatusBar'), sg.StatusBar('StatusBar')],
|
||||
[name('Sizegrip'), sg.Sizegrip()] ]
|
||||
|
||||
# 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)]]
|
||||
|
||||
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)
|
||||
|
||||
window['-PBAR-'].update(30) # Show 30% complete on ProgressBar
|
||||
window['-GRAPH-'].draw_image(data=sg.EMOJI_BASE64_HAPPY_JOY, location=(0,50)) # Draw something in the Graph Element
|
||||
|
||||
return window
|
||||
|
||||
|
||||
window = make_window()
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
# sg.Print(event, values)
|
||||
if event == sg.WIN_CLOSED or event == 'Exit':
|
||||
break
|
||||
|
||||
if values['-COMBO-'] != sg.theme():
|
||||
sg.theme(values['-COMBO-'])
|
||||
window.close()
|
||||
window = make_window()
|
||||
if event == '-USE CUSTOM TITLEBAR-':
|
||||
use_custom_titlebar = values['-USE CUSTOM TITLEBAR-']
|
||||
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)
|
||||
window.close()
|
||||
|
||||
|
54
DemoPrograms/Demo_All_Widgets.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
sg.ChangeLookAndFeel('GreenTan')
|
||||
|
||||
# ------ Menu Definition ------ #
|
||||
menu_def = [['&File', ['&Open', '&Save', 'E&xit', 'Properties']],
|
||||
['&Edit', ['Paste', ['Special', 'Normal', ], 'Undo'], ],
|
||||
['&Help', '&About...'], ]
|
||||
|
||||
# ------ Column Definition ------ #
|
||||
column1 = [[sg.Text('Column 1', background_color='lightblue', justification='center', size=(10, 1))],
|
||||
[sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 1')],
|
||||
[sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 2')],
|
||||
[sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 3')]]
|
||||
|
||||
layout = [
|
||||
[sg.Menu(menu_def, tearoff=True)],
|
||||
[sg.Text('(Almost) All widgets in one Window!', size=(30, 1), justification='center', font=("Helvetica", 25), relief=sg.RELIEF_RIDGE)],
|
||||
[sg.Text('Here is some text.... and a place to enter text')],
|
||||
[sg.InputText('This is my text')],
|
||||
[sg.Frame(layout=[
|
||||
[sg.Checkbox('Checkbox', size=(10,1)), sg.Checkbox('My second checkbox!', default=True)],
|
||||
[sg.Radio('My first Radio! ', "RADIO1", default=True, size=(10,1)), sg.Radio('My second Radio!', "RADIO1")]], title='Options',title_color='red', relief=sg.RELIEF_SUNKEN, tooltip='Use these to set flags')],
|
||||
[sg.Multiline(default_text='This is the default Text should you decide not to type anything', size=(35, 3)),
|
||||
sg.Multiline(default_text='A second multi-line', size=(35, 3))],
|
||||
[sg.InputCombo(('Combobox 1', 'Combobox 2'), size=(20, 1)),
|
||||
sg.Slider(range=(1, 100), orientation='h', size=(34, 20), default_value=85)],
|
||||
[sg.InputOptionMenu(('Menu Option 1', 'Menu Option 2', 'Menu Option 3'))],
|
||||
[sg.Listbox(values=('Listbox 1', 'Listbox 2', 'Listbox 3'), size=(30, 3)),
|
||||
sg.Frame('Labelled Group',[[
|
||||
sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=25, tick_interval=25),
|
||||
sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=75),
|
||||
sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=10),
|
||||
sg.Column(column1, background_color='lightblue')]])],
|
||||
[sg.Text('_' * 80)],
|
||||
[sg.Text('Choose A Folder', size=(35, 1))],
|
||||
[sg.Text('Your Folder', size=(15, 1), auto_size_text=False, justification='right'),
|
||||
sg.InputText('Default Folder'), sg.FolderBrowse()],
|
||||
[sg.Submit(tooltip='Click to submit this form'), sg.Cancel()]]
|
||||
|
||||
window = sg.Window('Everything bagel', default_element_size=(40, 1), grab_anywhere=False).Layout(layout)
|
||||
event, values = window.Read()
|
||||
|
||||
sg.Popup('Title',
|
||||
'The results of the window.',
|
||||
'The button clicked was "{}"'.format(event),
|
||||
'The values are', values)
|
||||
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
from PIL import Image, ImageTk, ImageSequence
|
||||
import PySimpleGUI as sg
|
||||
|
||||
"""
|
||||
Demo_Animated_GIFs_Using_PIL.py
|
||||
|
||||
You'll find other animated GIF playback demos for PySimpleGUI that use the tkinter built-in GIF parser.
|
||||
That is how the built-in PySimpleGUI Image.update_animation is used.
|
||||
|
||||
If you want to do the GIF file parsing yourself using PIL and update your Image element yourself, then
|
||||
this is one possible technique.
|
||||
|
||||
This particular demo will loop playing the GIF file over and over. To not loop, remove the while True statement.
|
||||
Copyright 2020 PySimpleGUI.org
|
||||
"""
|
||||
|
||||
gif_filename = r'ExampleGIF.gif'
|
||||
|
||||
layout = [[sg.Text('Happy Thursday!', background_color='#A37A3B', text_color='#FFF000', justification='c', key='-T-', font=("Bodoni MT", 40))],
|
||||
[sg.Image(key='-IMAGE-')]]
|
||||
|
||||
window = sg.Window('Window Title', layout, element_justification='c', margins=(0,0), element_padding=(0,0), finalize=True)
|
||||
|
||||
window['-T-'].expand(True, True, True) # Make the Text element expand to take up all available space
|
||||
|
||||
interframe_duration = Image.open(gif_filename).info['duration'] # get how long to delay between frames
|
||||
|
||||
while True:
|
||||
for frame in ImageSequence.Iterator(Image.open(gif_filename)):
|
||||
event, values = window.read(timeout=interframe_duration)
|
||||
if event == sg.WIN_CLOSED:
|
||||
exit(0)
|
||||
window['-IMAGE-'].update(data=ImageTk.PhotoImage(frame) )
|
|
@ -1,29 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
|
||||
"""
|
||||
Simple template window that saves position.
|
||||
|
||||
Rather than starting in the middle of the screen, this code will save the position the window was in when it last exited.
|
||||
|
||||
To pull this off it's going to be.... super.....?hard?
|
||||
No... of course it's going to be... SIMPLE
|
||||
|
||||
There is one added line of code. When the user attempts to close the window, that's when the position is saved.
|
||||
When the program starts, it reads the previously saved position as part of the window creation. User Settings APIs rock!
|
||||
|
||||
Copyright 2021 PySimpleGUI
|
||||
"""
|
||||
|
||||
layout = [[sg.Text('Window that Auto-saves position', font='_ 25')],
|
||||
[sg.Button('Ok'), sg.Button('Exit')]]
|
||||
|
||||
window = sg.Window('Auto-saves Location', layout, enable_close_attempted_event=True, location=sg.user_settings_get_entry('-location-', (None, None)))
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
print(event, values)
|
||||
if event in ('Exit', sg.WINDOW_CLOSE_ATTEMPTED_EVENT):
|
||||
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
|
||||
break
|
||||
|
||||
window.close()
|
|
@ -1,55 +1,28 @@
|
|||
import PySimpleGUI as sg
|
||||
import random
|
||||
|
||||
"""
|
||||
Demo - Using a Graph Element to make Bar Charts
|
||||
BAR_WIDTH = 50
|
||||
BAR_SPACING = 75
|
||||
EDGE_OFFSET = 3
|
||||
GRAPH_SIZE = (500,500)
|
||||
DATA_SIZE = (500,500)
|
||||
|
||||
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)
|
||||
graph = sg.Graph(GRAPH_SIZE, (0, 0), DATA_SIZE)
|
||||
|
||||
Copyright 2022 PySimpleGUI
|
||||
"""
|
||||
layout = [[sg.Text('Bar graphs using PySimpleGUI')],
|
||||
[graph],
|
||||
[sg.Button('OK')]]
|
||||
|
||||
|
||||
|
||||
BAR_WIDTH = 50 # width of each bar
|
||||
BAR_SPACING = 75 # space between each bar
|
||||
EDGE_OFFSET = 3 # offset from the left edge for first bar
|
||||
GRAPH_SIZE= DATA_SIZE = (500,500) # size in pixels
|
||||
|
||||
sg.theme('Light brown 1')
|
||||
|
||||
layout = [[sg.Text('Labelled Bar graphs using PySimpleGUI')],
|
||||
[sg.Graph(GRAPH_SIZE, (0,0), DATA_SIZE, k='-GRAPH-')],
|
||||
[sg.Button('OK'), sg.T('Click to display more data'), sg.Exit()]]
|
||||
|
||||
window = sg.Window('Bar Graph', layout, finalize=True)
|
||||
|
||||
graph = window['-GRAPH-'] # type: sg.Graph
|
||||
window = sg.Window('Window Title').Layout(layout)
|
||||
|
||||
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.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])
|
||||
|
||||
graph.draw_text(text=graph_value, location=(i*BAR_SPACING+EDGE_OFFSET+25, graph_value+10), font='_ 14')
|
||||
|
||||
# Normally at the top of the loop, but because we're drawing the graph first, making it at the bottom
|
||||
event, values = window.read()
|
||||
|
||||
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||
event, values = window.Read()
|
||||
graph.Erase()
|
||||
if event is None:
|
||||
break
|
||||
|
||||
|
||||
window.close()
|
||||
for i in range(7):
|
||||
graph_value = random.randint(0, 400)
|
||||
graph.DrawRectangle(top_left=(i * BAR_SPACING + EDGE_OFFSET, graph_value),
|
||||
bottom_right=(i * BAR_SPACING + EDGE_OFFSET + BAR_WIDTH, 0), fill_color='blue')
|
||||
graph.DrawText(text=graph_value, location=(i*BAR_SPACING+EDGE_OFFSET+25, graph_value+10))
|
|
@ -1,27 +1,27 @@
|
|||
# Base64 Encoder - encodes a folder of PNG files and creates a .py file with definitions
|
||||
import PySimpleGUI as sg
|
||||
import os
|
||||
import base64
|
||||
|
||||
'''
|
||||
Make base64 images
|
||||
input: folder with .png .ico .gif 's
|
||||
output: output.py file with variables
|
||||
Base64 Encoder - encodes a folder of PNG files and creates a .py file with definitions
|
||||
'''
|
||||
|
||||
OUTPUT_FILENAME = 'output.py'
|
||||
|
||||
def main():
|
||||
OUTPUT_FILENAME = 'output.py'
|
||||
# folder = r'C:\Python\PycharmProjects\GooeyGUI\Uno Cards'
|
||||
folder=''
|
||||
folder = sg.PopupGetFolder('Source folder for images\nImages will be encoded and results saved to %s'%OUTPUT_FILENAME,
|
||||
title='Base64 Encoder',
|
||||
default_path=folder, initial_folder=folder )
|
||||
|
||||
folder = sg.popup_get_folder('Source folder for images\nImages will be encoded and results saved to %s'%OUTPUT_FILENAME,
|
||||
title='Base64 Encoder')
|
||||
|
||||
if not folder:
|
||||
sg.popup_cancel('Cancelled - No valid folder entered')
|
||||
if folder is None or folder == '':
|
||||
sg.PopupCancel('Cancelled - No valid folder entered')
|
||||
return
|
||||
try:
|
||||
namesonly = [f for f in os.listdir(folder) if f.endswith('.png') or f.endswith('.ico') or f.endswith('.gif')]
|
||||
namesonly = [f for f in os.listdir(folder) if f.endswith('.png') or f.endswith('.ico')]
|
||||
except:
|
||||
sg.popup_cancel('Cancelled - No valid folder entered')
|
||||
sg.PopupCancel('Cancelled - No valid folder entered')
|
||||
return
|
||||
|
||||
outfile = open(os.path.join(folder, OUTPUT_FILENAME), 'w')
|
||||
|
@ -29,11 +29,12 @@ def main():
|
|||
for i, file in enumerate(namesonly):
|
||||
contents = open(os.path.join(folder, file), 'rb').read()
|
||||
encoded = base64.b64encode(contents)
|
||||
outfile.write('\n{} = {}'.format(file[:file.index(".")], encoded))
|
||||
sg.OneLineProgressMeter('Base64 Encoding', i+1, len(namesonly), key='-METER-')
|
||||
outfile.write('\n{} = {}\n\n'.format(file[:file.index(".")], encoded))
|
||||
sg.OneLineProgressMeter('Base64 Encoding', i+1, len(namesonly),key='_METER_')
|
||||
|
||||
outfile.close()
|
||||
sg.popup('Completed!', 'Encoded %s files'%(i+1))
|
||||
sg.Popup('Completed!', 'Encoded %s files'%(i+1))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
import base64
|
||||
|
||||
"""
|
||||
Make base64 image from a file
|
||||
This is usually done in order to create a Base64 image for use as an Ucon or a Button image
|
||||
To use, either copy and paste the full path to the file or use the browse button to locate the file.
|
||||
Once chosen, the conversion will happen automatically with the result placed on the clipboard.
|
||||
When complete, a popup window is shown that tells you to paste the image before closing the window. This is because of a
|
||||
tkinter problem on Linux. On Windows you can close the Window, but on Linux, you'll need to keep it open until the paste completes
|
||||
|
||||
NOTE - if you're replacing your ICO file for your window with a base64 image, you will first need to convert your icon from
|
||||
an ICO file into a PNG file. Encode the PNG file and then you'll be able to pass that value in your call to Window:
|
||||
|
||||
window = sg.Window('Window Title', layout, icon=icon)
|
||||
|
||||
Where icon is a variable you created using the contents of the clipboard folowing running this program.
|
||||
|
||||
Input: a single image file
|
||||
Output: clipboard will contain the Base64 Byte String of the source image
|
||||
|
||||
Copyright 2021 PySimpleGUI
|
||||
"""
|
||||
|
||||
|
||||
def convert_file_to_base64(filename):
|
||||
try:
|
||||
contents = open(filename, 'rb').read()
|
||||
encoded = base64.b64encode(contents)
|
||||
sg.clipboard_set(encoded)
|
||||
# pyperclip.copy(str(encoded))
|
||||
sg.popup('Copied to your clipboard!', 'Keep window open until you have pasted the base64 bytestring')
|
||||
except Exception as error:
|
||||
sg.popup_error('Cancelled - An error occurred', error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
filename = sg.popup_get_file('Source Image will be encoded and results placed on clipboard', title='Base64 Encoder')
|
||||
|
||||
if filename:
|
||||
convert_file_to_base64(filename)
|
||||
else:
|
||||
sg.popup_cancel('Cancelled - No valid file entered')
|
|
@ -1,25 +1,29 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
# Turn off padding in order to get a really tight looking layout.
|
||||
"""
|
||||
Turn off padding in order to get a really tight looking layout.
|
||||
"""
|
||||
|
||||
sg.theme('Dark')
|
||||
sg.set_options(element_padding=(0, 0))
|
||||
sg.ChangeLookAndFeel('Dark')
|
||||
sg.SetOptions(element_padding=(0, 0))
|
||||
|
||||
layout = [[sg.Text('User:', pad=((3, 0), 0)), sg.OptionMenu(values=('User 1', 'User 2'), size=(20, 1)),
|
||||
sg.Text('0', size=(8, 1))],
|
||||
[sg.Text('Customer:', pad=((3, 0), 0)), sg.OptionMenu(values=('Customer 1', 'Customer 2'), size=(20, 1)),
|
||||
sg.Text('1', size=(8, 1))],
|
||||
[sg.Text('Notes:', pad=((3, 0), 0)),
|
||||
sg.Input(size=(44, 1), background_color='white', text_color='black')],
|
||||
[sg.Button('Start', button_color=('white', 'black')),
|
||||
sg.Button('Stop', button_color=('gray50', 'black')),
|
||||
sg.Button('Reset', button_color=('white', '#9B0023')),
|
||||
sg.Button('Submit', button_color=('gray60', 'springgreen4')),
|
||||
layout = [[sg.T('User:', pad=((3, 0), 0)), sg.OptionMenu(values=('User 1', 'User 2'), size=(20, 1)),
|
||||
sg.T('0', size=(8, 1))],
|
||||
[sg.T('Customer:', pad=((3, 0), 0)), sg.OptionMenu(values=('Customer 1', 'Customer 2'), size=(20, 1)),
|
||||
sg.T('1', size=(8, 1))],
|
||||
[sg.T('Notes:', pad=((3, 0), 0)), sg.In(size=(44, 1), background_color='white', text_color='black')],
|
||||
[sg.ReadButton('Start', button_color=('white', 'black')),
|
||||
sg.ReadButton('Stop', button_color=('gray50', 'black')),
|
||||
sg.ReadButton('Reset', button_color=('white', '#9B0023')),
|
||||
sg.ReadButton('Submit', button_color=('gray60', 'springgreen4')),
|
||||
sg.Button('Exit', button_color=('white', '#00406B'))]]
|
||||
|
||||
window = sg.Window("Borderless Window",
|
||||
layout,
|
||||
default_element_size=(12, 1),
|
||||
text_justification='r',
|
||||
auto_size_text=False,
|
||||
|
@ -28,7 +32,11 @@ window = sg.Window("Borderless Window",
|
|||
grab_anywhere=True,
|
||||
default_button_element_size=(12, 1))
|
||||
|
||||
window.Layout(layout)
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||
event, values = window.Read()
|
||||
if event is None or event == 'Exit':
|
||||
break
|
||||
|
||||
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
import PySimpleGUI as sg
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
if not sys.platform.startswith('win'):
|
||||
sg.popup_error('Sorry, you gotta be on Windows')
|
||||
sg.PopupError('Sorry, you gotta be on Windows')
|
||||
sys.exit()
|
||||
import winsound
|
||||
|
||||
|
||||
sg.ChangeLookAndFeel('Dark')
|
||||
sg.SetOptions(element_padding=(0,0))
|
||||
|
||||
layout = [
|
||||
[sg.Button('Start', button_color=('white', 'black'), key='start'),
|
||||
sg.Button('Stop', button_color=('white', 'black'), key='stop'),
|
||||
sg.Button('Reset', button_color=('white', 'firebrick3'), key='reset'),
|
||||
sg.Button('Submit', button_color=('white', 'springgreen4'), key='submit')]
|
||||
[sg.ReadButton('Start', button_color=('white', 'black'), key='start'),
|
||||
sg.ReadButton('Stop', button_color=('white', 'black'), key='stop'),
|
||||
sg.ReadButton('Reset', button_color=('white', 'firebrick3'), key='reset'),
|
||||
sg.ReadButton('Submit', button_color=('white', 'springgreen4'), key='submit')]
|
||||
]
|
||||
|
||||
window = sg.Window("Button Click", layout, auto_size_buttons=False, default_button_element_size=(12,1), use_default_focus=False, finalize=True)
|
||||
window = sg.Window("Button Click", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False, default_button_element_size=(12,1), use_default_focus=False).Layout(layout).Finalize()
|
||||
|
||||
window['submit'].update(disabled=True)
|
||||
window.FindElement('submit').Update(disabled=True)
|
||||
|
||||
recording = have_data = False
|
||||
while True:
|
||||
event, values = window.read(timeout=100)
|
||||
if event == sg.WINDOW_CLOSED:
|
||||
break
|
||||
winsound.PlaySound("ButtonClick.wav", 1) if event != sg.TIMEOUT_KEY else None
|
||||
window.close()
|
||||
event, values = window.Read()
|
||||
if event is None:
|
||||
sys.exit(69)
|
||||
winsound.PlaySound("ButtonClick.wav", 1)
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
|
||||
"""
|
||||
Demo - Fill a listbox with list of files FilesBrowse button
|
||||
|
||||
This technique can be used to generate events from "Chooser Buttons" like FileBrowse, FilesBrowse
|
||||
FolderBrowser, ColorChooserButton, Calendar Button
|
||||
|
||||
Any button that uses a "Target" can be used with an invisible Input Element to generate an
|
||||
event when the user has made a choice. Enable events for the invisible element and an event will
|
||||
be generated when the Chooser Button fills in the element
|
||||
|
||||
This particular demo users a list of chosen files to populate a listbox
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
layout = [ [sg.LBox([], size=(20,10), key='-FILESLB-')],
|
||||
[sg.Input(visible=False, enable_events=True, key='-IN-'), sg.FilesBrowse()],
|
||||
[sg.Button('Go'), sg.Button('Exit')] ]
|
||||
|
||||
window = sg.Window('Window Title', layout)
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
# When choice has been made, then fill in the listbox with the choices
|
||||
if event == '-IN-':
|
||||
window['-FILESLB-'].Update(values['-IN-'].split(';'))
|
||||
window.close()
|
|
@ -1,6 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
import PySimpleGUI as sg
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
|
||||
"""
|
||||
Demo Button Function Calls
|
||||
|
@ -14,29 +18,26 @@ It is quite easy to simulate these callbacks however. The way to do this is to
|
|||
to your Event Loop
|
||||
"""
|
||||
|
||||
|
||||
def callback_function1():
|
||||
sg.popup('In Callback Function 1')
|
||||
sg.Popup('In Callback Function 1')
|
||||
print('In the callback function 1')
|
||||
|
||||
|
||||
def callback_function2():
|
||||
sg.popup('In Callback Function 2')
|
||||
sg.Popup('In Callback Function 2')
|
||||
print('In the callback function 2')
|
||||
|
||||
layout = [ [sg.Text('Demo of Button Callbacks')],
|
||||
[sg.Button('Button 1'), sg.Button('Button 2')] ]
|
||||
|
||||
layout = [[sg.Text('Demo of Button Callbacks')],
|
||||
[sg.Button('Button 1'), sg.Button('Button 2')]]
|
||||
|
||||
window = sg.Window('Button Callback Simulation', layout)
|
||||
window = sg.Window('Button Callback Simulation').Layout(layout)
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window.read()
|
||||
if event == sg.WIN_CLOSED:
|
||||
event, values = window.Read()
|
||||
if event is None:
|
||||
break
|
||||
elif event == 'Button 1':
|
||||
callback_function1() # call the "Callback" function
|
||||
elif event == 'Button 2':
|
||||
callback_function2() # call the "Callback" function
|
||||
|
||||
window.close()
|
||||
window.Close()
|
||||
|
|
|
@ -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,60 +1,51 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
"""
|
||||
Demonstrates using a "tight" layout with a Dark theme.
|
||||
Shows how button states can be controlled by a user application. The program manages the disabled/enabled
|
||||
states for buttons and changes the text color to show greyed-out (disabled) buttons
|
||||
"""
|
||||
|
||||
sg.theme('Dark')
|
||||
sg.set_options(element_padding=(0, 0))
|
||||
sg.ChangeLookAndFeel('Dark')
|
||||
sg.SetOptions(element_padding=(0,0))
|
||||
|
||||
layout = [[sg.Text('User:', pad=((3, 0), 0)), sg.OptionMenu(values=('User 1', 'User 2'), size=(20, 1)), sg.Text('0', size=(8, 1))],
|
||||
[sg.Text('Customer:', pad=((3, 0), 0)), sg.OptionMenu(
|
||||
values=('Customer 1', 'Customer 2'), size=(20, 1)), sg.Text('1', size=(8, 1))],
|
||||
[sg.Text('Notes:', pad=((3, 0), 0)), sg.Input(size=(44, 1),
|
||||
background_color='white', text_color='black')],
|
||||
[sg.Button('Start', button_color=('white', 'black'), key='-Start-'),
|
||||
sg.Button('Stop', button_color=('white', 'black'), key='-Stop-'),
|
||||
sg.Button('Reset', button_color=('white', 'firebrick3'), key='-Reset-'),
|
||||
sg.Button('Submit', button_color=('white', 'springgreen4'), key='-Submit-')]]
|
||||
layout = [[sg.T('User:', pad=((3,0),0)), sg.OptionMenu(values = ('User 1', 'User 2'), size=(20,1)), sg.T('0', size=(8,1))],
|
||||
[sg.T('Customer:', pad=((3,0),0)), sg.OptionMenu(values=('Customer 1', 'Customer 2'), size=(20,1)), sg.T('1', size=(8,1))],
|
||||
[sg.T('Notes:', pad=((3,0),0)), sg.In(size=(44,1), background_color='white', text_color='black')],
|
||||
[sg.ReadButton('Start', button_color=('white', 'black'), key='_Start_'),
|
||||
sg.ReadButton('Stop', button_color=('white', 'black'), key='_Stop_'),
|
||||
sg.ReadButton('Reset', button_color=('white', 'firebrick3'), key='_Reset_'),
|
||||
sg.ReadButton('Submit', button_color=('white', 'springgreen4'), key='_Submit_')]]
|
||||
|
||||
window = sg.Window("Time Tracker", layout,
|
||||
default_element_size=(12, 1),
|
||||
text_justification='r',
|
||||
auto_size_text=False,
|
||||
auto_size_buttons=False,
|
||||
default_button_element_size=(12, 1),
|
||||
finalize=True)
|
||||
window = sg.Window("Time Tracker", default_element_size=(12,1), text_justification='r', auto_size_text=False, auto_size_buttons=False,
|
||||
default_button_element_size=(12,1)).Layout(layout).Finalize()
|
||||
|
||||
|
||||
for key, state in {'-Start-': False, '-Stop-': True, '-Reset-': True, '-Submit-': True}.items():
|
||||
window[key].update(disabled=state)
|
||||
for key, state in {'_Start_': False, '_Stop_': True, '_Reset_': True, '_Submit_': True}.items():
|
||||
window.FindElement(key).Update(disabled=state)
|
||||
|
||||
recording = have_data = False
|
||||
while True:
|
||||
event, values = window.read()
|
||||
event, values = window.Read()
|
||||
print(event)
|
||||
if event == sg.WIN_CLOSED:
|
||||
break
|
||||
if event == '-Start-':
|
||||
for key, state in {'-Start-': True, '-Stop-': False, '-Reset-': False, '-Submit-': True}.items():
|
||||
window[key].update(disabled=state)
|
||||
if event is None:
|
||||
sys.exit(69)
|
||||
if event == '_Start_':
|
||||
for key, state in {'_Start_':True, '_Stop_':False, '_Reset_':False, '_Submit_':True}.items():
|
||||
window.FindElement(key).Update(disabled=state)
|
||||
recording = True
|
||||
elif event == '-Stop-' and recording:
|
||||
[window[key].update(disabled=value) for key, value in {
|
||||
'-Start-': False, '-Stop-': True, '-Reset-': False, '-Submit-': False}.items()]
|
||||
elif event == '_Stop_' and recording:
|
||||
[window.FindElement(key).Update(disabled=value) for key,value in {'_Start_':False, '_Stop_':True, '_Reset_':False, '_Submit_':False}.items()]
|
||||
recording = False
|
||||
have_data = True
|
||||
elif event == '-Reset-':
|
||||
[window[key].update(disabled=value) for key, value in {
|
||||
'-Start-': False, '-Stop-': True, '-Reset-': True, '-Submit-': True}.items()]
|
||||
elif event == '_Reset_':
|
||||
[window.FindElement(key).Update(disabled=value) for key,value in {'_Start_':False, '_Stop_':True, '_Reset_':True, '_Submit_':True}.items()]
|
||||
recording = False
|
||||
have_data = False
|
||||
elif event == '-Submit-' and have_data:
|
||||
[window[key].update(disabled=value) for key, value in {
|
||||
'-Start-': False, '-Stop-': True, '-Reset-': True, '-Submit-': False}.items()]
|
||||
elif event is '_Submit_' and have_data:
|
||||
[window.FindElement(key).Update(disabled=value) for key,value in {'_Start_':False, '_Stop_':True, '_Reset_':True, '_Submit_':False}.items()]
|
||||
recording = False
|
||||
|
||||
window.close()
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
"""
|
||||
Demo - Button Toggle #2
|
||||
|
||||
|
||||
Uses the IGNORE BUTTON setting.
|
||||
When creating or updating buttons in 4.35.0+, you can use the parameter:
|
||||
disabled=BUTTON_DISABLED_MEANS_IGNORE
|
||||
|
||||
This will cause the buytton to ignore your clicks but it won't change the button
|
||||
with the GUI, which would change the color and gray it out. The button will not
|
||||
change appearance at all. It will no longer respond to button clicks.
|
||||
|
||||
Another toggle button using Base64 strings
|
||||
Of course files could be used instead of Base64 strings
|
||||
|
||||
The differences between this toggle button demo and the other one are:
|
||||
1. Different button graphics
|
||||
2. The button state is stored in the metadata for the button
|
||||
3. The metadata for the button is a class instead of a single variable name
|
||||
|
||||
For buttons with graphics, it's generally best to set the button's:
|
||||
* border width=0
|
||||
* color = (background_color, background_color)
|
||||
|
||||
Buttons don't normally have explicit keys. However, since this button has
|
||||
no text, there is no default key. It's better to be explicit with buttons that
|
||||
change text or have graphics.
|
||||
|
||||
Copyright 2021 PySimpleGUI
|
||||
"""
|
||||
|
||||
import PySimpleGUI as sg
|
||||
import random
|
||||
|
||||
# Class holding the button graphic info. At this time only the state is kept
|
||||
class BtnInfo:
|
||||
def __init__(self, state=True):
|
||||
self.state = state # Can have 3 states - True, False, None (disabled)
|
||||
|
||||
# Main function that creates the layout, window and has event loop
|
||||
def main():
|
||||
layout = [[sg.Text('Toggle Button')],
|
||||
[sg.T('Disabled with PySimpleGUI Ignore:', text_color='yellow')],
|
||||
[sg.Button(image_data=on_image, k='-TOGGLE1-', border_width=0,
|
||||
button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled_button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
metadata=BtnInfo()),
|
||||
sg.T('Disable:'),
|
||||
sg.Button(image_data=off_image, k='-DISABLE1-', border_width=0,
|
||||
button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled_button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
metadata=BtnInfo(False)), sg.T('Disabled button color is\nbetter than other disabled button below')
|
||||
],
|
||||
[sg.Button(image_data=on_image, k='-TOGGLE2-', border_width=0,
|
||||
button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled_button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
metadata=BtnInfo()),
|
||||
sg.Image(data=sg.EMOJI_BASE64_HAPPY_THUMBS_UP,enable_events=True, k='-I-')
|
||||
],
|
||||
[ sg.T('Disabled with GUI:', text_color='yellow')],
|
||||
[sg.Button(image_data=on_image, k='-TOGGLE3-', border_width=0,
|
||||
button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled_button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled=True, metadata=BtnInfo()), sg.T('Note color has crosshatching')],
|
||||
[ sg.T('Disabled with PySimpleGUI (ignored):', text_color='yellow')],
|
||||
[sg.Button(image_data=on_image, k='-TOGGLE4-', border_width=0,
|
||||
button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled_button_color=(sg.theme_background_color(), sg.theme_background_color()),
|
||||
disabled=sg.BUTTON_DISABLED_MEANS_IGNORE,
|
||||
metadata=BtnInfo())],
|
||||
[sg.T(size=(40,1), k='-STATUS-')],
|
||||
[sg.Button('Exit')]]
|
||||
|
||||
window = sg.Window('Window Title', layout, font='_ 14', finalize=True)
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
# Where all the magic happens. 2 things happen when button is clicked
|
||||
# 1. The state toggles
|
||||
# 2. The buton graphic changes
|
||||
if 'TOGGLE' in event:
|
||||
window[event].metadata.state = not window[event].metadata.state
|
||||
window[event].update(image_data=on_image if window[event].metadata.state else off_image)
|
||||
elif event == '-DISABLE1-':
|
||||
window[event].metadata.state = not window[event].metadata.state
|
||||
window[event].update(image_data=on_image if window[event].metadata.state else off_image)
|
||||
window['-I-'].update(data=sg.EMOJI_BASE64_HAPPY_GASP if window[event].metadata.state else random.choice(sg.EMOJI_BASE64_HAPPY_LIST))
|
||||
# if disabling the button
|
||||
if window[event].metadata.state:
|
||||
if window['-TOGGLE1-'].metadata.state is True:
|
||||
window['-TOGGLE1-'].update(disabled=sg.BUTTON_DISABLED_MEANS_IGNORE, image_data=on_image_disabled)
|
||||
elif window['-TOGGLE1-'].metadata.state is False:
|
||||
window['-TOGGLE1-'].update(disabled=sg.BUTTON_DISABLED_MEANS_IGNORE, image_data=off_image_disabled)
|
||||
else:
|
||||
if window['-TOGGLE1-'].metadata.state is True:
|
||||
window['-TOGGLE1-'].update(disabled=False, image_data=on_image)
|
||||
elif window['-TOGGLE1-'].metadata.state is False:
|
||||
window['-TOGGLE1-'].update(disabled=False, image_data=off_image)
|
||||
window['-STATUS-'].update(f'event {event} button state = {window[event].metadata.state if window[event].metadata is not None else "Not applicable"}')
|
||||
window.close()
|
||||
|
||||
# Define the button graphic base 64 strings and then call the main function
|
||||
if __name__ == '__main__':
|
||||
on_image = b'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'
|
||||
|
||||
off_image = b'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'
|
||||
|
||||
off_image_disabled = b'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'
|
||||
on_image_disabled = b'iVBORw0KGgoAAAANSUhEUgAAAFoAAAAnCAYAAACPFF8dAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAVLSURBVGhD7Zu7TytHFMbHyxvsJeb9kjCiCihRpJAobaqblFGUJmXqKMofkyZpaKhS5HaJIgUpRZQmoqAhSgEUSBZgsAE/uJhX5ht80LmH8e56fdde7PuTPu0yj/XMt7Nnd2aXxPr6uuKMjIx84LruR47jJGtJbeeVplQqOaOjo+8MDAwk7u7uyrWsWIF2FYvFf3Rbt/HnQ+oDj0Ynk8kPl5eXf9Amf6L7pW5vb9X9/b3Jaye5XE719fWpubk51dPTY/bjijba+KbN3t7d3f324uLir1rWg9HpdPrFysrKy0KhMJTNZtX19XUtu/0sLi6qyclJlUqlcLWpRCJRy4knNzc3ShusKpXKq52dnS/z+fyvSE9sbGxMrq2t/Xd8fJw+PDw0hf1oRWdxNY2Pj6tMJqMmJiZUf3//Y3ocrjQJPOG+nJ2dYWSXt7a23tMRYt+Zn5//rlqteppMB5EHi5rZ2VmEtEeTAUzGJRo3yZOv7ydo94j293v8ndjW6JDxvh7RpoBEGtsKo9FofdNTq6urampqSvX29tZynhcIIUdHR//qUb3iDA4OZnDzs0Gm0khulQCMBs/VZIC2Dw8Pv6v71OvoO7lri3nUYb5tlToRp7Z9Deos37ZanYbVaA7vON/qCU1k6kQC94oMhxFk+FuCU9doPnptkPFRqBN5YjTvKO1LE3iZtwSjMwNiDGnYaD6aEa/1czieFdXQ0JB1wQfPw5C8Cii9Wwg9omHw2NiYmSLDaCz4YNoJ8ScHpGNBCGU4SIe6hVBGY+0BBmOiUy6XzQIKpptY9cOohrESjHg+y+u2ON+w0TAXpgGYfHl5aZYGq9WqMRsLLDDbNnXGyelWQsVoisUwl4OTQGvZPF5TOsxHyOlGQsdogNEroTQZGkqlktkiLnfq7M+LpnpsM4zS5EIVXvFUKhVzAmC2zH+OoA/1JGnYaByEwoN8PONhBXFbgngOw1GvnaNamhJWjdBwb2EmDAP0/EwvTV3XNQbiRNDJ4KBxuIGGQXayGXlhKx9WnFDDCjdBGEZhIJ1Om+dnmI2RXCwWayWfgrpXV1e1v4IhG10P2dEwCoKtnpQkVOgAGNX5fN7c5LCP+IvHOzxT85sk0uUoxt+oh7ygyI7Y5IetTlSSNBUoYSheg8E4mCYf9wDy5asyqlfvFZrE1pFGhd+0pYdRPbzKPTGaF6B9WVEeJGro95uRH7Y6jcqLuiOaKvIDyP2oFBRb3bDywlbeT5LAocPvQFEif5sUBFu9RuVHkDq+RvOK/ECIeW8y7nHZsJULIj9sdRpVEKxGU2W+lftRywtb+bDywlY+qCTGaLkuAagw39pGcBSjWoJJkFe+hJdtRn7Y6kBAznwdZPCVNg5V4gegfS4KI29KgB4VMWVHo7nZtjpcvG1hZTuulK0eID/RdpQDjn7+PcfMrh5UGciDRiVA69w03UfjMdVHw9EB5EUp/IaXbHXQdrwUQTsB2q5nwZc6/T6xubn5WyaT+Wxvb08VCgVTwAtbmIkCNHpmZkYtLCyY76P5iwQ6GXGE/MHMFzPlg4ODP/f39z91Tk9Pfzw/P1dLS0tqenra10h0shUC+JQYbTs5OXltfQRtjKvQdhhMyuVyP5k244t/PXJ+0aPmCywM4dLEohAuD1S0QUa0ApiMD9LxMTrCB1SvXe0GnuHegi1M1m3/I5vNvtBZd8Zo3fCkNvvnZDL5OV41Ic7EqTM48RjReOdo+3QhLmAAwmis4ejQ8bu+Ir/SaWYpk/9XViKVSn3tuu43ujMf67t8975JDYk29UrfAP/WA2NdawNJDzlK/Q9RjPZ1HEiBtwAAAABJRU5ErkJggg=='
|
||||
|
||||
main()
|
|
@ -1,37 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
|
||||
"""
|
||||
Toggle Button Demo - Simple Version
|
||||
|
||||
A simple graphic that toggles.
|
||||
The "State" of on/off is stored in the button's Metadata
|
||||
|
||||
Copyright 2021 PySimpleGUI
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
layout = [[sg.Text('A toggle button example')],
|
||||
[sg.Text('Off'),
|
||||
sg.Button(image_data=toggle_btn_off, key='-TOGGLE-GRAPHIC-', button_color=(sg.theme_background_color(), sg.theme_background_color()), border_width=0, metadata=False),
|
||||
sg.Text('On')]]
|
||||
|
||||
window = sg.Window('Toggle Button Simple Graphic', layout)
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
elif event == '-TOGGLE-GRAPHIC-': # if the graphical button that changes images
|
||||
window['-TOGGLE-GRAPHIC-'].metadata = not window['-TOGGLE-GRAPHIC-'].metadata
|
||||
window['-TOGGLE-GRAPHIC-'].update(image_data=toggle_btn_on if window['-TOGGLE-GRAPHIC-'].metadata else toggle_btn_off)
|
||||
|
||||
window.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# The base64 strings for the button images
|
||||
toggle_btn_off = b'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABmJLR0QA/wD/AP+gvaeTAAAED0lEQVRYCe1WTWwbRRR+M/vnv9hO7BjHpElMKSlpqBp6gRNHxAFVcKM3qgohQSqoqhQ45YAILUUVDRxAor2VAweohMSBG5ciodJUSVqa/iikaePEP4nj2Ovdnd1l3qqJksZGXscVPaylt7Oe/d6bb9/svO8BeD8vA14GvAx4GXiiM0DqsXv3xBcJU5IO+RXpLQvs5yzTijBmhurh3cyLorBGBVokQG9qVe0HgwiXLowdy9aKsY3g8PA5xYiQEUrsk93JTtjd1x3siIZBkSWQudUK4nZO1w3QuOWXV+HuP/fL85klAJuMCUX7zPj4MW1zvC0Ej4yMp/w++K2rM9b70sHBYCjo34x9bPelsgp/XJksZ7KFuwZjr3732YcL64ttEDw6cq5bVuCvgy/sje7rT0sI8PtkSHSEIRIKgCQKOAUGM6G4VoGlwiqoVd2Za9Vl8u87bGJqpqBqZOj86eEHGNch+M7otwHJNq4NDexJD+59RiCEQG8qzslFgN8ibpvZNsBifgXmFvJg459tiOYmOElzYvr2bbmkD509e1ylGEZk1Y+Ssfan18n1p7vgqVh9cuiDxJPxKPT3dfGXcN4Tp3dsg/27hUQs0qMGpRMYjLz38dcxS7Dm3nztlUAb38p0d4JnLozPGrbFfBFm79c8hA3H2AxcXSvDz7/+XtZE1kMN23hjV7LTRnKBh9/cZnAj94mOCOD32gi2EUw4FIRUMm6LGhyiik86nO5NBdGRpxYH14bbjYfJteN/OKR7UiFZVg5T27QHYu0RBxoONV9W8KQ7QVp0iXdE8fANUGZa0QAvfhhXlkQcmjJZbt631oIBnwKmacYoEJvwiuFgWncWnXAtuVBBEAoVVXWCaQZzxmYuut68b631KmoVBEHMUUrJjQLXRAQVSxUcmrKVHfjWWjC3XOT1FW5QrWpc5IJdQhDKVzOigEqS5dKHMVplnNOqrmsXqUSkn+YzWaHE9RW1FeXL7SKZXBFUrXW6jIV6YTEvMAUu0W/G3kcxPXP5ylQZs4fa6marcWvvZfJu36kuHjlc/nMSuXz+/ejxgqPFpuQ/xVude9eu39Jxu27OLvBGoMjrUN04zrNMbgVmOBZ96iPdPZmYntH5Ls76KuxL9NyoLA/brav7n382emDfHqeooXyhQmARVhSnAwNNMx5bu3V1+habun5nWdXhwJZ2C5mirTesyUR738sv7g88UQ0rEkTDlp+1wwe8Pf0klegUenYlgyg7bby75jUTITs2rhCAXXQ2vwxz84vlB0tZ0wL4NEcLX/04OrrltG1s8aOrHhk51SaK0us+n/K2xexBxljcsm1n6x/Fuv1PCWGiKOaoQCY1Vb9gWPov50+fdEqd21ge3suAlwEvA14G/ucM/AuppqNllLGPKwAAAABJRU5ErkJggg=='
|
||||
toggle_btn_on = b'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABmJLR0QA/wD/AP+gvaeTAAAD+UlEQVRYCe1XzW8bVRCffbvrtbP+2NhOD7GzLm1VoZaPhvwDnKBUKlVyqAQ3/gAkDlWgPeVQEUCtEOIP4AaHSI0CqBWCQyXOdQuRaEFOk3g3IMWO46+tvZ+PeZs6apq4ipON1MNafrvreTPzfvub92bGAOEnZCBkIGQgZOClZoDrh25y5pdjruleEiX+A+rCaQo05bpuvJ/+IHJCSJtwpAHA/e269g8W5RbuzF6o7OVjF8D3Pr4tSSkyjcqfptPDMDKSleW4DKIggIAD5Yf+Oo4DNg6jbUBlvWLUNutAwZu1GnDjzrcXzGcX2AHw/emFUV6Sfk0pqcKpEydkKSo9q3tkz91uF5aWlo1Gs/mYc+i7tz4//19vsW2AU9O381TiioVCQcnlRsWeQhD3bJyH1/MiFLICyBHiuzQsD1arDvypW7DR9nzZmq47q2W95prm+I9fXfqXCX2AF2d+GhI98Y8xVX0lnxvl2UQQg0csb78ag3NjEeD8lXZ7pRTgftmCu4864OGzrq+5ZU0rCa3m+NzXlzvoAoB3+M+SyWQuaHBTEzKMq/3BMbgM+FuFCDBd9kK5XI5PJBKqLSev+POTV29lKB8rT0yMD0WjUSYLZLxzNgZvIHODOHuATP72Vwc6nQ4Uiw8MUeBU4nHS5HA6TYMEl02wPRcZBJuv+ya+UCZOIBaLwfCwQi1Mc4QXhA+PjWRkXyOgC1uIhW5Qd8yG2TK7kSweLcRGKKVnMNExWWBDTQsH9qVmtmzjiThQDs4Qz/OUSGTwcLwIQTLW58i+yOjpXDLqn1tgmDzXzRCk9eDenjo9yhvBmlizrB3V5dDrNTuY0A7opdndStqmaQLPC1WCGfShYRgHdLe32UrV3ntiH9LliuNrsToNlD4kruN8v75eafnSgC6Luo2+B3fGKskilj5muV6pNhk2Qqg5v7lZ51nBZhNBjGrbxfI1+La5t2JCzfD8RF1HTBGJXyDzs1MblONulEqPDVYXgwDIfNx91IUVbAbY837GMur+/k/XZ75UWmJ77ou5mfM1/0x7vP1ls9XQdF2z9uNsPzosXPNFA5m0/EX72TBSiqsWzN8z/GZB08pWq9VeEZ+0bjKb7RTD2i1P4u6r+bwypo5tZUumEcDAmuC3W8ezIqSGfE6g/sTd1W5p5bKjaWubrmWd29Fu9TD0GlYlmTx+8tTJoZeqYe2BZC1/JEU+wQR5TVEUPptJy3Fs+Vkzgf8lemqHumP1AnYoMZSwsVEz6o26i/G9Lgitb+ZmLu/YZtshfn5FZDPBCcJFQRQ+8ih9DctOFvdLIKHH6uUQnq9yhFu0bec7znZ+xpAGmuqef5/wd8hAyEDIQMjAETHwP7nQl2WnYk4yAAAAAElFTkSuQmCC'
|
||||
|
||||
main()
|
|
@ -1,32 +0,0 @@
|
|||
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
|
||||
|
||||
play = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAByElEQVRoge3ZMWsUQRjG8Z8RFSKCgoJp0qSJjVpoZ2clkk8g5CtYpU+TD5DSUkvbVCFNYiM2dhZqY6GFQooEISGai8Xu4HgmcnM3c+su+4fj2L2dmedhb+Z95x16enp6hljBxaZF5OAE7/GoaSGTchJ9tnCrWTnjE0zs19+HWMPlJkWNQzAyh2c4rq+/YBnnmpOWRjASuIfX0f0d3GlAVzLDRmBG9Ta+1r8d4wVuTFdaGqcZCVzFOn7Uz+ziKc5PR1oa/zISWMRm9OxbPCisK5lRjASW8Clqs4H5MrLSSTECs1jFQd3ue319KbewVFKNBBbwMmr/EY8z6kpmXCOBh3gX9dNYdjCpEbigWs326r6OVKvdlQn7TSKHkcCcKt4MNJAd5DQSuI83Ud87uJ15jL8oYYTf2cE3f2YH1wuMhXJGAtdU8+WnwtlBaSOBu3gVjZc9O5iWEapJ/wSf6zEHeI6bZzWYmY6u/4v+rzUirZ/snVh+hwPitpYFxNanKJ1IGk9L4xcz6Eom18bqg5ZtrDqx1Y2LDwPVG2lV8aH15aDWF+jOKpkWi8o5GKWIXTwq56BzxwqdOejpxNFbJw5DO3M83dPT02J+AbN50HbYDxzCAAAAAElFTkSuQmCC'
|
||||
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')
|
||||
|
||||
# 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)] ]
|
||||
|
||||
# Create the window
|
||||
window = sg.Window('Simple Base64 Buttons', 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
|
||||
break
|
||||
window.close() # Exiting so clean up
|
|
@ -1,44 +1,50 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
import time
|
||||
import PySimpleGUI as sg
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
def show_win():
|
||||
sg.set_options(border_width=0, margins=(0, 0), element_padding=(5, 3))
|
||||
sg.SetOptions(border_width=0, margins=(0,0), element_padding=(5,3))
|
||||
|
||||
frame_layout = [
|
||||
[sg.Button(image_data=mac_red,
|
||||
button_color=(sg.theme_background_color(),sg.theme_background_color()), key='-exit-'),
|
||||
sg.Button('', image_data=mac_orange,
|
||||
button_color=(sg.theme_background_color(),sg.theme_background_color())),
|
||||
sg.Button('', image_data=mac_green,
|
||||
button_color=(sg.theme_background_color(),sg.theme_background_color()), key='-minimize-'),
|
||||
sg.Text(' '*40)], ]
|
||||
|
||||
layout = [[sg.Frame('', frame_layout)],
|
||||
[sg.Text('')],
|
||||
[sg.Text('My Mac-alike window', size=(25, 2))], ]
|
||||
frame_layout = [ [sg.Button('', image_data=mac_red, button_color=('white', sg.COLOR_SYSTEM_DEFAULT), key='_exit_'),
|
||||
sg.Button('', image_data=mac_orange, button_color=('white', sg.COLOR_SYSTEM_DEFAULT)),
|
||||
sg.Button('', image_data=mac_green, button_color=('white', sg.COLOR_SYSTEM_DEFAULT), key='_minimize_'),
|
||||
sg.Text(' '*40)],]
|
||||
|
||||
window = sg.Window('My new window', layout,
|
||||
no_titlebar=True, grab_anywhere=True,
|
||||
alpha_channel=0, finalize=True)
|
||||
layout = [[sg.Frame('',frame_layout)],
|
||||
[sg.T('')],
|
||||
[ sg.Text(' My Mac-alike window', size=(25,2)) ],]
|
||||
|
||||
window = sg.Window('My new window',
|
||||
no_titlebar=True,
|
||||
grab_anywhere=True,
|
||||
alpha_channel=0,
|
||||
).Layout(layout).Finalize()
|
||||
|
||||
for i in range(100):
|
||||
window.set_alpha(i/100)
|
||||
window.SetAlpha(i/100)
|
||||
time.sleep(.01)
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window.read()
|
||||
if event == sg.WIN_CLOSED or event == '-exit-':
|
||||
event, values = window.Read()
|
||||
if event is None or event == '_exit_':
|
||||
break
|
||||
if event == '-minimize-':
|
||||
if event == '_minimize_':
|
||||
# window.Minimize() # cannot minimize a window with no titlebar
|
||||
pass
|
||||
print(event, values)
|
||||
|
||||
|
||||
|
||||
mac_red = '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'
|
||||
|
||||
mac_green = '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'
|
||||
|
||||
mac_orange = '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'
|
||||
show_win()
|
||||
|
||||
|
||||
show_win()
|
|
@ -1,54 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
Demo - Realtime Buttons
|
||||
|
||||
Realtime buttons provide a way for you to get a continuous stream of button
|
||||
events for as long as a button is held down.
|
||||
|
||||
This demo is using a timeout to determine that a button has been released.
|
||||
If your application doesn't care when a button is released and only needs to know
|
||||
that it's being held down, then you can remove the timeout on the window read call.
|
||||
|
||||
Note that your reaction latency will be the same as your timeout value. In this demo
|
||||
the timeout is 100, so there will be 100ms between releasing a button and your program detecting
|
||||
this has happened.
|
||||
|
||||
Copyright 2021 PySimpleGUI
|
||||
"""
|
||||
|
||||
import PySimpleGUI as sg
|
||||
|
||||
def main():
|
||||
# The Quit button is being placed in the bottom right corner and the colors are inverted, just for fun
|
||||
layout = [[sg.Text('Robotics Remote Control')],
|
||||
[sg.Text('Hold Down Button To Move')],
|
||||
[sg.Text()],
|
||||
[sg.Text(' '),
|
||||
sg.RealtimeButton(sg.SYMBOL_UP, key='-FORWARD-')],
|
||||
[sg.RealtimeButton(sg.SYMBOL_LEFT, key='-LEFT-'),
|
||||
sg.Text(size=(10,1), key='-STATUS-', justification='c', pad=(0,0)),
|
||||
sg.RealtimeButton(sg.SYMBOL_RIGHT, key='-RIGHT-')],
|
||||
[sg.Text(' '),
|
||||
sg.RealtimeButton(sg.SYMBOL_DOWN, key='-DOWN-')],
|
||||
[sg.Text()],
|
||||
[sg.Column([[sg.Quit(button_color=(sg.theme_button_color()[1], sg.theme_button_color()[0]), focus=True)]], justification='r')]]
|
||||
|
||||
window = sg.Window('Robotics Remote Control', layout)
|
||||
|
||||
while True:
|
||||
# This is the code that reads and updates your window
|
||||
event, values = window.read(timeout=100)
|
||||
if event in (sg.WIN_CLOSED, 'Quit'):
|
||||
break
|
||||
if event != sg.TIMEOUT_EVENT:
|
||||
# if not a timeout event, then it's a button that's being held down
|
||||
window['-STATUS-'].update(event)
|
||||
else:
|
||||
# A timeout signals that all buttons have been released so clear the status display
|
||||
window['-STATUS-'].update('')
|
||||
|
||||
window.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
sg.theme('dark red')
|
||||
main()
|
|
@ -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])
|
|
@ -1,24 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
"""
|
||||
Simple test harness to demonstate how to use the CalendarButton and the get date popup
|
||||
"""
|
||||
# sg.theme('Dark Red')
|
||||
layout = [[sg.Text('Date Chooser Test Harness', key='-TXT-')],
|
||||
[sg.Input(key='-IN-', size=(20,1)), sg.CalendarButton('Cal US No Buttons Location (0,0)', close_when_date_chosen=True, target='-IN-', location=(0,0), no_titlebar=False, )],
|
||||
[sg.Input(key='-IN3-', size=(20,1)), sg.CalendarButton('Cal Monday', title='Pick a date any date', no_titlebar=True, close_when_date_chosen=False, target='-IN3-', begin_at_sunday_plus=1, month_names=('студзень', 'люты', 'сакавік', 'красавік', 'май', 'чэрвень', 'ліпень', 'жнівень', 'верасень', 'кастрычнік', 'лістапад', 'снежань'), day_abbreviations=('Дш', 'Шш', 'Шр', 'Бш', 'Жм', 'Иш', 'Жш'))],
|
||||
[sg.Input(key='-IN2-', size=(20,1)), sg.CalendarButton('Cal German Feb 2020', target='-IN2-', default_date_m_d_y=(2,None,2020), locale='de_DE', begin_at_sunday_plus=1 )],
|
||||
[sg.Input(key='-IN4-', size=(20,1)), sg.CalendarButton('Cal Format %m-%d Jan 2020', target='-IN4-', format='%m-%d', default_date_m_d_y=(1,None,2020), )],
|
||||
[sg.Button('Read'), sg.Button('Date Popup'), sg.Exit()]]
|
||||
layout = [[sg.T('Calendar Test')],
|
||||
[sg.In('', size=(20,1), key='input')],
|
||||
[sg.CalendarButton('Choose Date', target='input', key='date')],
|
||||
[sg.Ok(key=1)]]
|
||||
|
||||
window = sg.Window('window', layout)
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
print(event, values)
|
||||
if event in (sg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
elif event == 'Date Popup':
|
||||
sg.popup('You chose:', sg.popup_get_date())
|
||||
window.close()
|
||||
window = sg.Window('Calendar', grab_anywhere=False).Layout(layout)
|
||||
event,values = window.Read()
|
||||
sg.Popup(values['input'])
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
layout = [
|
||||
[sg.Canvas(size=(150, 150), background_color='red', key='canvas')],
|
||||
[sg.Text('Change circle color to:'), sg.Button('Red'), sg.Button('Blue')]
|
||||
]
|
||||
[sg.Canvas(size=(150, 150), background_color='red', key='canvas')],
|
||||
[sg.T('Change circle color to:'), sg.ReadButton('Red'), sg.ReadButton('Blue')]
|
||||
]
|
||||
|
||||
window = sg.Window('Canvas test', layout, finalize=True)
|
||||
window = sg.Window('Canvas test').Layout(layout).Finalize()
|
||||
|
||||
cir = window['canvas'].TKCanvas.create_oval(50, 50, 100, 100)
|
||||
cir = window.FindElement('canvas').TKCanvas.create_oval(50, 50, 100, 100)
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event == sg.WIN_CLOSED:
|
||||
event, values = window.Read()
|
||||
if event is None:
|
||||
break
|
||||
if event in ('Blue', 'Red'):
|
||||
window['canvas'].TKCanvas.itemconfig(cir, fill=event)
|
||||
if event is 'Blue':
|
||||
window.FindElement('canvas').TKCanvas.itemconfig(cir, fill = "Blue")
|
||||
elif event is 'Red':
|
||||
window.FindElement('canvas').TKCanvas.itemconfig(cir, fill = "Red")
|
||||
|
|
48
DemoPrograms/Demo_Change_Submits_InputText.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
"""
|
||||
Demonstrates the new change_submits parameter for inputtext elements
|
||||
It ONLY submits when a button changes the field, not normal user input
|
||||
Be careful on persistent forms to not clear the input
|
||||
"""
|
||||
layout = [[ sg.Text('Test of reading input field') ],
|
||||
[sg.T('This input is normal'), sg.In()],
|
||||
[sg.T('This input change submits'), sg.In(change_submits=True)],
|
||||
[sg.T('This multiline input change submits'), sg.Multiline(change_submits=True, do_not_clear=True)],
|
||||
[sg.T('This input is normal'), sg.In(), sg.FileBrowse()],
|
||||
[sg.T('File Browse submits'), sg.In(change_submits=True,
|
||||
do_not_clear=True,
|
||||
key='_in1_'), sg.FileBrowse()],
|
||||
[sg.T('Color Chooser submits'), sg.In(change_submits=True,
|
||||
do_not_clear=True,
|
||||
key='_in2_'), sg.ColorChooserButton('Color...', target=(sg.ThisRow, -1))],
|
||||
[sg.T('Folder Browse submits'), sg.In(change_submits=True,
|
||||
do_not_clear=True,
|
||||
key='_in3_'), sg.FolderBrowse()],
|
||||
[sg.T('Calendar Chooser submits'), sg.In(change_submits=True,
|
||||
do_not_clear=True,
|
||||
key='_in4_'), sg.CalendarButton('Date...', target=(sg.ThisRow, -1))],
|
||||
[sg.T('Disabled input submits'), sg.In(change_submits=True,
|
||||
do_not_clear=True,
|
||||
disabled=True,
|
||||
key='_in5'), sg.FileBrowse()],
|
||||
[sg.T('This input clears after submit'),sg.In(change_submits=True,
|
||||
key='_in6_'), sg.FileBrowse()],
|
||||
[ sg.Button('Read')]]
|
||||
|
||||
window = sg.Window('Demonstration of InputText with change_submits',
|
||||
auto_size_text=False,
|
||||
default_element_size=(22,1),
|
||||
text_justification='right',
|
||||
).Layout(layout)
|
||||
|
||||
while True: # Event Loop
|
||||
event, values = window.Read()
|
||||
print(event, values)
|
||||
if event is None:
|
||||
break
|
|
@ -1,31 +1,41 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 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
|
||||
A chat window. Add call to your send-routine, print the response and you're done
|
||||
|
||||
Copyright 2023 PySimpleGUI
|
||||
To see this program RUN on the web go here:
|
||||
https://repl.it/@PySimpleGUI/Chat-Application-Demo
|
||||
|
||||
Note that the size of the display on repl.it is smaller than most, so the sizes of the
|
||||
Multiline and Output text areas were reduced in the online version. Nothing else was changed
|
||||
'''
|
||||
|
||||
sg.theme('GreenTan') # give our window a spiffy set of colors
|
||||
sg.ChangeLookAndFeel('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.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]))]]
|
||||
layout = [ [sg.Text('Your output will go here', size=(40, 1))],
|
||||
[sg.Output(size=(127, 30), font=('Helvetica 10'))],
|
||||
[sg.Multiline(size=(85, 5), enter_submits=True, key='query'),
|
||||
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)
|
||||
window = sg.Window('Chat window',
|
||||
default_element_size=(30, 2),
|
||||
font=('Helvetica',' 13'),
|
||||
default_button_element_size=(8,2)).Layout(layout)
|
||||
|
||||
while True: # The Event Loop
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'EXIT'): # quit if exit button or X
|
||||
break
|
||||
if event == 'SEND':
|
||||
query = values['-QUERY-'].rstrip()
|
||||
# ---===--- Loop taking in user input and using it --- #
|
||||
while True:
|
||||
event, value = window.Read()
|
||||
if event is 'SEND':
|
||||
query = value['query'].rstrip()
|
||||
# EXECUTE YOUR COMMAND HERE
|
||||
print('The command you entered was {}'.format(query), flush=True)
|
||||
print('The command you entered was {}'.format(query))
|
||||
elif event in (None, 'EXIT'): # quit if exit button or X
|
||||
break
|
||||
sys.exit(69)
|
||||
|
||||
window.close()
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
'''
|
||||
A chatbot with history
|
||||
|
@ -11,60 +15,46 @@ Special keyboard keys:
|
|||
Control C - exit form
|
||||
'''
|
||||
|
||||
|
||||
def ChatBotWithHistory():
|
||||
# ------- Make a new Window ------- #
|
||||
# give our form a spiffy set of colors
|
||||
sg.theme('GreenTan')
|
||||
sg.ChangeLookAndFeel('GreenTan') # give our form a spiffy set of colors
|
||||
|
||||
layout = [[sg.Text('Your output will go here', size=(40, 1))],
|
||||
[sg.Output(size=(127, 30), font=('Helvetica 10'))],
|
||||
[sg.Text('Command History'),
|
||||
sg.Text('', size=(20, 3), key='history')],
|
||||
[sg.ML(size=(85, 5), enter_submits=True, 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]))]]
|
||||
layout = [[sg.Text('Your output will go here', size=(40, 1))],
|
||||
[sg.Output(size=(127, 30), font=('Helvetica 10'))],
|
||||
[sg.T('Command History'), sg.T('', size=(20,3), key='history')],
|
||||
[sg.Multiline(size=(85, 5), enter_submits=True, key='query', do_not_clear=False),
|
||||
sg.ReadButton('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 with history', layout,
|
||||
default_element_size=(30, 2),
|
||||
font=('Helvetica', ' 13'),
|
||||
default_button_element_size=(8, 2),
|
||||
return_keyboard_events=True)
|
||||
window = sg.Window('Chat window with history', default_element_size=(30, 2), font=('Helvetica',' 13'), default_button_element_size=(8,2), return_keyboard_events=True).Layout(layout)
|
||||
|
||||
# ---===--- Loop taking in user input and using it --- #
|
||||
command_history = []
|
||||
history_offset = 0
|
||||
|
||||
while True:
|
||||
event, value = window.read()
|
||||
|
||||
if event == 'SEND':
|
||||
(event, value) = window.Read()
|
||||
if event is 'SEND':
|
||||
query = value['query'].rstrip()
|
||||
# EXECUTE YOUR COMMAND HERE
|
||||
print('The command you entered was {}'.format(query))
|
||||
command_history.append(query)
|
||||
history_offset = len(command_history)-1
|
||||
# manually clear input because keyboard events blocks clear
|
||||
window['query'].update('')
|
||||
window['history'].update('\n'.join(command_history[-3:]))
|
||||
|
||||
elif event in (sg.WIN_CLOSED, 'EXIT'): # quit if exit event or X
|
||||
window.FindElement('query').Update('') # manually clear input because keyboard events blocks clear
|
||||
window.FindElement('history').Update('\n'.join(command_history[-3:]))
|
||||
elif event is None or event is 'EXIT': # quit if exit event or X
|
||||
break
|
||||
|
||||
elif 'Up' in event and len(command_history):
|
||||
command = command_history[history_offset]
|
||||
# decrement is not zero
|
||||
history_offset -= 1 * (history_offset > 0)
|
||||
window['query'].update(command)
|
||||
|
||||
history_offset -= 1 * (history_offset > 0) # decrement is not zero
|
||||
window.FindElement('query').Update(command)
|
||||
elif 'Down' in event and len(command_history):
|
||||
# increment up to end of list
|
||||
history_offset += 1 * (history_offset < len(command_history)-1)
|
||||
history_offset += 1 * (history_offset < len(command_history)-1) # increment up to end of list
|
||||
command = command_history[history_offset]
|
||||
window['query'].update(command)
|
||||
|
||||
window.FindElement('query').Update(command)
|
||||
elif 'Escape' in event:
|
||||
window['query'].update('')
|
||||
window.FindElement('query').Update('')
|
||||
|
||||
sys.exit(69)
|
||||
|
||||
|
||||
ChatBotWithHistory()
|
||||
|
|
|
@ -1,99 +1,76 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
from chatterbot import ChatBot
|
||||
import chatterbot.utils
|
||||
|
||||
|
||||
'''
|
||||
Demo_Chatterbot.py
|
||||
|
||||
Note - this code was written using version 0.8.7 of Chatterbot... to install:
|
||||
|
||||
python -m pip install chatterbot==0.8.7
|
||||
|
||||
It still runs fine with the old version.
|
||||
|
||||
A GUI wrapped arouind the Chatterbot package.
|
||||
The GUI is used to show progress bars during the training process and
|
||||
The GUI is used to show progress bars during the training process and
|
||||
to collect user input that is sent to the chatbot. The reply is displayed in the GUI window
|
||||
'''
|
||||
|
||||
# Create the 'Trainer GUI'
|
||||
# The Trainer GUI consists of a lot of progress bars stacked on top of each other
|
||||
sg.theme('GreenTan')
|
||||
sg.ChangeLookAndFeel('GreenTan')
|
||||
# sg.DebugWin()
|
||||
MAX_PROG_BARS = 20 # number of training sessions
|
||||
bars = []
|
||||
texts = []
|
||||
training_layout = [[sg.Text('TRAINING PROGRESS', size=(20, 1), font=('Helvetica', 17))]]
|
||||
training_layout = [[sg.T('TRAINING PROGRESS', size=(20, 1), font=('Helvetica', 17))], ]
|
||||
for i in range(MAX_PROG_BARS):
|
||||
bars.append(sg.ProgressBar(100, size=(30, 4)))
|
||||
texts.append(sg.Text(' ' * 20, size=(20, 1), justification='right'))
|
||||
training_layout += [[texts[i], bars[i]], ] # add a single row
|
||||
texts.append(sg.T(' ' * 20, size=(20, 1), justification='right'))
|
||||
training_layout += [[texts[i], bars[i]],] # add a single row
|
||||
|
||||
training_window = sg.Window('Training', training_layout)
|
||||
training_window = sg.Window('Training').Layout(training_layout)
|
||||
current_bar = 0
|
||||
|
||||
# callback function for training runs
|
||||
|
||||
|
||||
def print_progress_bar(description, iteration_counter, total_items, progress_bar_length=20):
|
||||
global current_bar
|
||||
global bars
|
||||
global texts
|
||||
global training_window
|
||||
# update the window and the bars
|
||||
button, values = training_window.read(timeout=0)
|
||||
button, values = training_window.Read(timeout=0)
|
||||
if button is None: # if user closed the window on us, exit
|
||||
return
|
||||
sys.exit(69)
|
||||
if bars[current_bar].UpdateBar(iteration_counter, max=total_items) is False:
|
||||
return
|
||||
# show the training dataset name
|
||||
texts[current_bar].update(description)
|
||||
sys.exit(69)
|
||||
texts[current_bar].Update(description) # show the training dataset name
|
||||
if iteration_counter == total_items:
|
||||
current_bar += 1
|
||||
|
||||
|
||||
# redefine the chatbot text based progress bar with a graphical one
|
||||
chatterbot.utils.print_progress_bar = print_progress_bar
|
||||
|
||||
|
||||
from chatterbot import ChatBot
|
||||
from chatterbot.trainers import ChatterBotCorpusTrainer
|
||||
|
||||
chatbot = ChatBot('Ron Obvious')
|
||||
|
||||
# Create a new trainer for the chatbot
|
||||
trainer = ChatterBotCorpusTrainer(chatbot)
|
||||
|
||||
# Train based on the english corpus
|
||||
trainer.train("chatterbot.corpus.english")
|
||||
|
||||
# Train based on english greetings corpus
|
||||
trainer.train("chatterbot.corpus.english.greetings")
|
||||
|
||||
# Train based on the english conversations corpus
|
||||
trainer.train("chatterbot.corpus.english.conversations")
|
||||
chatbot = ChatBot('Ron Obvious', trainer='chatterbot.trainers.ChatterBotCorpusTrainer')
|
||||
|
||||
# Train based on the english corpus
|
||||
# chatbot.train("chatterbot.corpus.english")
|
||||
chatbot.train("chatterbot.corpus.english")
|
||||
|
||||
################# GUI #################
|
||||
|
||||
layout = [[sg.Multiline(size=(80, 20), reroute_stdout=True, echo_stdout_stderr=True)],
|
||||
[sg.MLine(size=(70, 5), key='-MLINE IN-', enter_submits=True, do_not_clear=False),
|
||||
layout = [[sg.Output(size=(80, 20))],
|
||||
[sg.Multiline(size=(70, 5), enter_submits=True),
|
||||
sg.Button('SEND', bind_return_key=True), sg.Button('EXIT')]]
|
||||
|
||||
window = sg.Window('Chat Window', layout,
|
||||
default_element_size=(30, 2))
|
||||
window = sg.Window('Chat Window', auto_size_text=True, default_element_size=(30, 2)).Layout(layout)
|
||||
|
||||
# ---===--- Loop taking in user input and using it to query HowDoI web oracle --- #
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event != 'SEND':
|
||||
event, (value,) = window.Read()
|
||||
if event is not 'SEND':
|
||||
break
|
||||
string = values['-MLINE IN-'].rstrip()
|
||||
print(' ' + string)
|
||||
string = value.rstrip()
|
||||
print(' '+string)
|
||||
# send the user input to chatbot to get a response
|
||||
response = chatbot.get_response(values['-MLINE IN-'].rstrip())
|
||||
print(response)
|
||||
response = chatbot.get_response(value.rstrip())
|
||||
print(response)
|
|
@ -1,7 +1,13 @@
|
|||
#!/usr/bin/env python
|
||||
import PySimpleGUI as sg
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
import PySimpleGUI as sg
|
||||
else:
|
||||
import PySimpleGUI27 as sg
|
||||
|
||||
from chatterbot import ChatBot
|
||||
import chatterbot.utils
|
||||
|
||||
from gtts import gTTS
|
||||
from pygame import mixer
|
||||
import time
|
||||
|
@ -9,33 +15,25 @@ import os
|
|||
|
||||
'''
|
||||
Demo_Chatterbot.py
|
||||
|
||||
|
||||
Note - this code was written using version 0.8.7 of Chatterbot... to install:
|
||||
|
||||
python -m pip install chatterbot==0.8.7
|
||||
|
||||
It still runs fine with the old version.
|
||||
|
||||
A GUI wrapped arouind the Chatterbot package.
|
||||
The GUI is used to show progress bars during the training process and
|
||||
The GUI is used to show progress bars during the training process and
|
||||
to collect user input that is sent to the chatbot. The reply is displayed in the GUI window
|
||||
'''
|
||||
|
||||
# Create the 'Trainer GUI'
|
||||
# The Trainer GUI consists of a lot of progress bars stacked on top of each other
|
||||
sg.theme('NeutralBlue')
|
||||
sg.ChangeLookAndFeel('NeutralBlue')
|
||||
# sg.DebugWin()
|
||||
MAX_PROG_BARS = 20 # number of training sessions
|
||||
bars = []
|
||||
texts = []
|
||||
training_layout = [[sg.Text('TRAINING PROGRESS', size=(20, 1), font=('Helvetica', 17))], ]
|
||||
training_layout = [[sg.T('TRAINING PROGRESS', size=(20, 1), font=('Helvetica', 17))], ]
|
||||
for i in range(MAX_PROG_BARS):
|
||||
bars.append(sg.ProgressBar(100, size=(30, 4)))
|
||||
texts.append(sg.Text(' ' * 20, size=(20, 1), justification='right'))
|
||||
texts.append(sg.T(' ' * 20, size=(20, 1), justification='right'))
|
||||
training_layout += [[texts[i], bars[i]],] # add a single row
|
||||
|
||||
training_window = sg.Window('Training', training_layout)
|
||||
training_window = sg.Window('Training').Layout(training_layout)
|
||||
current_bar = 0
|
||||
|
||||
# callback function for training runs
|
||||
|
@ -45,12 +43,12 @@ def print_progress_bar(description, iteration_counter, total_items, progress_bar
|
|||
global texts
|
||||
global training_window
|
||||
# update the window and the bars
|
||||
button, values = training_window.read(timeout=0)
|
||||
button, values = training_window.Read(timeout=0)
|
||||
if button is None: # if user closed the window on us, exit
|
||||
return
|
||||
if bars[current_bar].update_bar(iteration_counter, max=total_items) is False:
|
||||
return
|
||||
texts[current_bar].update(description) # show the training dataset name
|
||||
sys.exit(69)
|
||||
if bars[current_bar].UpdateBar(iteration_counter, max=total_items) is False:
|
||||
sys.exit(69)
|
||||
texts[current_bar].Update(description) # show the training dataset name
|
||||
if iteration_counter == total_items:
|
||||
current_bar += 1
|
||||
|
||||
|
@ -80,22 +78,20 @@ chatbot.train("chatterbot.corpus.english")
|
|||
|
||||
################# GUI #################
|
||||
|
||||
layout = [[sg.Multiline(size=(80, 20), reroute_stdout=True, echo_stdout_stderr=True)],
|
||||
[sg.MLine(size=(70, 5), key='-MLINE IN-', enter_submits=True, do_not_clear=False),
|
||||
layout = [[sg.Output(size=(80, 20))],
|
||||
[sg.Multiline(size=(70, 5), enter_submits=True),
|
||||
sg.Button('SEND', bind_return_key=True), sg.Button('EXIT')]]
|
||||
|
||||
window = sg.Window('Chat Window', layout,
|
||||
default_element_size=(30, 2))
|
||||
window = sg.Window('Chat Window', auto_size_text=True, default_element_size=(30, 2)).Layout(layout)
|
||||
|
||||
# ---===--- Loop taking in user input and using it to query HowDoI web oracle --- #
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event != 'SEND':
|
||||
event, (value,) = window.Read()
|
||||
if event is not 'SEND':
|
||||
break
|
||||
string = values['-MLINE IN-'].rstrip()
|
||||
print(' ' + string)
|
||||
string = value.rstrip()
|
||||
print(' '+string)
|
||||
# send the user input to chatbot to get a response
|
||||
response = chatbot.get_response(values['-MLINE IN-'].rstrip())
|
||||
response = chatbot.get_response(value.rstrip())
|
||||
print(response)
|
||||
|
||||
window.close()
|
||||
speak(str(response))
|
|
@ -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()
|
|
@ -1,103 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
|
||||
"""
|
||||
Demo - Class wrapper
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
'''
|
||||
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):
|
||||
self.layout = [ [sg.Text('My layout')],
|
||||
[sg.Input(key='-IN-')],
|
||||
[sg.Button('Go'), sg.Button('Exit')] ]
|
||||
|
||||
self.window = sg.Window('My new window', self.layout)
|
||||
|
||||
def run(self):
|
||||
while True: # Event Loop
|
||||
self.event, self.values = self.window.read()
|
||||
if self.event in (sg.WIN_CLOSED, 'Exit'):
|
||||
break
|
||||
|
||||
if self.event == 'Go':
|
||||
self.button_go()
|
||||
|
||||
self.window.close()
|
||||
|
||||
def button_go(self):
|
||||
sg.popup('Go button clicked', 'Input value:', self.values['-IN-'])
|
||||
|
||||
# Create the class
|
||||
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,24 +0,0 @@
|
|||
"""
|
||||
Demo_Close_Attempted_Event
|
||||
|
||||
Catches if a window close was tried by user (click "X") and confirms with a popup.
|
||||
Requires PySimpleGUI 4.33.0 and later
|
||||
|
||||
Copyright 2021 PySimpleGUI Inc.
|
||||
"""
|
||||
|
||||
import PySimpleGUI as sg
|
||||
|
||||
layout = [[sg.Text('Close confirmation demo')],
|
||||
[sg.Text('Try closing window with the "X"')],
|
||||
[sg.Button('Go'), sg.Button('Exit')]]
|
||||
|
||||
window = sg.Window('Window Title', layout, enable_close_attempted_event=True)
|
||||
|
||||
while True:
|
||||
event, values = window.read()
|
||||
print(event, values)
|
||||
if (event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT or event == 'Exit') and sg.popup_yes_no('Do you really want to exit?') == 'Yes':
|
||||
break
|
||||
|
||||
window.close()
|
1728
DemoPrograms/Demo_Color.py
Normal file
|
@ -1,719 +0,0 @@
|
|||
import PySimpleGUI as sg
|
||||
|
||||
|
||||
def popup_color_chooser(look_and_feel=None):
|
||||
"""
|
||||
|
||||
:return: Any(str, None) Returns hex string of color chosen or None if nothing was chosen
|
||||
"""
|
||||
color_map = {
|
||||
'alice blue': '#F0F8FF',
|
||||
'AliceBlue': '#F0F8FF',
|
||||
'antique white': '#FAEBD7',
|
||||
'AntiqueWhite': '#FAEBD7',
|
||||
'AntiqueWhite1': '#FFEFDB',
|
||||
'AntiqueWhite2': '#EEDFCC',
|
||||
'AntiqueWhite3': '#CDC0B0',
|
||||
'AntiqueWhite4': '#8B8378',
|
||||
'aquamarine': '#7FFFD4',
|
||||
'aquamarine1': '#7FFFD4',
|
||||
'aquamarine2': '#76EEC6',
|
||||
'aquamarine3': '#66CDAA',
|
||||
'aquamarine4': '#458B74',
|
||||
'azure': '#F0FFFF',
|
||||
'azure1': '#F0FFFF',
|
||||
'azure2': '#E0EEEE',
|
||||
'azure3': '#C1CDCD',
|
||||
'azure4': '#838B8B',
|
||||
'beige': '#F5F5DC',
|
||||
'bisque': '#FFE4C4',
|
||||
'bisque1': '#FFE4C4',
|
||||
'bisque2': '#EED5B7',
|
||||
'bisque3': '#CDB79E',
|
||||
'bisque4': '#8B7D6B',
|
||||
'black': '#000000',
|
||||
'blanched almond': '#FFEBCD',
|
||||
'BlanchedAlmond': '#FFEBCD',
|
||||
'blue': '#0000FF',
|
||||
'blue violet': '#8A2BE2',
|
||||
'blue1': '#0000FF',
|
||||
'blue2': '#0000EE',
|
||||
'blue3': '#0000CD',
|
||||
'blue4': '#00008B',
|
||||
'BlueViolet': '#8A2BE2',
|
||||
'brown': '#A52A2A',
|
||||
'brown1': '#FF4040',
|
||||
'brown2': '#EE3B3B',
|
||||
'brown3': '#CD3333',
|
||||
'brown4': '#8B2323',
|
||||
'burlywood': '#DEB887',
|
||||
'burlywood1': '#FFD39B',
|
||||
'burlywood2': '#EEC591',
|
||||
'burlywood3': '#CDAA7D',
|
||||
'burlywood4': '#8B7355',
|
||||
'cadet blue': '#5F9EA0',
|
||||
'CadetBlue': '#5F9EA0',
|
||||
'CadetBlue1': '#98F5FF',
|
||||
'CadetBlue2': '#8EE5EE',
|
||||
'CadetBlue3': '#7AC5CD',
|
||||
'CadetBlue4': '#53868B',
|
||||
'chartreuse': '#7FFF00',
|
||||
'chartreuse1': '#7FFF00',
|
||||
'chartreuse2': '#76EE00',
|
||||
'chartreuse3': '#66CD00',
|
||||
'chartreuse4': '#458B00',
|
||||
'chocolate': '#D2691E',
|
||||
'chocolate1': '#FF7F24',
|
||||
'chocolate2': '#EE7621',
|
||||
'chocolate3': '#CD661D',
|
||||
'chocolate4': '#8B4513',
|
||||
'coral': '#FF7F50',
|
||||
'coral1': '#FF7256',
|
||||
'coral2': '#EE6A50',
|
||||
'coral3': '#CD5B45',
|
||||
'coral4': '#8B3E2F',
|
||||
'cornflower blue': '#6495ED',
|
||||
'CornflowerBlue': '#6495ED',
|
||||
'cornsilk': '#FFF8DC',
|
||||
'cornsilk1': '#FFF8DC',
|
||||
'cornsilk2': '#EEE8CD',
|
||||
'cornsilk3': '#CDC8B1',
|
||||
'cornsilk4': '#8B8878',
|
||||
'cyan': '#00FFFF',
|
||||
'cyan1': '#00FFFF',
|
||||
'cyan2': '#00EEEE',
|
||||
'cyan3': '#00CDCD',
|
||||
'cyan4': '#008B8B',
|
||||
'dark blue': '#00008B',
|
||||
'dark cyan': '#008B8B',
|
||||
'dark goldenrod': '#B8860B',
|
||||
'dark gray': '#A9A9A9',
|
||||
'dark green': '#006400',
|
||||
'dark grey': '#A9A9A9',
|
||||
'dark khaki': '#BDB76B',
|
||||
'dark magenta': '#8B008B',
|
||||
'dark olive green': '#556B2F',
|
||||
'dark orange': '#FF8C00',
|
||||
'dark orchid': '#9932CC',
|
||||
'dark red': '#8B0000',
|
||||
'dark salmon': '#E9967A',
|
||||
'dark sea green': '#8FBC8F',
|
||||
'dark slate blue': '#483D8B',
|
||||
'dark slate gray': '#2F4F4F',
|
||||
'dark slate grey': '#2F4F4F',
|
||||
'dark turquoise': '#00CED1',
|
||||
'dark violet': '#9400D3',
|
||||
'DarkBlue': '#00008B',
|
||||
'DarkCyan': '#008B8B',
|
||||
'DarkGoldenrod': '#B8860B',
|
||||
'DarkGoldenrod1': '#FFB90F',
|
||||
'DarkGoldenrod2': '#EEAD0E',
|
||||
'DarkGoldenrod3': '#CD950C',
|
||||
'DarkGoldenrod4': '#8B6508',
|
||||
'DarkGray': '#A9A9A9',
|
||||
'DarkGreen': '#006400',
|
||||
'DarkGrey': '#A9A9A9',
|
||||
'DarkKhaki': '#BDB76B',
|
||||
'DarkMagenta': '#8B008B',
|
||||
'DarkOliveGreen': '#556B2F',
|
||||
'DarkOliveGreen1': '#CAFF70',
|
||||
'DarkOliveGreen2': '#BCEE68',
|
||||
'DarkOliveGreen3': '#A2CD5A',
|
||||
'DarkOliveGreen4': '#6E8B3D',
|
||||
'DarkOrange': '#FF8C00',
|
||||
'DarkOrange1': '#FF7F00',
|
||||
'DarkOrange2': '#EE7600',
|
||||
'DarkOrange3': '#CD6600',
|
||||
'DarkOrange4': '#8B4500',
|
||||
'DarkOrchid': '#9932CC',
|
||||
'DarkOrchid1': '#BF3EFF',
|
||||
'DarkOrchid2': '#B23AEE',
|
||||
'DarkOrchid3': '#9A32CD',
|
||||
'DarkOrchid4': '#68228B',
|
||||
'DarkRed': '#8B0000',
|
||||
'DarkSalmon': '#E9967A',
|
||||
'DarkSeaGreen': '#8FBC8F',
|
||||
'DarkSeaGreen1': '#C1FFC1',
|
||||
'DarkSeaGreen2': '#B4EEB4',
|
||||
'DarkSeaGreen3': '#9BCD9B',
|
||||
'DarkSeaGreen4': '#698B69',
|
||||
'DarkSlateBlue': '#483D8B',
|
||||
'DarkSlateGray': '#2F4F4F',
|
||||
'DarkSlateGray1': '#97FFFF',
|
||||
'DarkSlateGray2': '#8DEEEE',
|
||||
'DarkSlateGray3': '#79CDCD',
|
||||
'DarkSlateGray4': '#528B8B',
|
||||
'DarkSlateGrey': '#2F4F4F',
|
||||
'DarkTurquoise': '#00CED1',
|
||||
'DarkViolet': '#9400D3',
|
||||
'deep pink': '#FF1493',
|
||||
'deep sky blue': '#00BFFF',
|
||||
'DeepPink': '#FF1493',
|
||||
'DeepPink1': '#FF1493',
|
||||
'DeepPink2': '#EE1289',
|
||||
'DeepPink3': '#CD1076',
|
||||
'DeepPink4': '#8B0A50',
|
||||
'DeepSkyBlue': '#00BFFF',
|
||||
'DeepSkyBlue1': '#00BFFF',
|
||||
'DeepSkyBlue2': '#00B2EE',
|
||||
'DeepSkyBlue3': '#009ACD',
|
||||
'DeepSkyBlue4': '#00688B',
|
||||
'dim gray': '#696969',
|
||||
'dim grey': '#696969',
|
||||
'DimGray': '#696969',
|
||||
'DimGrey': '#696969',
|
||||
'dodger blue': '#1E90FF',
|
||||
'DodgerBlue': '#1E90FF',
|
||||
'DodgerBlue1': '#1E90FF',
|
||||
'DodgerBlue2': '#1C86EE',
|
||||
'DodgerBlue3': '#1874CD',
|
||||
'DodgerBlue4': '#104E8B',
|
||||
'firebrick': '#B22222',
|
||||
'firebrick1': '#FF3030',
|
||||
'firebrick2': '#EE2C2C',
|
||||
'firebrick3': '#CD2626',
|
||||
'firebrick4': '#8B1A1A',
|
||||
'floral white': '#FFFAF0',
|
||||
'FloralWhite': '#FFFAF0',
|
||||
'forest green': '#228B22',
|
||||
'ForestGreen': '#228B22',
|
||||
'gainsboro': '#DCDCDC',
|
||||
'ghost white': '#F8F8FF',
|
||||
'GhostWhite': '#F8F8FF',
|
||||
'gold': '#FFD700',
|
||||
'gold1': '#FFD700',
|
||||
'gold2': '#EEC900',
|
||||
'gold3': '#CDAD00',
|
||||
'gold4': '#8B7500',
|
||||
'goldenrod': '#DAA520',
|
||||
'goldenrod1': '#FFC125',
|
||||
'goldenrod2': '#EEB422',
|
||||
'goldenrod3': '#CD9B1D',
|
||||
'goldenrod4': '#8B6914',
|
||||
'green': '#00FF00',
|
||||
'green yellow': '#ADFF2F',
|
||||
'green1': '#00FF00',
|
||||
'green2': '#00EE00',
|
||||
'green3': '#00CD00',
|
||||
'green4': '#008B00',
|
||||
'GreenYellow': '#ADFF2F',
|
||||
'grey': '#BEBEBE',
|
||||
'grey0': '#000000',
|
||||
'grey1': '#030303',
|
||||
'grey2': '#050505',
|
||||
'grey3': '#080808',
|
||||
'grey4': '#0A0A0A',
|
||||
'grey5': '#0D0D0D',
|
||||
'grey6': '#0F0F0F',
|
||||
'grey7': '#121212',
|
||||
'grey8': '#141414',
|
||||
'grey9': '#171717',
|
||||
'grey10': '#1A1A1A',
|
||||
'grey11': '#1C1C1C',
|
||||
'grey12': '#1F1F1F',
|
||||
'grey13': '#212121',
|
||||
'grey14': '#242424',
|
||||
'grey15': '#262626',
|
||||
'grey16': '#292929',
|
||||
'grey17': '#2B2B2B',
|
||||
'grey18': '#2E2E2E',
|
||||
'grey19': '#303030',
|
||||
'grey20': '#333333',
|
||||
'grey21': '#363636',
|
||||
'grey22': '#383838',
|
||||
'grey23': '#3B3B3B',
|
||||
'grey24': '#3D3D3D',
|
||||
'grey25': '#404040',
|
||||
'grey26': '#424242',
|
||||
'grey27': '#454545',
|
||||
'grey28': '#474747',
|
||||
'grey29': '#4A4A4A',
|
||||
'grey30': '#4D4D4D',
|
||||
'grey31': '#4F4F4F',
|
||||
'grey32': '#525252',
|
||||
'grey33': '#545454',
|
||||
'grey34': '#575757',
|
||||
'grey35': '#595959',
|
||||
'grey36': '#5C5C5C',
|
||||
'grey37': '#5E5E5E',
|
||||
'grey38': '#616161',
|
||||
'grey39': '#636363',
|
||||
'grey40': '#666666',
|
||||
'grey41': '#696969',
|
||||
'grey42': '#6B6B6B',
|
||||
'grey43': '#6E6E6E',
|
||||
'grey44': '#707070',
|
||||
'grey45': '#737373',
|
||||
'grey46': '#757575',
|
||||
'grey47': '#787878',
|
||||
'grey48': '#7A7A7A',
|
||||
'grey49': '#7D7D7D',
|
||||
'grey50': '#7F7F7F',
|
||||
'grey51': '#828282',
|
||||
'grey52': '#858585',
|
||||
'grey53': '#878787',
|
||||
'grey54': '#8A8A8A',
|
||||
'grey55': '#8C8C8C',
|
||||
'grey56': '#8F8F8F',
|
||||
'grey57': '#919191',
|
||||
'grey58': '#949494',
|
||||
'grey59': '#969696',
|
||||
'grey60': '#999999',
|
||||
'grey61': '#9C9C9C',
|
||||
'grey62': '#9E9E9E',
|
||||
'grey63': '#A1A1A1',
|
||||
'grey64': '#A3A3A3',
|
||||
'grey65': '#A6A6A6',
|
||||
'grey66': '#A8A8A8',
|
||||
'grey67': '#ABABAB',
|
||||
'grey68': '#ADADAD',
|
||||
'grey69': '#B0B0B0',
|
||||
'grey70': '#B3B3B3',
|
||||
'grey71': '#B5B5B5',
|
||||
'grey72': '#B8B8B8',
|
||||
'grey73': '#BABABA',
|
||||
'grey74': '#BDBDBD',
|
||||
'grey75': '#BFBFBF',
|
||||
'grey76': '#C2C2C2',
|
||||
'grey77': '#C4C4C4',
|
||||
'grey78': '#C7C7C7',
|
||||
'grey79': '#C9C9C9',
|
||||
'grey80': '#CCCCCC',
|
||||
'grey81': '#CFCFCF',
|
||||
'grey82': '#D1D1D1',
|
||||
'grey83': '#D4D4D4',
|
||||
'grey84': '#D6D6D6',
|
||||
'grey85': '#D9D9D9',
|
||||
'grey86': '#DBDBDB',
|
||||
'grey87': '#DEDEDE',
|
||||
'grey88': '#E0E0E0',
|
||||
'grey89': '#E3E3E3',
|
||||
'grey90': '#E5E5E5',
|
||||
'grey91': '#E8E8E8',
|
||||
'grey92': '#EBEBEB',
|
||||
'grey93': '#EDEDED',
|
||||
'grey94': '#F0F0F0',
|
||||
'grey95': '#F2F2F2',
|
||||
'grey96': '#F5F5F5',
|
||||
'grey97': '#F7F7F7',
|
||||
'grey98': '#FAFAFA',
|
||||
'grey99': '#FCFCFC',
|
||||
'grey100': '#FFFFFF',
|
||||
'honeydew': '#F0FFF0',
|
||||
'honeydew1': '#F0FFF0',
|
||||
'honeydew2': '#E0EEE0',
|
||||
'honeydew3': '#C1CDC1',
|
||||
'honeydew4': '#838B83',
|
||||
'hot pink': '#FF69B4',
|
||||
'HotPink': '#FF69B4',
|
||||
'HotPink1': '#FF6EB4',
|
||||
'HotPink2': '#EE6AA7',
|
||||
'HotPink3': '#CD6090',
|
||||
'HotPink4': '#8B3A62',
|
||||
'indian red': '#CD5C5C',
|
||||
'IndianRed': '#CD5C5C',
|
||||
'IndianRed1': '#FF6A6A',
|
||||
'IndianRed2': '#EE6363',
|
||||
'IndianRed3': '#CD5555',
|
||||
'IndianRed4': '#8B3A3A',
|
||||
'ivory': '#FFFFF0',
|
||||
'ivory1': '#FFFFF0',
|
||||
'ivory2': '#EEEEE0',
|
||||
'ivory3': '#CDCDC1',
|
||||
'ivory4': '#8B8B83',
|
||||
'khaki': '#F0E68C',
|
||||
'khaki1': '#FFF68F',
|
||||
'khaki2': '#EEE685',
|
||||
'khaki3': '#CDC673',
|
||||
'khaki4': '#8B864E',
|
||||
'lavender': '#E6E6FA',
|
||||
'lavender blush': '#FFF0F5',
|
||||
'LavenderBlush': '#FFF0F5',
|
||||
'LavenderBlush1': '#FFF0F5',
|
||||
'LavenderBlush2': '#EEE0E5',
|
||||
'LavenderBlush3': '#CDC1C5',
|
||||
'LavenderBlush4': '#8B8386',
|
||||
'lawn green': '#7CFC00',
|
||||
'LawnGreen': '#7CFC00',
|
||||
'lemon chiffon': '#FFFACD',
|
||||
'LemonChiffon': '#FFFACD',
|
||||
'LemonChiffon1': '#FFFACD',
|
||||
'LemonChiffon2': '#EEE9BF',
|
||||
'LemonChiffon3': '#CDC9A5',
|
||||
'LemonChiffon4': '#8B8970',
|
||||
'light blue': '#ADD8E6',
|
||||
'light coral': '#F08080',
|
||||
'light cyan': '#E0FFFF',
|
||||
'light goldenrod': '#EEDD82',
|
||||
'light goldenrod yellow': '#FAFAD2',
|
||||
'light gray': '#D3D3D3',
|
||||
'light green': '#90EE90',
|
||||
'light grey': '#D3D3D3',
|
||||
'light pink': '#FFB6C1',
|
||||
'light salmon': '#FFA07A',
|
||||
'light sea green': '#20B2AA',
|
||||
'light sky blue': '#87CEFA',
|
||||
'light slate blue': '#8470FF',
|
||||
'light slate gray': '#778899',
|
||||
'light slate grey': '#778899',
|
||||
'light steel blue': '#B0C4DE',
|
||||
'light yellow': '#FFFFE0',
|
||||
'LightBlue': '#ADD8E6',
|
||||
'LightBlue1': '#BFEFFF',
|
||||
'LightBlue2': '#B2DFEE',
|
||||
'LightBlue3': '#9AC0CD',
|
||||
'LightBlue4': '#68838B',
|
||||
'LightCoral': '#F08080',
|
||||
'LightCyan': '#E0FFFF',
|
||||
'LightCyan1': '#E0FFFF',
|
||||
'LightCyan2': '#D1EEEE',
|
||||
'LightCyan3': '#B4CDCD',
|
||||
'LightCyan4': '#7A8B8B',
|
||||
'LightGoldenrod': '#EEDD82',
|
||||
'LightGoldenrod1': '#FFEC8B',
|
||||
'LightGoldenrod2': '#EEDC82',
|
||||
'LightGoldenrod3': '#CDBE70',
|
||||
'LightGoldenrod4': '#8B814C',
|
||||
'LightGoldenrodYellow': '#FAFAD2',
|
||||
'LightGray': '#D3D3D3',
|
||||
'LightGreen': '#90EE90',
|
||||
'LightGrey': '#D3D3D3',
|
||||
'LightPink': '#FFB6C1',
|
||||
'LightPink1': '#FFAEB9',
|
||||
'LightPink2': '#EEA2AD',
|
||||
'LightPink3': '#CD8C95',
|
||||
'LightPink4': '#8B5F65',
|
||||
'LightSalmon': '#FFA07A',
|
||||
'LightSalmon1': '#FFA07A',
|
||||
'LightSalmon2': '#EE9572',
|
||||
'LightSalmon3': '#CD8162',
|
||||
'LightSalmon4': '#8B5742',
|
||||
'LightSeaGreen': '#20B2AA',
|
||||
'LightSkyBlue': '#87CEFA',
|
||||
'LightSkyBlue1': '#B0E2FF',
|
||||
'LightSkyBlue2': '#A4D3EE',
|
||||
'LightSkyBlue3': '#8DB6CD',
|
||||
'LightSkyBlue4': '#607B8B',
|
||||
'LightSlateBlue': '#8470FF',
|
||||
'LightSlateGray': '#778899',
|
||||
'LightSlateGrey': '#778899',
|
||||
'LightSteelBlue': '#B0C4DE',
|
||||
'LightSteelBlue1': '#CAE1FF',
|
||||
'LightSteelBlue2': '#BCD2EE',
|
||||
'LightSteelBlue3': '#A2B5CD',
|
||||
'LightSteelBlue4': '#6E7B8B',
|
||||
'LightYellow': '#FFFFE0',
|
||||
'LightYellow1': '#FFFFE0',
|
||||
'LightYellow2': '#EEEED1',
|
||||
'LightYellow3': '#CDCDB4',
|
||||
'LightYellow4': '#8B8B7A',
|
||||
'lime green': '#32CD32',
|
||||
'LimeGreen': '#32CD32',
|
||||
'linen': '#FAF0E6',
|
||||
'magenta': '#FF00FF',
|
||||
'magenta1': '#FF00FF',
|
||||
'magenta2': '#EE00EE',
|
||||
'magenta3': '#CD00CD',
|
||||
'magenta4': '#8B008B',
|
||||
'maroon': '#B03060',
|
||||
'maroon1': '#FF34B3',
|
||||
'maroon2': '#EE30A7',
|
||||
'maroon3': '#CD2990',
|
||||
'maroon4': '#8B1C62',
|
||||
'medium aquamarine': '#66CDAA',
|
||||
'medium blue': '#0000CD',
|
||||
'medium orchid': '#BA55D3',
|
||||
'medium purple': '#9370DB',
|
||||
'medium sea green': '#3CB371',
|
||||
'medium slate blue': '#7B68EE',
|
||||
'medium spring green': '#00FA9A',
|
||||
'medium turquoise': '#48D1CC',
|
||||
'medium violet red': '#C71585',
|
||||
'MediumAquamarine': '#66CDAA',
|
||||
'MediumBlue': '#0000CD',
|
||||
'MediumOrchid': '#BA55D3',
|
||||
'MediumOrchid1': '#E066FF',
|
||||
'MediumOrchid2': '#D15FEE',
|
||||
'MediumOrchid3': '#B452CD',
|
||||
'MediumOrchid4': '#7A378B',
|
||||
'MediumPurple': '#9370DB',
|
||||
'MediumPurple1': '#AB82FF',
|
||||
'MediumPurple2': '#9F79EE',
|
||||
'MediumPurple3': '#8968CD',
|
||||
'MediumPurple4': '#5D478B',
|
||||
'MediumSeaGreen': '#3CB371',
|
||||
'MediumSlateBlue': '#7B68EE',
|
||||
'MediumSpringGreen': '#00FA9A',
|
||||
'MediumTurquoise': '#48D1CC',
|
||||
'MediumVioletRed': '#C71585',
|
||||
'midnight blue': '#191970',
|
||||
'MidnightBlue': '#191970',
|
||||
'mint cream': '#F5FFFA',
|
||||
'MintCream': '#F5FFFA',
|
||||
'misty rose': '#FFE4E1',
|
||||
'MistyRose': '#FFE4E1',
|
||||
'MistyRose1': '#FFE4E1',
|
||||
'MistyRose2': '#EED5D2',
|
||||
'MistyRose3': '#CDB7B5',
|
||||
'MistyRose4': '#8B7D7B',
|
||||
'moccasin': '#FFE4B5',
|
||||
'navajo white': '#FFDEAD',
|
||||
'NavajoWhite': '#FFDEAD',
|
||||
'NavajoWhite1': '#FFDEAD',
|
||||
'NavajoWhite2': '#EECFA1',
|
||||
'NavajoWhite3': '#CDB38B',
|
||||
'NavajoWhite4': '#8B795E',
|
||||
'navy': '#000080',
|
||||
'navy blue': '#000080',
|
||||
'NavyBlue': '#000080',
|
||||
'old lace': '#FDF5E6',
|
||||
'OldLace': '#FDF5E6',
|
||||
'olive drab': '#6B8E23',
|
||||
'OliveDrab': '#6B8E23',
|
||||
'OliveDrab1': '#C0FF3E',
|
||||
'OliveDrab2': '#B3EE3A',
|
||||
'OliveDrab3': '#9ACD32',
|
||||
'OliveDrab4': '#698B22',
|
||||
'orange': '#FFA500',
|
||||
'orange red': '#FF4500',
|
||||
'orange1': '#FFA500',
|
||||
'orange2': '#EE9A00',
|
||||
'orange3': '#CD8500',
|
||||
'orange4': '#8B5A00',
|
||||
'OrangeRed': '#FF4500',
|
||||
'OrangeRed1': '#FF4500',
|
||||
'OrangeRed2': '#EE4000',
|
||||
'OrangeRed3': '#CD3700',
|
||||
'OrangeRed4': '#8B2500',
|
||||
'orchid': '#DA70D6',
|
||||
'orchid1': '#FF83FA',
|
||||
'orchid2': '#EE7AE9',
|
||||
'orchid3': '#CD69C9',
|
||||
'orchid4': '#8B4789',
|
||||
'pale goldenrod': '#EEE8AA',
|
||||
'pale green': '#98FB98',
|
||||
'pale turquoise': '#AFEEEE',
|
||||
'pale violet red': '#DB7093',
|
||||
'PaleGoldenrod': '#EEE8AA',
|
||||
'PaleGreen': '#98FB98',
|
||||
'PaleGreen1': '#9AFF9A',
|
||||
'PaleGreen2': '#90EE90',
|
||||
'PaleGreen3': '#7CCD7C',
|
||||
'PaleGreen4': '#548B54',
|
||||
'PaleTurquoise': '#AFEEEE',
|
||||
'PaleTurquoise1': '#BBFFFF',
|
||||
'PaleTurquoise2': '#AEEEEE',
|
||||
'PaleTurquoise3': '#96CDCD',
|
||||
'PaleTurquoise4': '#668B8B',
|
||||
'PaleVioletRed': '#DB7093',
|
||||
'PaleVioletRed1': '#FF82AB',
|
||||
'PaleVioletRed2': '#EE799F',
|
||||
'PaleVioletRed3': '#CD687F',
|
||||
'PaleVioletRed4': '#8B475D',
|
||||
'papaya whip': '#FFEFD5',
|
||||
'PapayaWhip': '#FFEFD5',
|
||||
'peach puff': '#FFDAB9',
|
||||
'PeachPuff': '#FFDAB9',
|
||||
'PeachPuff1': '#FFDAB9',
|
||||
'PeachPuff2': '#EECBAD',
|
||||
'PeachPuff3': '#CDAF95',
|
||||
'PeachPuff4': '#8B7765',
|
||||
'peru': '#CD853F',
|
||||
'pink': '#FFC0CB',
|
||||
'pink1': '#FFB5C5',
|
||||
'pink2': '#EEA9B8',
|
||||
'pink3': '#CD919E',
|
||||
'pink4': '#8B636C',
|
||||
'plum': '#DDA0DD',
|
||||
'plum1': '#FFBBFF',
|
||||
'plum2': '#EEAEEE',
|
||||
'plum3': '#CD96CD',
|
||||
'plum4': '#8B668B',
|
||||
'powder blue': '#B0E0E6',
|
||||
'PowderBlue': '#B0E0E6',
|
||||
'purple': '#A020F0',
|
||||
'purple1': '#9B30FF',
|
||||
'purple2': '#912CEE',
|
||||
'purple3': '#7D26CD',
|
||||
'purple4': '#551A8B',
|
||||
'red': '#FF0000',
|
||||
'red1': '#FF0000',
|
||||
'red2': '#EE0000',
|
||||
'red3': '#CD0000',
|
||||
'red4': '#8B0000',
|
||||
'rosy brown': '#BC8F8F',
|
||||
'RosyBrown': '#BC8F8F',
|
||||
'RosyBrown1': '#FFC1C1',
|
||||
'RosyBrown2': '#EEB4B4',
|
||||
'RosyBrown3': '#CD9B9B',
|
||||
'RosyBrown4': '#8B6969',
|
||||
'royal blue': '#4169E1',
|
||||
'RoyalBlue': '#4169E1',
|
||||
'RoyalBlue1': '#4876FF',
|
||||
'RoyalBlue2': '#436EEE',
|
||||
'RoyalBlue3': '#3A5FCD',
|
||||
'RoyalBlue4': '#27408B',
|
||||
'saddle brown': '#8B4513',
|
||||
'SaddleBrown': '#8B4513',
|
||||
'salmon': '#FA8072',
|
||||
'salmon1': '#FF8C69',
|
||||
'salmon2': '#EE8262',
|
||||
'salmon3': '#CD7054',
|
||||
'salmon4': '#8B4C39',
|
||||
'sandy brown': '#F4A460',
|
||||
'SandyBrown': '#F4A460',
|
||||
'sea green': '#2E8B57',
|
||||
'SeaGreen': '#2E8B57',
|
||||
'SeaGreen1': '#54FF9F',
|
||||
'SeaGreen2': '#4EEE94',
|
||||
'SeaGreen3': '#43CD80',
|
||||
'SeaGreen4': '#2E8B57',
|
||||
'seashell': '#FFF5EE',
|
||||
'seashell1': '#FFF5EE',
|
||||
'seashell2': '#EEE5DE',
|
||||
'seashell3': '#CDC5BF',
|
||||
'seashell4': '#8B8682',
|
||||
'sienna': '#A0522D',
|
||||
'sienna1': '#FF8247',
|
||||
'sienna2': '#EE7942',
|
||||
'sienna3': '#CD6839',
|
||||
'sienna4': '#8B4726',
|
||||
'sky blue': '#87CEEB',
|
||||
'SkyBlue': '#87CEEB',
|
||||
'SkyBlue1': '#87CEFF',
|
||||
'SkyBlue2': '#7EC0EE',
|
||||
'SkyBlue3': '#6CA6CD',
|
||||
'SkyBlue4': '#4A708B',
|
||||
'slate blue': '#6A5ACD',
|
||||
'slate gray': '#708090',
|
||||
'slate grey': '#708090',
|
||||
'SlateBlue': '#6A5ACD',
|
||||
'SlateBlue1': '#836FFF',
|
||||
'SlateBlue2': '#7A67EE',
|
||||
'SlateBlue3': '#6959CD',
|
||||
'SlateBlue4': '#473C8B',
|
||||
'SlateGray': '#708090',
|
||||
'SlateGray1': '#C6E2FF',
|
||||
'SlateGray2': '#B9D3EE',
|
||||
'SlateGray3': '#9FB6CD',
|
||||
'SlateGray4': '#6C7B8B',
|
||||
'SlateGrey': '#708090',
|
||||
'snow': '#FFFAFA',
|
||||
'snow1': '#FFFAFA',
|
||||
'snow2': '#EEE9E9',
|
||||
'snow3': '#CDC9C9',
|
||||
'snow4': '#8B8989',
|
||||
'spring green': '#00FF7F',
|
||||
'SpringGreen': '#00FF7F',
|
||||
'SpringGreen1': '#00FF7F',
|
||||
'SpringGreen2': '#00EE76',
|
||||
'SpringGreen3': '#00CD66',
|
||||
'SpringGreen4': '#008B45',
|
||||
'steel blue': '#4682B4',
|
||||
'SteelBlue': '#4682B4',
|
||||
'SteelBlue1': '#63B8FF',
|
||||
'SteelBlue2': '#5CACEE',
|
||||
'SteelBlue3': '#4F94CD',
|
||||
'SteelBlue4': '#36648B',
|
||||
'tan': '#D2B48C',
|
||||
'tan1': '#FFA54F',
|
||||
'tan2': '#EE9A49',
|
||||
'tan3': '#CD853F',
|
||||
'tan4': '#8B5A2B',
|
||||
'thistle': '#D8BFD8',
|
||||
'thistle1': '#FFE1FF',
|
||||
'thistle2': '#EED2EE',
|
||||
'thistle3': '#CDB5CD',
|
||||
'thistle4': '#8B7B8B',
|
||||
'tomato': '#FF6347',
|
||||
'tomato1': '#FF6347',
|
||||
'tomato2': '#EE5C42',
|
||||
'tomato3': '#CD4F39',
|
||||
'tomato4': '#8B3626',
|
||||
'turquoise': '#40E0D0',
|
||||
'turquoise1': '#00F5FF',
|
||||
'turquoise2': '#00E5EE',
|
||||
'turquoise3': '#00C5CD',
|
||||
'turquoise4': '#00868B',
|
||||
'violet': '#EE82EE',
|
||||
'violet red': '#D02090',
|
||||
'VioletRed': '#D02090',
|
||||
'VioletRed1': '#FF3E96',
|
||||
'VioletRed2': '#EE3A8C',
|
||||
'VioletRed3': '#CD3278',
|
||||
'VioletRed4': '#8B2252',
|
||||
'wheat': '#F5DEB3',
|
||||
'wheat1': '#FFE7BA',
|
||||
'wheat2': '#EED8AE',
|
||||
'wheat3': '#CDBA96',
|
||||
'wheat4': '#8B7E66',
|
||||
'white': '#FFFFFF',
|
||||
'white smoke': '#F5F5F5',
|
||||
'WhiteSmoke': '#F5F5F5',
|
||||
'yellow': '#FFFF00',
|
||||
'yellow green': '#9ACD32',
|
||||
'yellow1': '#FFFF00',
|
||||
'yellow2': '#EEEE00',
|
||||
'yellow3': '#CDCD00',
|
||||
'yellow4': '#8B8B00',
|
||||
'YellowGreen': '#9ACD32',
|
||||
}
|
||||
|
||||
old_look_and_feel = None
|
||||
if look_and_feel is not None:
|
||||
old_look_and_feel = sg.CURRENT_LOOK_AND_FEEL
|
||||
sg.theme(look_and_feel)
|
||||
|
||||
button_size = (1, 1)
|
||||
|
||||
# button_size = (None,None) # for very compact buttons
|
||||
|
||||
def ColorButton(color):
|
||||
"""
|
||||
A User Defined Element - returns a Button that configured in a certain way.
|
||||
:param color: Tuple[str, str] ( color name, hex string)
|
||||
:return: sg.Button object
|
||||
"""
|
||||
return sg.B(button_color=('white', color[1]), pad=(0, 0), size=button_size, key=color, tooltip=f'{color[0]}:{color[1]}', border_width=0)
|
||||
|
||||
num_colors = len(list(color_map.keys()))
|
||||
row_len = 40
|
||||
|
||||
grid = [[ColorButton(list(color_map.items())[c + j * row_len]) for c in range(0, row_len)] for j in range(0, num_colors // row_len)]
|
||||
grid += [[ColorButton(list(color_map.items())[c + num_colors - num_colors % row_len]) for c in range(0, num_colors % row_len)]]
|
||||
|
||||
layout = [[sg.Text('Pick a color', font='Def 18')]] + grid + \
|
||||
[[sg.Button('OK'), sg.T(size=(30, 1), key='-OUT-')]]
|
||||
|
||||
window = sg.Window('Window Title', layout, no_titlebar=True, grab_anywhere=True, keep_on_top=True, use_ttk_buttons=True)
|
||||
color_chosen = None
|
||||
while True: # Event Loop
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'OK'):
|
||||
if event == sg.WIN_CLOSED:
|
||||
color_chosen = None
|
||||
break
|
||||
window['-OUT-'](f'You chose {event[0]} : {event[1]}')
|
||||
color_chosen = event[1]
|
||||
window.close()
|
||||
if old_look_and_feel is not None:
|
||||
sg.theme(old_look_and_feel)
|
||||
return color_chosen
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sg.theme('Light Brown 4')
|
||||
layout = [[sg.In(key='-CHOICE-'), sg.B('Color Picker')],
|
||||
[sg.Ok(), sg.Cancel()]]
|
||||
window = sg.Window('My application', layout)
|
||||
while True:
|
||||
event, values = window.read()
|
||||
if event in (sg.WIN_CLOSED, 'Cancel'):
|
||||
break
|
||||
if event.startswith('Color'):
|
||||
window.hide()
|
||||
color_chosen = popup_color_chooser('Dark Blue 3')
|
||||
window['-CHOICE-'].update(color_chosen)
|
||||
window.un_hide()
|
||||
else:
|
||||
print(f'The current look and feel = {sg.CURRENT_LOOK_AND_FEEL}')
|