init repo

This commit is contained in:
2026-04-15 07:53:51 +08:00
commit 7e9f9b5f25
21 changed files with 38577 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
__pycache__/
*.pyc

2
PySimpleGUI/.gitignore vendored Executable file
View File

@@ -0,0 +1,2 @@
readme_creator/psg_gui.py

39
PySimpleGUI/CONTRIBUTING.md Executable file
View File

@@ -0,0 +1,39 @@
## 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
PySimpleGUI/PySimpleGUI.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

26840
PySimpleGUI/PySimpleGUI.py Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,459 @@
![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png)
![Downloads](http://pepy.tech/badge/pysimpleguiwx)
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-1000-yellow.svg)
![Python Version](https://img.shields.io/badge/Python-3.x-yellow.svg)
[![PyPI Version](https://img.shields.io/pypi/v/pysimpleguiwx.svg?style=for-the-badge)](https://pypi.org/project/pysimpleguiwx/)
# PySimpleGUIWx
The WxPython port of PySimpleGUI
## Primary PySimpleGUI Documentation
To get instructions on how use PySimpleGUI's APIs, please reference the [main documentation](http://www.PySimpleGUI.org).
This Readme is for information ***specific to*** the WxPython port of PySimpleGUI.
## Why Use PySimpleGUIWx Over The Other Ports?
PySimpleGUIWx brings the number of PySimpleGUI ports to 3.
Why use PySimpleGUIWx over PySimpleGUIQt PySimpleGUI (tkinter version)?
There are a couple of easy reasons to use PySimpleGUIWx over PySimpleGUIQt. One is footprint. PyInstaller EXE for PySimpleGUIWx is 9 MB, on Qt it's 240 MB. Another is cool widgets.
WxPython has some nice advanced widgets that will be offered though PySimpleGUIWx, hopefully sooner than later.
The System Tray feature works well with a feature set identical to PySimpleGUIQt. If you are looking for a System Tray feature, PySimpleGUIWx is recommended over PySimpleGUIQt ; the primary reason being size of the WxPython framework versus the size of Qt. They both give you very similar features. They look and behave in an ***identical*** fashion when using PySimpleGUI. That's the beauty of the PSG SDK, the function calls are the same for all implementations of PySimpleGUI. The source code is highly portable between the GUI frameworks.
This simple list is another way of looking at the question....
1. It's simple and easy to program GUIs
2. You can move between the GUI frameworks tkinter, Qt and WxPython by changing a single line of code, the import statement.
3. Get the same custom layout and access to the same widgets but in a simple, easy to use and understand interface.
4. It's fun to program GUIs again
## Engineering Pre-Release Version 0.13.0
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
Having trouble? Visit the [GitHub site ](http://www.PySimpleGUI.com) and log an Issue.
## What Works
Remember, these are Engineering Releases. Not all features are complete, but generally speaking those that are marked as completed and working are working quite well. It's not an "Engineering Quality". The completed features are at about a Beta level.
### Ready to use
#### Elements
* Text
* Input Text
* Buttons including file/folder browse
* Input multiline
* Output multiline
* Output
* Columns
* Frames - except cannot set colors yet
* Progress Meters
* Checkbox
* Radio Button
* Combobox
* Spinner
* Vertical and Horizontal Separators
#### Features
* System Tray
* Debug Print
* Invisible/Visible Elements
* All Popups
* Check box
* Keyboard key events
* Mouse wheel events
* Multiple windows
* Read with timeout
* Background images
* One Line Progress Meter (tm)
* Auto-closing windows
* No titlebar windows
* Grab anywhere windows
* Alpha channel
* Window size
* Window disappear/reappear
* Get screen size
* Get window location
* Change window size
* Window move
* Window minimize
* Window maximize
* Window Disable
* Window Enable
* Window Hide
* Window UnHide
* Window Bring to front
* Look and Feel settings
* Default Icon
* Base64 Icons
* PEP8 bindings for all element methods and functions
It won't take long to poke at these and hit errors. For example, the code to do Button Updates is not complete. Most of the time you won't be doing this.
Due to the small size of the development team, features may feel a little "thin" for a while. The idea is to implement with enough depth that 80% of the uses are covered. It's a multi-pass, iterative approach.
If you, the reader, are having problems or have hit a spot where something is not yet implemented, then open an Issue. They are often completed in a day. This process of users pushing the boundaries is what drives the priorities for development. It's "real world" kinds of problems that have made PySimpleGUI what it is today.
## SystemTray
This was the first fully functioning feature of PySimpleGUIWx. Previously only the Qt port supported the System Tray. Why use Wx? The footprint is much much smaller. An EXE file created using PyInstaller is 9 MB for PySimpleGUIWx, when using Qt it's 240 MB.
Now it's possible to "tack on" the System Tray to your PySimpleGUI application.
If you're unable to upgrade to Qt but want the System Tray feature, then adding PySimpleGUIWx to your project may be the way to go.
You can mix your System Tray's event loop with your normal Window event loop by adding a timeout to both your Window.Read call and your SystemTray.Read call.
### Source code compatibility
PySimpleGUIWx's System Tray feature has been tested against the same PySimpleGUIQt feature. As long as you don't use features that are not yet supported you'll find your source code will run on either PySimpleGUIQt or PySimpleGUIWx by changing the import statement.
## System Tray Design Pattern
Here is a design pattern you can use to get a jump-start.
This program will create a system tray icon and perform a blocking Read.
```python
import PySimpleGUIWx as sg
tray = sg.SystemTray(menu= ['menu',['Open', ['&Save::KEY', '---', 'Issues', '!Disabled'], 'E&xit']],
filename=r'C:\Python\PycharmProjects\GooeyGUI\default_icon.ico')
tray.ShowMessage('My Message', 'The tray icon is up and runnning!')
while True:
event = tray.Read()
print(event)
if event == 'Exit':
break
```
## Menu Definitions
See the original, full documentation for PySimpleGUI to get an understanding of how menus are defined.
## SystemTray Methods
### Read - Read the context menu or check for events
```python
def Read(timeout=None)
'''
Reads the context menu
:param timeout: Optional. Any value other than None indicates a non-blocking read
:return: String representing meny item chosen. None if nothing read.
'''
```
The `timeout` parameter specifies how long to wait for an event to take place. If nothing happens within the timeout period, then a "timeout event" is returned. These types of reads make it possible to run asynchronously. To run non-blocked, specify `timeout=0`on the Read call (not yet supported).
Read returns the menu text, complete with key, for the menu item chosen. If you specified `Open::key` as the menu entry, and the user clicked on `Open`, then you will receive the string `Open::key` upon completion of the Read.
#### Read special return values
In addition to Menu Items, the Read call can return several special values. They include:
EVENT_SYSTEM_TRAY_ICON_DOUBLE_CLICKED - Tray icon was double clicked
EVENT_SYSTEM_TRAY_ICON_ACTIVATED - Tray icon was single clicked
EVENT_SYSTEM_TRAY_MESSAGE_CLICKED - a message balloon was clicked
TIMEOUT_KEY is returned if no events are available if the timeout value is set in the Read call
### ShowMessage
Just like Qt, you can create a pop-up message. Unlike Qt, you cannot set your own custom icon in the message, at least you can't at the moment.
The preset `messageicon` values are:
SYSTEM_TRAY_MESSAGE_ICON_INFORMATION
SYSTEM_TRAY_MESSAGE_ICON_WARNING
SYSTEM_TRAY_MESSAGE_ICON_CRITICAL
SYSTEM_TRAY_MESSAGE_ICON_NOICON
```python
ShowMessage(title, message, filename=None, data=None, data_base64=None, messageicon=None, time=10000):
'''
Shows a balloon above icon in system tray
:param title: Title shown in balloon
:param message: Message to be displayed
:param filename: Optional icon filename
:param data: Optional in-ram icon
:param data_base64: Optional base64 icon
:param time: How long to display message in milliseconds :return:
'''
```
### Update
You can update any of these items within a SystemTray object
* Menu definition
* Icon (not working yet)
* Tooltip
Change them all or just 1.
```python
Update(menu=None, tooltip=None,filename=None, data=None, data_base64=None,)
'''
Updates the menu, tooltip or icon
:param menu: menu defintion
:param tooltip: string representing tooltip
:param filename: icon filename
:param data: icon raw image
:param data_base64: icon base 64 image
:return:
'''
```
## Menus with Keys
You can add a key to your menu items. To do so, you add :: and the key value to the end of your menu definition.
`menu_def = ['File', ['Hide::key', '&Open::key', '&Save',['1', '2', ['a','b']], '&Properties', 'E&xit']]`
The menu definition adds a key "key" to the menu entries Hide and Open.
If you want to change the separator characters from :: top something else,change the variable `MENU_KEY_SEPARATOR`
When a menu item has a key and it is chosen, then entire string is returned. If Hide were selected, then Hide::key would be returned from the Read. Note that the shortcut character & is NOT returned from Reads.
## Popups
Starting with release 0.4.0, most of the Popup functions work. This means you can do things like show information in a window when there's a choice made in a System Tray menu. Or if your program finds some event it wishes to inform the user about. For example, when new Issues are posted on a GitHub project.
# Release Notes:
### 0.1.0 - 25-Dec-2018
* Support for SystemTray
* Read, with or without a timeout
* Catch single click, double click events
* Source code compatiable with Qt
### 0.2.0 - 26-Dec-2018
* Correctly handling base64 images
* Support for clicking message balloon
* Can Hide and UnHide the icon
### 0.3.0 - 27-Dec-2018
* Hooked up buttons!
* Browse file button is only file/folder button that works
* Text, Input and Button elements are the only working elements
* SystemTray can take any kind of image as icon
* Read with Timeout (non-zero) works
* Popups
### 0.4.0 PySimpleGUIWx 30-Dec-2018
* Text Element - colors, font work
* Text Update method works
* Button - Close button implemented
* Button - Implemented basic button, correctly presented Values on Read
* Button - Can now set font
* Changed overall "App" variable usage for better mainloop control
* Windows - Timeouts and non-blocking Reads work
* Windows - Autoclose works
* Windows - Non-blocking calls supported (timeout=0)
* Windows - Grab anywhere works
* Windows - No title-bar works
* Windows - Location and Size working correctly
* Correctly adding element padding to Text, Input, Buttons
* Popups - most Popups work (except for the input type that involve folders)
### 0.5.0 PySimpleGUIWx 6-Jan-2019
* New element - Multiline input
* New element - Multiline output
* Borderless Windows
* Grab anywhere windows
* Alpha channel for windows
* Finishing up the Text and Input Text Elements
* Visibility for all Elements
* Input Get / Set focus
* Output element - unable to get stdout to re-route
* Debug window works
### 0.6.0 9-Jan-2019
* Column Element
* Checkbox Element with events
* Output Element
* Background Image (I think works)
* Debug Print
* One Line Progress Meter
* All Popups works
### 0.7.0 PySimpleGUIWx 21-Jan-2019
* Element.Update support for disabled and tooltip
* Combo Element
* Newest Combo parameters
* Radio Element
* Newest Radio parameters (size_px, visible, enable_events)
* Type hints on Wx widgets
* Spinner Element
* Newest Spinner parameters
* Text Element visibility
* Column Element size_px parameter (unclear if works... likely does not)
* Column visibility
* Column Update method added
* System Tray - support for any kind of image format for icons
* Window.Move
* Window.Minimize
* Window.Maximize
* Window.Disable
* Window.Enable
* Window.Hide
* Window.UnHide
* Window.BringToFront
* Popup non_blocking - returns window and button not just button
* More comprehensive test harness when running PySimpleGUIWx.py
### 0.8.0 20-Feb-2019 PySimpleGUIWx
* Big Try/Except block around Update method for multiline in case window closed
* Text - convert incoming text to string right away
* Text.Update - convert incoming value to string
* Completed Button.Update method. Can now change text, color, etc.
* Added Try around reading multiline input value - not sure why needed
* OneLineProgressMeter - can update text on every call now
### 0.9.0 06-Mar-2019 PySimpleGUIWx
* Addition of Assert Suppression
* This was needed for a multi-threaded version of PySimpleGUIWx
* Complained when exiting a system tray if did not make this change and ran the tray in a thread
* Tray.Close now correctly Hides the icon
* SetGlobalIcon functional
* Can also now set icon using SetOptions call
### 0.10.0 23-Mar-2019 PySimpleGUIWx
* `do_not_clear` is now TRUE by default on Input and Multiline elements!!
## 0.11.0 11-Apr-2019 PySimpleGUIWx
* NEW Window parameter layout so can skip calling Layout
## 0.13.0 1-OCT-2019 PySimpleGUIWx
* Version numbering using sg.version string
* PEP8 bindings!
* Improved scaling of character to pixel sizes of elements that are multilined
* Added Metadata variable to all elements
* Renamed element callback functions to start with _
* Removed __del__ methods everywhere except Output Element
* Can "Call" an element which will call its Update method
* InputText element - convert default text and password char to string
* Removed old code such as tkinter's tooltip and drag and drop from Qt
* Shortcut I for InputText
* Listbox added size_px parm
* Changed type checking to use the comment style types
* Added Element.Widget to all Elements so can access the Wx widgets directly
* Text Element now defaults to '' so no need to specify anything if a blank Text Element (often used for output)
* Button text converted to string when creating button
* New Button shortcuts - B, Btn
* VerticalSeparator - Newly supported Element
* HorizontalSeparator - Newly supported Element
* Slider - added size_px parm
* Fixed leak caused by System Tray not cleaning up the timer
* Window - added finalize paramter so can skip using chained .Finalize()
* Window - AllKeysDict now used like other PySimpleGUI ports. Has all the keys and elements in a window
* Window.FindElement - added silent_on_error parm like other ports have
* Window[key] construct added that calls FindElement
* window() - can "Call" a window you've created. Will call Window.Read()
* Popup buttons no longer use CloseButtons for normal popups. Calls window.Close manually
* PopupGetFolder changed to use keys, normal button, new window design patterns
* PopupGetFile changed to use keys, normal buttons, new window design patterns
* PopupGetText changed to use keys, normal buttons, new window design patterns
* Default application (PySimpleGUI.main) now shows the version number like other PySimpleGUI ports
## 0.13.0 17-Nov-2019 PySimpleGUIWx
* 105 Look and Feel Themes to choose from!
* New "Fuzzy" look and feel selection
* Preview all look and feels not yet supported due to lack of Frame support
## 0.15.0 PySimpleGUIWx 24-Dec-2019
Themes!
* Picked up the new "theme" APIs like all 4 ports got
* Dark Blue 3 is the new official color theme for PySimpleGUI
* Added "port" string so that your code can detect which port of PySimpleGUI is being executed
* Removed restriction on Macs (totally didn't make sense that it was there as it blocked a tkinter problem, not a Wx one)
* Depricated the TRANSPARENT_BUTTON variable as it was being misunderstood by users and was misleading
* BROWSE_FILES_DELIMITER can be changed to change the default ';' delimeter between filenames in FilesBrowse button
* Frame Element! BUT, it's only a partial solution as I am unable to set the background color (need to understand how panels work). It's better than nothing
## 0.16.0 PySimpleGUIWx 6-May-2020
* Added constants
* WIN_CLOSED and WINDOW_CLOSED
* EVENT_TIMEOUT and TIMEOUT_EVENT
* Added Graph.change_coordinates method
* Added close parameter to Window.read
## 0.17.0 PySimpleGUIWx 6-Jun-2020
Element justification within Window and Containers! Finally a unified justification
* When any Radio element is updated to be False, the entire GROUP is reset so nothing is selected
* element_jutification added so that all elements inside these will be justified accordingly.
* For PySimpleGUIQt only, the default is "float" which sets nothing. Buttons will stretch across the window as result
* Valid values are 'l', 'r', 'c'. You can spell it out, but only first letter is used.
* Window
* Frame
* Column
* Tab
## 0.17.1 PySimpleGUIWx 7-Jun-2020
* Quick patch of Multiline.update so that newlines are recognized correctly
# Design
# Author
Mike B.
# License
GNU Lesser General Public License (LGPL 3) +
# Acknowledgments
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTIxNDIwNTI0ODQsODg2MzA1Mjk2XX0=
-->

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

3
PySimpleGUI/__init__.py Executable file
View File

@@ -0,0 +1,3 @@
name = "PySimpleGUI"
from .PySimpleGUI import *
from .PySimpleGUI import __version__

1
PySimpleGUI/_config.yml Executable file
View File

@@ -0,0 +1 @@
theme: jekyll-theme-hacker

BIN
PySimpleGUI/default_icon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

165
PySimpleGUI/license.txt Executable file
View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

8
PySimpleGUI/mkdocs.yml Executable file
View File

@@ -0,0 +1,8 @@
site_name: PySimpleGUI
theme:
name: mkdocs
custom_dir: docs_modification/
plugins:
- search:
prebuild_index: true
extra_css: [extra.css]

282
PySimpleGUI/psgtray.py Executable file
View File

@@ -0,0 +1,282 @@
import pystray, io, base64, threading, time
from PIL import Image
import PySimpleGUI as sg
"""
A System Tray Icon implementation that can work with the tkinter port of PySimpleGUI!
To use, add this import to your code:
from psgtray import SystemTray
Make sure the psgtray.py file is in the same folder as your app or is on your Python path
Because this code is entirely in the user's space it's possible to use the pystray package
to implement the system tray icon feature. You need to install pystray and PIL.
As of this date, the latest version of pystray is 0.17.3
This code works well under Windows.
On Linux there are some challenges. Some changes were
needed in order to get pystray to run as a thread using gtk as the backend.
The separator '---' caused problems so it is now ignored. Unknown why it caused the
menu to not show at all, but it does.
A sample bit of code is at the bottom for your reference.
Your window will receive events from the system tray thread.
In addition to the init, these are the class methods available:
change_icon
hide_icon
show_icon
set_tooltip
notify
In your code, you will receive events from tray with key SystemTray.key
The value will be the choice made or a click event. This is the magic statement:
window.write_event_value(tray.key, item.text)
Extra Special thanks to FireDM for the design pattern that made this work.
(https://github.com/firedm/FireDM)
Copyright 2021 PySimpleGUI
"""
class SystemTray:
DOUBLE_CLICK_THRESHOLD = 500 # time in milliseconds to determine double clicks
DEFAULT_KEY = '-TRAY-' # the default key that will be used to send events to your window
key_counter = 0
def __init__(self, menu=None, icon=None, tooltip='', single_click_events=False, window=None, key=DEFAULT_KEY):
"""
A System Tray Icon
Initializing the object is all that is required to make the tray icon and start the thread.
:param menu: The PySimpleGUI menu data structure
:type menu: List[List[Tuple[str, List[str]]]
:param icon: Icon to show in the system tray. Can be a file or a BASE64 byte string
:type icon: str | bytes
:param tooltip: Tooltip that is shown when mouse hovers over the system tray icon
:type tooltip: str
:param single_click_events: If True then both single click and double click events will be generated
:type single_click_events: bool
:param window: The window where the events will be sent using window.write_event_value
:type window: sg.Window
"""
self.title = tooltip
self.tray_icon = None # type: pystray.Icon
self.window = window
self.tooltip = tooltip
self.menu_items = self._convert_psg_menu_to_tray(menu[1])
self.key = key if SystemTray.key_counter == 0 else key+str(SystemTray.key_counter)
SystemTray.key_counter += 1
self.double_click_timer = 0
self.single_click_events_enabled = single_click_events
if icon is None:
self.icon = sg.DEFAULT_BASE64_ICON
else:
self.icon = icon
self.thread_started = False
self.thread = threading.Thread(target=self._pystray_thread, daemon=True)
self.thread.start()
while not self.thread_started: # wait for the thread to begin
time.sleep(.2)
time.sleep(.2) # one more slight delay to allow things to actually get running
def change_icon(self, icon=None):
"""
Change the icon shown in the tray to a file or a BASE64 byte string.
:param icon: The icon to change to
:type icon: str | bytes
"""
if icon is not None:
self.tray_icon.icon = self._create_image(icon)
def hide_icon(self):
"""
Hides the icon
"""
self.tray_icon.visible = False
def show_icon(self):
"""
Shows a previously hidden icon
"""
self.tray_icon.visible = True
def set_tooltip(self, tooltip):
"""
Set the tooltip that is shown when hovering over the icon in the system tray
"""
self.tray_icon.title = tooltip
def show_message(self, title=None, message=None):
"""
Show a notification message balloon in the system tray
:param title: Title that is shown at the top of the balloon
:type title: str
:param message: Main message to be displayed
:type message: str
"""
self.tray_icon.notify(title=str(title) if title is not None else '', message=str(message) if message is not None else '')
def close(self):
"""
Whlie not required, calling close will remove the icon from the tray right away.
"""
self.tray_icon.visible = False # hiding will close any message bubbles that may hold up the removal of icon from tray
self.tray_icon.stop()
# --------------------------- The methods below this point are not meant to be user callable ---------------------------
def _on_clicked(self, icon, item: pystray.MenuItem):
self.window.write_event_value(self.key, item.text)
def _convert_psg_menu_to_tray(self, psg_menu):
menu_items = []
i = 0
if isinstance(psg_menu, list):
while i < len(psg_menu):
item = psg_menu[i]
look_ahead = item
if i != (len(psg_menu) - 1):
look_ahead = psg_menu[i + 1]
if not isinstance(item, list) and not isinstance(look_ahead, list):
disabled = False
if item == sg.MENU_SEPARATOR_LINE:
item = pystray.Menu.SEPARATOR
elif item.startswith(sg.MENU_DISABLED_CHARACTER):
disabled = True
item = item[1:]
if not (item == pystray.Menu.SEPARATOR and sg.running_linux()):
menu_items.append(pystray.MenuItem(item, self._on_clicked, enabled=not disabled, default=False))
elif look_ahead != item:
if isinstance(look_ahead, list):
if menu_items is None:
menu_items = pystray.MenuItem(item, pystray.Menu(*self._convert_psg_menu_to_tray(look_ahead)))
else:
menu_items.append(pystray.MenuItem(item, pystray.Menu(*self._convert_psg_menu_to_tray(look_ahead))))
i += 1
# important item - this is where clicking the icon itself will go
menu_items.append(pystray.MenuItem('default', self._default_action_callback, enabled=True, default=True, visible=False))
return menu_items
def _default_action_callback(self):
delta = (time.time() - self.double_click_timer) * 1000
if delta < self.DOUBLE_CLICK_THRESHOLD: # if last click was recent, then this click is a double-click
self.window.write_event_value(self.key, sg.EVENT_SYSTEM_TRAY_ICON_DOUBLE_CLICKED)
self.double_click_timer = 0
else:
if self.single_click_events_enabled:
self.window.write_event_value(self.key, sg.EVENT_SYSTEM_TRAY_ICON_ACTIVATED)
self.double_click_timer = time.time()
def _pystray_thread(self):
self.tray_icon = pystray.Icon(self.title, self._create_image(self.icon))
self.tray_icon.default_action = self._default_action_callback
self.tray_icon.menu = pystray.Menu(*self.menu_items)
self.tray_icon.title = self.tooltip # tooltip for the icon
self.thread_started = True
self.tray_icon.run()
def _create_image(self, icon):
if isinstance(icon, bytes):
buffer = io.BytesIO(base64.b64decode(icon))
img = Image.open(buffer)
elif isinstance(icon, str):
img = Image.open(icon)
else:
img = None
return img
# MM""""""""`M dP
# MM mmmmmmmM 88
# M` MMMM dP. .dP .d8888b. 88d8b.d8b. 88d888b. 88 .d8888b.
# MM MMMMMMMM `8bd8' 88' `88 88'`88'`88 88' `88 88 88ooood8
# MM MMMMMMMM .d88b. 88. .88 88 88 88 88. .88 88 88. ...
# MM .M dP' `dP `88888P8 dP dP dP 88Y888P' dP `88888P'
# MMMMMMMMMMMM 88
# dP
# M""MMMMM""M
# M MMMMM M
# M MMMMM M .d8888b. .d8888b.
# M MMMMM M Y8ooooo. 88ooood8
# M `MMM' M 88 88. ...
# Mb dM `88888P' `88888P'
# MMMMMMMMMMM
def main():
# This example shows using TWO tray icons together
menu = ['', ['Show Window', 'Hide Window', '---', '!Disabled Item', 'Change Icon', ['Happy', 'Sad', 'Plain'], 'Exit']]
tooltip = 'Tooltip'
layout = [[sg.Text('My PySimpleGUI Window with a Tray Icon - X will minimize to tray')],
[sg.Text('Note - you are running a file that is meant to be imported')],
[sg.T('Change Icon Tooltip:'), sg.Input(tooltip, key='-IN-', s=(20,1)), sg.B('Change Tooltip')],
[sg.Multiline(size=(60,10), reroute_stdout=False, reroute_cprint=True, write_only=True, key='-OUT-')],
[sg.Button('Go'), sg.B('Hide Icon'), sg.B('Show Icon'), sg.B('Hide Window'), sg.B('Close Tray'), sg.Button('Exit')]]
window = sg.Window('Window Title', layout, finalize=True, enable_close_attempted_event=True)
tray1 = SystemTray(menu, single_click_events=False, window=window, tooltip=tooltip, icon=sg.DEFAULT_BASE64_ICON)
tray2 = SystemTray(menu, single_click_events=False, window=window, tooltip=tooltip, icon=sg.EMOJI_BASE64_HAPPY_JOY)
time.sleep(.5) # wait just a little bit since TWO are being started at once
tray2.show_message('Started', 'Both tray icons started')
while True:
event, values = window.read()
print(event, values)
# IMPORTANT step. It's not required, but convenient.
# if it's a tray event, change the event variable to be whatever the tray sent
# This will make your event loop homogeneous with event conditionals all using the same event variable
if event in (tray1.key, tray2.key):
sg.cprint(f'System Tray Event = ', values[event], c='white on red')
tray = tray1 if event == tray1.key else tray2
event = values[event] # use the System Tray's event as if was from the window
else:
tray = tray1 # if wasn't a tray event, there's still a tray varaible used, so default to "first" tray created
if event in (sg.WIN_CLOSED, 'Exit'):
break
sg.cprint(event, values)
tray.show_message(title=event, message=values)
tray.set_tooltip(values['-IN-'])
if event in ('Show Window', sg.EVENT_SYSTEM_TRAY_ICON_DOUBLE_CLICKED):
window.un_hide()
window.bring_to_front()
elif event in ('Hide Window', sg.WIN_CLOSE_ATTEMPTED_EVENT):
window.hide()
tray.show_icon() # if hiding window, better make sure the icon is visible
# tray.notify('System Tray Item Chosen', f'You chose {event}')
elif event == 'Happy':
tray.change_icon(sg.EMOJI_BASE64_HAPPY_JOY)
elif event == 'Sad':
tray.change_icon(sg.EMOJI_BASE64_FRUSTRATED)
elif event == 'Plain':
tray.change_icon(sg.DEFAULT_BASE64_ICON)
elif event == 'Hide Icon':
tray.hide_icon()
elif event == 'Show Icon':
tray.show_icon()
elif event == 'Close Tray':
tray.close()
elif event == 'Change Tooltip':
tray.set_tooltip(values['-IN-'])
tray1.close()
tray2.close()
window.close()
if __name__ == '__main__':
# Normally this file is not "run"
main()

748
PySimpleGUI/readme.ja.md Executable file
View File

@@ -0,0 +1,748 @@
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Logo%20with%20text%20for%20GitHub%20Top.png" alt="人間のためのPythonGUI ">
<h2 align="center">人間のためのPythonGUI</h2>
</p>
tkinter、Qt、WxPython、およびRemiブラウザベースのGUIフレームワークを、よりシンプルなインタフェースに変換します。ウィンドウ定義は初心者が理解するPythonコアデータ型リストと辞書を使用して簡略化されます。コールバックベースのモデルからメッセージを渡すモデルにイベント処理を変更することでさらに単純化が行われます。
コードはより多くのユーザーがパッケージを使用するのにオブジェクト指向アーキテクチャを持つ*必要はありません*。アーキテクチャは理解しやすいものですが、必ずしも*単純*な問題だけに制限されるわけではありません。
ただし一部のプログラムはPySimpleGUIには適していません。 定義上、PySimpleGUIは基盤となるGUIフレームワークの機能のサブセットを実装します。どのプログラムがPySimpleGUIに適していてどのプログラムが適していないかを正確に定義することは難しいです。 プログラムの詳細によって異なります。エクセルを詳細に複製することはPySimpleGUIに適していないものの例です。
[Japanese version of this readme](https://github.com/PySimpleGUI/PySimpleGUI/blob/master/readme.ja.md).
<a href="https://www.buymeacoffee.com/PySimpleGUI" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/arial-yellow.png" alt="Buy Me A Coffee" width="217px" ></a>
<!-- I could use a coffee! It fuels consultants, editors, domain registration and so many other things required for PySimpleGUI to be a thriving project. -->
コーヒーが飲みたいです! コンサルタント、エディター、ドメイン登録など、PySimpleGUIプロジェクトが繁栄するために必要な多くのものをまかなえます。
<hr>
# 統計 :chart_with_upwards_trend:
## PyPIの統計とバージョン
| TK | TK 2.7 | Qt| WxPython | Web (Remi) |
| -- | -- | -- | -- | -- |
| ![tkinter](https://img.shields.io/pypi/dm/pysimplegui?label=tkinter) | ![tkinter 2.7 downloads](https://img.shields.io/pypi/dm/pysimplegui27?label=tkinter%202.7) | ![qt](https://img.shields.io/pypi/dm/pysimpleguiqt?label=qt) | ![wx](https://img.shields.io/pypi/dm/pysimpleguiwx?label=wx) | ![web](https://img.shields.io/pypi/dm/pysimpleguiweb?label=web) |
| [![tkinter](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui) | [![tkinter27](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27) | [![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt) | [![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) | [![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) |
| ![tkinter](https://img.shields.io/pypi/v/pysimplegui.svg?label=tkinter%20PyPI%20Ver&color=red) | ![tkinter 2.7](https://img.shields.io/pypi/v/pysimplegui27.svg?label=tkinter%202.7%20PyPI%20Ver&color=red) | ![qt](https://img.shields.io/pypi/v/pysimpleguiqt.svg?label=qt%20PyPI%20Ver&color=red) | ![wx](https://img.shields.io/pypi/v/pysimpleguiwx.svg?label=wx%20PyPI%20Ver&color=red) | ![web](https://img.shields.io/pypi/v/pysimpleguiweb.svg?label=web%20PyPI%20Ver&color=red) |
| [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUI)](https://pypi.python.org/pypi/PySimpleGUI/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUI27)](https://pypi.python.org/pypi/PySimpleGUI27/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUIQt)](https://pypi.python.org/pypi/PySimpleGUIQt/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUIWx)](https://pypi.python.org/pypi/PySimpleGUIWx/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUIWeb)](https://pypi.python.org/pypi/PySimpleGUIWeb/) |
--------------------------
## GitHubの統計
| Issues | Commit Activity | Stars | Docs |
| -- | -- | -- | -- |
| ![GitHub issues](https://img.shields.io/github/issues-raw/PySimpleGUI/PySimpleGUI?color=blue) | ![commit activity](https://img.shields.io/github/commit-activity/m/PySimpleGUI/PySimpleGUI.svg?color=blue) | ![stars](https://img.shields.io/github/stars/PySimpleGUI/PySimpleGUI.svg?label=stars&maxAge=2592000) | ![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest) |
| ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/PySimpleGUI/PySimpleGUI?color=blue) | ![last commit](https://img.shields.io/github/last-commit/PySimpleGUI/PySimpleGUI.svg?color=blue) | |
<p align="center">
<img src="https://github-readme-stats.vercel.app/api/?username=PySimpleGUI&bg_color=3e7bac&title_color=ffdd55&icon_color=ffdd55&text_color=ffdd55&show_icons=true&count_private=true">
</p>
<hr>
# PySimpleGUIとは何ですか:question:
PySimpleGUIはあらゆるレベルのPythonプログラマがGUIを作成できるようにするPythonパッケージです。ウィジェットを含む「レイアウト」を使用して、GUIウィンドウを指定しますPySimpleGUIでは「エレメント」と呼びます。 レイアウトはサポートされている4つのフレームワークのいずれかを使用してウィンドウを作成して、ウィンドウ表示や操作するのに使用されます。 サポートされるフレームワークは、tkinter、Qt、WxPython、WxPythonまたはRemiが含まれます。このようなパッケージを「ラッパー」と呼ぶ場合があります。
PySimpleGUIは「ボイラープレートコード」の多くを実装しているため、基となるフレームワークで直接記述するよりも単純で短かいコードになります。
さらにインターフェイスは、望んだ結果を得るために、必要なコードをできるだけ少なくするように単純化されています。使用するプログラムやフレームワークにもよりますがPySimpleGUIでのプログラムはフレームワークのいずれかを直接使用して同じウィンドウを作成するよりも、コードの量は1/2から1/10程度になる場合があります。
目標は使用しているGUIフレームワーク上の特定のオブジェクトやコードをカプセル化/非表示にすることですが、必要に応じてフレームワークに依存しているウィジェットやウィンドウに直接アクセスできます。
設定や機能がまだ公開されておらずPySimpleGUI APIを使用してアクセスできない場合でも、フレームワークから遮断されてません。PySimpleGUIのパッケージ自体を直接変更せずに機能を拡張できます。
## 「GUIのギャップ」を埋める
Pythonはプログラミング コミュニティに多くの人々を招いています。プログラムの数と扱う領域の範囲は気が遠くなります しかし多くの場合、プログラムとテクロジーは一握りの人々以外の手の届かないところにあります。Pythonプログラムの大半は"コマンドライン"ベースです。プログラマー系の人はテキストインターフェイスを介してコンピューターとやり取りすることに慣れているため、この問題はありません。 プログラマーはコマンドラインインターフェイスに問題はありませんがほとんどの「普通の人」は問題を抱えています。 これにより、デジタル・ディバイド、「GUIのギャップ」が生み出されます。
プログラムにGUIを追加することで、そのプログラムはより多くの人に知ってもらえるようになります。プログラムはより親しみやすくなります。GUIはコマンドラインインターフェイースに慣れているプログラマーであっても、いくつかのプログラムの操作を簡単にできます。 そして最後にGUIを必要とする問題もあります。
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/GUI%20Gap%202020.png" width="600px">
</p>
<hr>
# 私について :wave:
こんにちは! 私はマイクです。 GitHubのPySimpleGUIで問題を解決してPySimpleGUIを継続的に前進させ続けています。私は昼と夜、そして週末もプロジェクトとPySimpleGUIユーザーに捧げてきました。私たちの成功は最終的に共有されます。 あなたが成功したときに私は成功しています。
Pythonでは相対的な新人ですが、70年代からソフトウェアを書いてきました。 私のキャリアの大半はシリコンバレーでの製品開発に費やされました。自分が開発してきた企業製品と同じような、プロフェッショナリズムと献身をPySimpleGUIにもたらします。今、あなたは私の顧客です。
## プロジェクトの目標 :goal_net:
PySimpleGUIプロジェクトの重要な目標は以下の2つです。
* 楽しむこと
* あなたの成功
真面目なプロジェクトのゴールとして**楽しむ**というのは変に聞こえるかもしれませんが、これは真面目な目標です。私はこれらのGUIプログラムを書くことはとても楽しいと思います。その理由の1つは、完全なソリューションの作成にかかる時間がいかに短いかということです。もし私達がプロセスを楽しんでいない場合は、誰かがあきらめています。
膨大な量のドキュメント、クックブック、すぐに使える100種類以上のデモプログラム、詳細なコールリファレンス、YouTubeのビデオ、オンラインのTrinketのデモなど、すべてが楽しい体験を生み出すために作用しています。
**あなたの成功**は共通の目標です。 PySimpleGUIは開発者向けに構築されました。あなたは私の仲間です。ユーザーとPySimpleGUIの共同作業の結果を見るのは予想外の報酬でした。ドキュメントやその他の資料を使用してアプリケーションの構築に役立ててください。トラブルに遭遇した場合は、[PySimpleGUI GitHub の問題](http://Issues.PySimpleGUI.org)でIssueを開いてヘルプを利用できます。 以下のサポートのセクションを見てください。
<hr>
# 教育リソース :books:
www.PySimpleGUI.orgは覚えやすく、ドキュメントが配置されている場所です。上部にはいくつかの異なるドキュメントを表すタブがあります。ドキュメントは「Read The Docs」に記載されており、各ドキュメントの目次があり、検索も簡単です。
数百ページの文書化されたドキュメントと数百のサンプルプログラムがあり、あなたが非常に速く効果を発揮するのに役立ちます。
単一のGUIパッケージを学ぶのに数日または数週間投資するよりも、PySimpleGUIを使用すると午後の時間だけでプロジェクトを完成させられるかもしれません。
## 例1 - ワンショットウィンドウ
このタイプのプログラムは、ウィンドウが1回表示されて収集された値が閉じられるため、「ワンショット」ウィンドウと呼ばれます。 ワードプロセッサのように長い間開いたままになっていません。
### 単純なPySimpleGUIプログラムの解剖学
PySimpleGUIプログラムには5つのセクションがあります
```python
import PySimpleGUI as sg # パート 1 - インポート
# ウィンドウの内容を定義する
layout = [ [sg.Text("お名前は何ですか?")], # パート 2 - レイアウト
[sg.Input()],
[sg.Button('はい')] ]
# ウィンドウを作成する
window = sg.Window('ウィンドウタイトル', layout) # パート 3- ウィンドウ定義
# ウィンドウを表示し、対話する
event, values = window.read() # パート 4- イベントループまたは Window.read 呼び出し
# 収集された情報で何かをする
print('ハロー ', values[0], "PySimpleGUIを試してくれてありがとう!")
# 画面から削除して終了
window.close() #パート 5 - ウィンドウを閉じる
```
コードは、以下のウィンドウを生成します
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/WhatsYourNameBlank1.jpg">
</p>
<hr>
## 例2 - インタラクティブウィンドウ
この例では、ユーザーがウィンドウを閉じるか、または [終了] ボタンをクリックするまで、ウィンドウは画面上に残ります。先ほど見たワンショットウィンドウとインタラクティブウィンドウの主な違いは、「イベントループ」の追加です。イベントループはウィンドウからイベントと入力を読み込みます。アプリケーションの中心はイベントループになります。
```python
import PySimpleGUI as sg
# ウィンドウの内容を定義する
layout = [[sg.Text("お名前は何ですか?")],
[sg.Input(key='-入力-')],
[sg.Text(size=(55,1), key='-出力-')],
[sg.Button('はい'), sg.Button('終了')]]
# ウィンドウを作成する
window = sg.Window('ウィンドウタイトル',レイアウト)
# イベントループを使用してウィンドウを表示し、対話する
while True:
event, values = window.read()
# ユーザーが終了したいのか、ウィンドウが閉じられたかどうかを確認してください
if event == sg.WINDOW_CLOSED or event == '終了':
break
# Output a message to the window
window['-出力-'].update('ハロー ' + values['-入力-'] + "! PySimpleGUI をお試しいただきありがとうございます")
# 画面から削除して終了
window.close()
```
以下は、例2が作成するウィンドウです。
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/WhatsYourNameBlank.jpg">
</p>
入力フィールドに値を入力して [OK] ボタンをクリックした後の表示は次のようになります。
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/HelloWorld1.jpg">
</p>
この例とワンショット ウィンドウの違いについて簡単に見てみましょう。
まず、レイアウトの違いに気づくでしょう。とくに2つの変更が重要です。1つは`Input`エレメントと`Text`エレメントの1つに`key`パラメーターを追加することです。「key」はエレメントの名前のようなものです。 またはPythonの辞書キーのようなものです。 `Input`エレメントのキーは、コードの後半で辞書キーとして使用されます。
もう1つの違いは、この `Text`エレメントの追加です:
```python
[sg.Text(size=(40,1), key='-OUTPUT-')],
```
すでにカバーしている「キー」という2つのパラメーターがあります。 `Size`パラメーターはエレメントの文字数のサイズを定義します。 この場合、`Text`エレメントは幅40文字、高さ1文字であることを示しています。テキストの文字列が指定されていないので空白で表示されていことに注意してください。 作成されたウィンドウでは空白行になっているのがわかります。
また 、[終了]ボタンを追加しました。
イベントループには、おなじみの`window.read()`呼び出しがあります。
読み込んだ後に続くのは、このif文です。
```python
if event == sg.WINDOW_CLOSED or event == '終了':
break
```
このコードは、ユーザーが「X閉じる」をクリックしてウィンドウを閉じたか、または「終了」ボタンをクリックしたかどうかを確認します。 これらのいずれかが発生した場合、コードはイベント ループから抜け出します。
ウィンドウが閉じられず、「終了」ボタンがクリックされていない場合は動作が継続されます。 起こりうる唯一の事は、ユーザーが「OK」ボタンをクリックしたことです。 イベントループの最後のステートメントは次のとおりです。
```python
window['-OUTPUT-'].update('ハロー ' + values['-INPUT-'] + "! PySimpleGUI をお試しいただきありがとうございます")
```
このステートメントは、`-OUTPUT-`キー を持つ`Text`エレメントを文字列で更新します。`window['-OUTPUT-']``-OUTPUT-`キーを持つエレメントを検索します。 キーは、空白の`Text`エレメントに属します。 エレメントが検索から返されると、そのエレメントの`update`メソッドが呼び出されます。 ほとんどすべてのエレメントは`update`メソッドを持っています。 このメソッドはエレメントの値や構成を変更したりするのに使用します。
テキストを黄色にしたい場合は、`update`メソッドに`text_color`パラメーターを追加して以下のように処理します。
```python
window['-出力-'].update('ハロー ' + values['-入力-'] + "! PySimpleGUI をお試しいただきありがとうございます", text_color='yellow')
```
`text_color`パラメーターを追加した後、これが新しい結果ウィンドウとなります。
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/HelloWorldYellow.jpg">
</p>
各エレメントで使用できるパラメーターは[call referenceドキュメント](http://calls.PySimpleGUI.org)とdocstringsの両方に記載されています。PySimpleGUIには利用可能なすべてのオプションを理解するのに役立つ豊富なドキュメントが用意されています。`Text`エレメントの`update'`メソッドを検索すると、以下のような定義が見つかります:
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/TextUpdate.jpg">
</p>
ご覧のように、いくつかのものは、`Text`エレメントに変更できます。 call referenceドキュメントはPySimpleGUIでのプログラミングを簡単にする貴重なリソースです。
<hr>
## レイアウトはおもしろいです(笑)! :laughing:
ウィンドウのレイアウトは「リストのリスト」(LOL)です。 ウィンドウは「行」に分割されます。 ウィンドウの各行はレイアウトのリストになります。 すべてのリストを連結すると、レイアウトができあがります。リストのリストです。
行の定義を簡単に確認にするため、各行に追加で 'Text' エレメントを追加しました。レイアウトは自体は以前と同じです:
```python
layout = [ [sg.Text('ライン 1'), sg.Text("お名前は何ですか")],
[sg.Text('ライン 2'), sg.Input()],
[sg.Text('ライン 3'), sg.Button('はい')] ]
```
このレイアウトの各行は、ウィンドウ内の行に表示されるエレメントのリストです。
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/rows.jpg">
</p>
リストを使用してGUIを定義する場合、他のフレームワークを使用してGUIプログラミングを行う方法にくらべていくつかの大きな利点があります。 たとえば、Pythonのリスト内包表記を利用して、1行のコードでボタンのグリッドを作成できます。
次の3行のコードです。
```python
import PySimpleGUI as sg
layout = [[sg.Button(f'{row}, {col}') for col in range(4)] for row in range(4)]
event, values = sg.Window('List Comprehensions', layout).read(close=True)
```
ボタンの4 x 4グリッドを持つウィンドウを生成します。
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/4x4grid.jpg">
</p>
「楽しむ」がプロジェクトの目的の1つであることを思い出してください。 Pythonの強力な基本機能をGUIの問題に直接適用するのは楽しいです。GUIを作成するコードのページの代わりに、数行または多くの場合は1行のコードを作成します。
## コードの折りたたみ
ウィンドウのコードを1行のコードに凝縮できます。 レイアウトの定義、ウィンドウ作成、表示、およびデータ収集はすべて、次の1行のコードで書けます。
```python
event, values = sg.Window('Window Title', [[sg.Text("お名前は何ですか?")],[sg.Input()],[sg.Button('はい')]]).read(close=True)
```
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/WhatsYourName.jpg">
</p>
同じウィンドウが表示され、PySimpleGUIプログラムのセクションを示す例と同じ値が返されます。 非常に少ない量で多くのことを行うことができるため、Pythonコードにすばやく簡単にGUIを追加できます。 データを表示してユーザーからの選択を得たい場合は、1ページのコードではなく1行のコードで行うことができます。
短縮エイリアスを使用してより少ない文字数でコードのスペースをさらに短くできます。すべてのエレメントには、使用できる短い名前が1つ以上含まれています。 たとえば、`Text`エレメントは単に`T`として書けます。`Input`エレメントは `I``Button``B`と書けます。 したがって、ウィンドウの1行のコードは以下になります:
```python
event, values = sg.Window('Window Title', [[sg.T("あなたの名前は何ですか?")],[sg.I()],[sg.B('はい')]]).read(close=True)
```
### コードの移植性
PySimpleGUIは現在、4つのPythonのGUIフレームワークで実行できます。 使用するフレームワークは、importステートメントを使用して指定します。 インポートを変更すると、基本のGUIフレームワークが変更されます。プログラムによっては、別のGUIフレームワークで実行するためにはimport文以外の変更は必要ありません。 上記の例では、インポートを`PySimpleGUI`から`PySimpleGUIQt``PySimpleGUIWx``PySimpleGUIWeb``PySimpleGUIWeb`に変更すると、フレームワークが変更されます。
| ステートメントをインポート | 結果ウィンドウ |
|--|--|
| PySimpleGUI | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-tkinter.jpg) |
| PySimpleGUIQt | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-Qt.jpg) |
| PySimpleGUIWx | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-WxPython.jpg) |
| PySimpleGUIWeb | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-Remi.jpg) |
GUIのコードをあるフレームワークから別のフレームワークに移植するたとえば、コードをtkinterからQtに変更するには、通常はコードの書き換えが必要です。PySimpleGUIは、フレームワーク間の簡単な移動を可能にするように設計されています。 場合によってはいくつかの変更が必要ですが目的は最小限の変更で移植性の高いコードを作ることです。
システムトレイアイコンなどの一部の機能は、すべてのポートで使用できないです。 システムトレイアイコン機能はQtおよびWxPythonポートで使用できます。シミュレートされたバージョンはtkinterで使用できます。システムトレイアイコンは、PySimpleGUIWebポートではサポートされません。
## ランタイム環境
|環境 |サポートされる |
|--|--|
|パイソン| Python 3.4+ |
|オペレーティング システム |ウィンドウズ,Linux,マック |
|ハードウェア |デスクトップPC,ノートパソコン,ラズベリーパイ,PyDroid3 を実行しているアンドロイドデバイス |
|オンライン |repli.it,Trinket.comどちらもブラウザ上でtkinterを実行する|
|GUIフレームワーク |tkinter, pyside2, WxPython, Remi |
## 統合
200以上の「デモプログラム」の中には、多くの人気のPythonパッケージをGUIに統合する方法の例が見つかります。
ウィンドウにMatplotlibの描画を埋め込みたいですか、問題ありません、 デモコードをコピーすると即座にあなたの夢のMatplotlibの描画をあなたのGUIに組み込めます。
これらのパッケージやその他のパッケージは、デモプログラムやデモレポが用意されているので、GUIに入れる準備ができています。
|パッケージ |説明 |
|--|--|
Matplotlib |グラフやプロットの多くの種類 |
OpenCV |コンピュータビジョンAIでよく使用さる |
VLC |ビデオ再生 |
pymunk |物理エンジン|
psutil |システム環境の統計 |
prawn |Reddit API |
json |PySimpleGUIは、「ユーザー設定」を格納する特別なAPIをラップします。 |
weather |お天気アプリを作るためにいくつかの天気APIと統合 |
mido |MIDIの再生 |
beautiful soup |ウェブスクレイピングGitHub issueウォッチャーでの例 |
<hr>
# インストール :floppy_disk:
PySimpleGUIをインストールする一般的に2つの方法があります。
1. PyPIからpipでインストールする
2. PySimpleGUI.pyファイルをダウンロードしてアプリケーションのフォルダーに配置します
### Pipインストールとアップグレード
現在提案されている`pip`コマンドを呼び出す方法は、Pythonを使ってモジュールとして実行することです。 以前は、`pip`または`pip3`コマンドはコマンドライン/シェル上で
直接実行されました。 提案された方法は以下となります。
Windowsの初期インストール
`python -m pip install PySimpleGUI`
LinuxおよびmacOSの初期インストール
`python3 -m pip install PySimpleGUI`
`pip`を使用してアップグレードするには、単に2つのパラメーター`--upgrade --no-cache-dir`を指定するだけです。
Windowsのアップグレード
`python -m pip install --upgrade --no-cache-dir PySimpleGUI`
LinuxおよびmacOSのアップグレード
`python3 -m pip install --upgrade --no-cache-dir PySimpleGUI`
### 単一ファイルのインストール
PySimpleGUIはRaspberry Piのようなインターネットに接続されていないシステムでも、簡単にインストールできるように単一の.py ファイルとして作成されました。 PySimpleGUI.pyファイルをインポートするアプリケーションと同じフォルダーに置くだけです。Pythonはインポート時にローカルのコピーを使用します。
.pyファイルを使用してインストールする場合は、PyPIから入手するか、最新の未リリースバージョンを実行したい場合はGitHubからダウンロードします。
PyPIからインストールするには、wheelまたは.gzファイルをダウンロードして解凍します。.whlファイルをzipにリネームすると、通常のzipファイルと同じように開くことができます。 フォルダーの中にはPySimpleGUI.pyファイルがあります。 このファイルをアプリケーションのフォルダーにコピーすると完了です。
tkinterバージョンのPySimpleGUIのPyPIリンクです
https://pypi.org/project/PySimpleGUI/#files
GitHubリポジトリの最新バージョンは、こちらで確認できます
https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/PySimpleGUI.py
「そうだけど、巨大なソースファイルを1つだけ持つのはなんてひどい考えだ」と今、考えている人もいるでしょう。 これは*時には*ひどい考えかもしれません。 今回は、メリットはデメリットを大幅に上回りました。 コンピュータサイエンスの概念の多くはトレードオフまたは主観的なものです。 一部の人が望むのと同じくらいすべてが白黒ではありません。 多くの場合、この質問に対する答えは「次第」です。
## ギャラリー :art:
ユーザーが投稿したGUIとGitHubにあるGUIのより正式なギャラリーの作成は進行中ですが、readmeを作成時点ではまだ完成していません。現在まとまってスクリーンショットを見れる場所は2か所あります。願わくは人々が作っている素晴らしい作品を正当化するためのWikiやその他の仕組みがすぐにリリースされることを願っています。
### ユーザーが提出したギャラリー
1つ目は、GitHubにある[ユーザーがスクリーンショットを提出したissue](https://github.com/PySimpleGUI/PySimpleGUI/issues/10)です。 これは、人々が作ったものを披露するための非公式な方法です。 理想的ではありませんがスタートでした。
### 大量にスクラップされたGitHubの画像
2つ目は、PySimpleGUIを使用していると伝えられているGitHubの1,000のプロジェクトか集めた[3,000以上の画像の大規模なギャラリー ](https://www.dropbox.com/sh/g67ms0darox0i2p/AAAMrkIM6C64nwHLDkboCWnaa?dl=0)です。 手作業でフィルタリングされており初期のドキュメントで使用されていた古いスクリーンショットがたくさんあります。 しかし、そこにあなたの想像力を引き起こす何かが見つかもしれません。
<hr>
# PySimpleGUIの用途について :hammer:
次のセクションでは、PySimpleGUIの用途の一部を紹介します。 GitHubだけでも1,000以上のプロジェクトでPySimpleGUIを使用しています。これだけの多くの人々の可能性が広がったことは本当に驚くべきことです。 多くのユーザーは以前にPythonでGUIを作成しようとして失敗したと話していましたが、彼らがPySimpleGUIを試してみて最終的に自分の夢を達成できたと話しています。
## 最初のGUI
もちろん、PySimpleGUIのもっとも優れた使い方の1つはPythonプロジェクト用のGUIを作ることです。 ファイル名をリクエストするだけの小さなプロジェクトから開始できます。 このためには、`popup`と呼ばれる「ハイレベル関数」の1つを1回呼び出すだけで済みます。 ポップアップにはあらゆる種類があり、一部は情報を収集します
`popup`自体で情報を表示するためのウィンドウを作成します。printと同じように複数のパラメーターを渡せます。情報を取得したい場合は、`popup_get_filename`のように`popup_get_`で始まる関数を呼び出すします。
コマンドラインでファイル名を指定する代わりに、ファイル名を取得するための1行を追加することで、プログラムは「普通の人」が快適に使用できるプログラムに変身します。
```python
import PySimpleGUI as sg
filename = sg.popup_get_file('処理したいファイルを入力してください')
sg.popup('入力した', filename)
```
このコードは、2つのポップアップウィンドウを表示します。 1つはファイル名を取得するためで、入力ボックスの閲覧やペーストができます。
<p align="center">
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/popupgetfilename.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/popupgetfilename.jpg" alt="img" width="400px"></a>
</p>
もう一方のウィンドウは収集された内容を出力します。
<p align="center">
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/popupyouentered.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/popupyouentered.jpg" alt="img" width="175px"></a>
</p>
<br>
## Rainmeter風スタイルウィンドウ
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/RainmeterStyleWidgets.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/RainmeterStyleWidgets.jpg" alt="img" align="right" width="500px"></a>
GUIフレームワークのデフォルト設定では見栄えの良いウィンドウは作成できません。しかし細部に注意することでウィンドウを魅力的に見せるためにいくつかのことをおこなえます。 PySimpleGUIは、色やタイトルバーの削除などの機能をより簡単に操作できます。 その結果、典型的なtkinterのようには見えないウィンドウができます。
ここでは、典型的なtkinterのように見えないウィンドウをWindowsで作成する方法の例を紹介します。 この例ではウィンドウのタイトル バーが削除されています。その結果としてデスクトップウィジェットプログラムのRainmeterように見えるウィンドウができあがります。
<br><br>
ウィンドウの透明度も簡単に設定できます。 同じRainmeterスタイルのデスクトップウィジェットの他の例を紹介します。 半透明なので、薄暗く表示される場合もあります。
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/semi-transparent.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/semi-transparent.jpg" alt="img" align="right" width="500px"></a>
タイトルバーの削除とウィンドウの半透明化の両方の効果はウィンドウを作成する際に2つのパラメータを設定することで実現しています。 これはPySimpleGUIがいかに機能に簡単にアクセスできるかを示す例です。 また、PySimpleGUI のコードはGUIフレームワーク間で移植可能なので、Qtのような他のポートでも同じパラメータで動作します。
例1のウィンドウ作成の呼び出しを以下のコードに変更すると同様の半透明のウィンドウが作成されます。
```python
window = sg.Window('My window', layout, no_titlebar=True, alpha_channel=0.5)
```
## ゲーム
ゲーム開発用のSDKとしては特に記述されていませんが、PySimpleGUIはゲームの開発を非常に簡単にします。
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Chess.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Chess.png" alt="img" align="right" width="500px"></a>
このチェスプログラムはチェスをするだけでなく、チェスAI「Stockfish」を統合します。
<br><br><br><br><br><br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Minesweeper.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Minesweeper.gif" alt="img" align="right" width="500px"></a>
マインスイーパのいくつかのバリエーションがユーザーによってリリースされました。
<br><br><br><br>
<br><br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/minesweeper_israel_dryer.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/minesweeper_israel_dryer.png" alt="img" align="right" width="500px"></a>
<br><br><br><br><br><br><br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Solitaire.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Solitaire.gif" alt="img" align="right" width="500px"></a>
<br><br>
PySimpleGUIの`Graph`エレメントを使用すると画像の操作が簡単なので、カードゲームはPySimpleGUIを使用すると簡単です。
ゲーム開発用のSDKとして書かれたわけではありませんが、PySimpleGUIはゲームの開発を非常に簡単にします。<br><br>
<br><br>
<br><br><br>
## メディアのキャプチャと再生
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/OpenCV.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/OpenCV.jpg" alt="img" align="right" width="400px"></a>
WEBカメラからビデオをキャプチャしてGUIで表示するのには、PySimpleGUIのコードでは4行でできます。 さらに印象的なのはこらの4行のコードがtkinter、Qt、および Webポートで動作します。 tkinterを使用して画像を表示するのと同じコードを使用して、ブラウザでWebカメラをリアルタイムが表示できます。
また、VLCプレーヤーを使って、オーディオやビデオなどのメディア再生も可能です。デモアプリケーションが提供されているので実際の作業例が用意されています。このreadmeに記載されている内容は全て、あなた自身の創作の出発点として利用できます。
<br><br><br><br><br>
<br><br><br><br><br>
<br><br>
## 人工知能
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO_GIF.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO_GIF.gif" alt="img" align="right" width="500px"></a>
AIとPythonは長い間、この2つが組み合わされたときのスーパーパワーとして認識されてきました。しかし、多くの場合、ユーザーがGUIを使用してこれらのAIアルゴリズムを身近に操作する方法が欠けています。
これらのYOLOのデモは、GUIがAIアルゴリズムとの対話においていかに大きな違いをもたらすかの素晴らしい例です。 これらのウィンドウの下部にある2つのスライダーに注目してください。 この2つのスライダーは、YOLOアルゴリズムが使用するパラメーターを変更します。
コマンドラインのみを使用してYOLOデモをチューニングする場合は、アプリケーションを起動するときに、パラメーターを設定し、その実行方法を確認して、アプリケーションを停止し、パラメーターを変更して最後に新しいパラメーターでアプリケーションを再起動する必要があります。
<br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO%20Object%20Detection.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO%20Object%20Detection.jpg" alt="img" align="right" width="500px"></a>
これらのステップと、GUIを使用して実行できる操作と比較してみます。 GUIを使用すると、これらのパラメーターをリアルタイムで変更できます。 アルゴリズムにどのような影響を与えているかについて、すぐにフィードバックを得られます。
<br><br><br><br><br>
<br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Colorizer.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Colorizer.jpg" alt="img" align="right" width="500px"></a>
公開されているAIプログラムには、コマンドラインで動かすプログラムが非常に多く存在します。 これ自体は大きなハードルではありませんが、コマンドラインでカラーリングしたいファイル名を入力/貼り付け、プログラムを実行して、出力ファイルの結果をファイルビューアーで開くのは十分「面倒くさい」です。
GUIには、**ユーザーエクスペリエンスを変更する**を「GUIギャップ」に変化させる力があります。 このカラーライズの例では、ユーザーは画像が格納されてたフォルダーを指定して、画像をクリックするだけでカラーリングと結果表示の両方を行えます。
カラーライズを行うプログラム/アルゴリズムは自由に利用可能で、使用可能でした。 不足していたのはGUIがもたらす使いやすさです。
<hr>
## グラフ化
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/CPU%20Cores%20Dashboard%202.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/CPU%20Cores%20Dashboard%202.gif" alt="img" align="right" width="500px"></a>
GUIでのデータの表示と操作はPySimpleGUIを使用すると簡単です。いくつかのオプションがあります。
組み込みの描画/グラフ作成機能を使用してカスタムグラフを作成できます。 このCPU使用率モニタは`Graph`エレメントを使用します。
<br><br>
<br><br>
<br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib.jpg" alt="img" align="right" width="500px"></a>
MatplotlibはPythonユーザーに人気があります。 PySimpleGUIは、MatplotlibのグラフをGUIウィンドウに直接埋め込めます。 Matplotlibのインタラクティブ機能を保持したい場合はインタラクティブコントロールをウィンドウに埋め込むこともできます。
<br><br>
<br><br>
<br><br>
<br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib2.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib2.jpg" alt="img" align="right" width="500px"></a>
PySimpleGUIのカラーテーマを使用すると、ほとんどの人がMatplotlibで作成するデフォルトのグラフよりも一段上のグラフを作成できます。
<br><br>
<br><br>
<br><br>
<br><br>
<br><br>
<br><br>
<br><br>
<hr>
## フロントエンド
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/JumpCutter.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/JumpCutter.png" alt="img" align="right" width="500px"></a>
前述の「GUIギャップ」は、PySimpleGUIを使用して簡単に解決できます。 GUIを追加するプログラムにソースコードを用意する必要もありません。「フロントエンド」GUI は、コマンドラインアプリケーションに渡す情報を収集するGUIです。
フロントエンドGUIは、プログラマにとってユーザーがコマンドライン・インターフェーイスを使い心地よく感じなかったために、以前は使いたがらなかったアプリケーションを配布するための素晴らしい方法です。これらのGUIは、ソースコードにアクセスできないコマンドラインプログラムのための唯一の選択肢です。
この例は、「Jump Cutter」というプログラムのフロントエンドです。 パラメーターはGUIをとおして収集されて、パラメーターを使用してコマンドラインが構築され、コマンドラインプログラムの出力がGUIインターフェイスにルーティングされてコマンドが実行されます。この例では、実行されたコマンドが黄色で表示されています。
<br><br>
<hr>
## Raspberry Pi
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Raspberry%20Pi.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Raspberry%20Pi.jpg" alt="img" align="right" width="500px"></a>
PySimpleGUIはPython 3.4に対応しているため、Raspberry Piのプロジェクト用のGUIを作成できます。 タッチスクリーンと組み合わせるととくにうまく機能します。 モニターが接続されていない場合は、PySimpleGUIWebを使用してPiを制御することもできます。
<br><br>
<br><br>
<br><br>
<br><br><br>
<hr>
## 高度な機能への簡単なアクセス
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Customized%20Titlebar.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Customized%20Titlebar.gif" alt="img" align="right" width="500px"></a>
基礎となるGUIフレームワークの多くの機能に非常に簡単にアクセスできるため、GUIフレームワークを直接使っているようには見えないアプリケーションを作るための機能を組み合わせられます。
たとえば、tkinterやその他のGUIパッケージを使用してタイトルバーの色や外見を変更することはできませんが、PySimpleGUIを使用すると、カスタムタイトルバーを持っているかのように表示されるウィンドウを簡単に作成できます。
<br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Desktop%20Bouncing%20Balls.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Desktop%20Bouncing%20Balls.gif" alt="img" align="right" width="500px"></a>
信じられないことに、このウィンドウはスクリーンセーバーのように見えるものを実現するためにtkinterを使用しています。
ウィンドウではtkinter はアプリケーションから背景を完全に取り除けます。 繰り返しますがPySimpleGUIはこれらの機能へのアクセスを簡単にします。 透明なウィンドウを作成するには、`Window`を作成する呼び出しにパラメータを1つ追加する必要があります。 1つのパラメータ変更だけで、次の効果を持つ単純なアプリケーションを作成できます。
デスクトップ上のすべてのものをフルスクリーンウィンドウをクリックして操作できます。
<hr>
# テーマ
デフォルトのグレーのGUIにうんざりしましたか? PySimpleGUI は`theme`関数の呼び出しを行うこだけで、ウィンドウの見た目を素敵にします。 150種類以上のカラーテーマを選択できます:
<p align="center">
<a href=""><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ThemePreview.jpg" alt="img" width="900px"></a>
</p>
ほとんどのGUIフレームワークでは、作成するすべてのウィジェットの色を指定する必要があります。 PySimpleGUIは、この雑用を代わりに行い自動的に選択したテーマに合わせてエレメントを色付けします。
テーマを使用するには、ウィンドウを作成する前にテーマ名を指定して`theme`関数を呼び出します。読みやすくするためにスペースを追加できます。 テーマを「dark grey 9」に設定するには
```python
import PySimpleGUI as sg
sg.theme('dark grey 9')
```
この1行のコードでウィンドウの外観を完全に変更します:
<p align="center">
<a href=""><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/DarkGreyJapanese.jpg" alt="img" width="400px"></a>
</p>
テーマは、背景、テキスト、入力背景、入力テキスト、およびボタンの色を変更しました。 このような配色を変更する他のGUIパッケージでは、各ウィジェットの色を個別に指定する必要があり、コードを何度も変更する必要があります。
<hr>
# サポート:muscle:
最初のステップは[ドキュメンテーション](http://www.PySimpleGUI.org)と[デモプログラム](http://Demos.PySimpleGUI.org)でなければなりません。 です。もしまだ質問があったり、ヘルプが必要な場合は...問題ありません...ヘルプは無料で提供されています。PySimpleGUIのGitHubリポジトリで[Issueを提出](http://Issues.PySimpleGUI.org)するだけで、助けが得られます。
ほとんどのソフトウェア会社は、バグレポートに付随するフォームを持っています。 それは悪い取引ではありません.フォームに必要事項記入すれば、無料でソフトウェアのサポートを受けられます。この情報は効率的に回答を得るのに役立ちます。
PySimpleGUIのバージョン番号や基になるGUIフレームワークなどの情報を要求するだけでなく、問題の解決に役立つかもしれない項目のチェックリストも提供されます。
***フォームに記入してください 。***  あなたには無意味に感じるかもしれません。ほんの一瞬ですが苦痛に感じるかもしれません。記入はあなたがより早く解決策を得るのに役立ちます。もしあなたがスピーディーな回答と解決を得るために役立つ必要な情報でなければ、記入は必要ではありません。「私はあなたを助けるために私を助ける」。
# 支援する <a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/PSGSuperHero.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/PSGSuperHero.png" alt="img" width="90px"></a>
プロジェクトの財政的支援は非常に高く評価されています。 正直に言うと、経済的な援助が必要です。 ライトをつけ続けるだけで高価です。 ドメイン名登録、トリンケット、コンサルティングヘルプなどのサブスクリプションの長いリストは、すぐにかなりの経常コストに加算されます。
PySimpleGUIの開発は安くありませんでした。愛情をこめて開発したとはいえ何年にもわたって非常に手間のかかる開発でした。こんにちの姿になるのにかなりの時間をついやしました。現在も続けています。
PySimpleGUIにはオープンソースライセンスがあり、そのまま残ることができれば素晴らしいことです。 お客様またはお客様の会社 (特に企業でPySimpleGUIを使用している場合) が、PySimpleGUIを使用して経済的に利益を得ている場合は、プロジェクトの寿命を延長する機会を持っています。
### Buy Me a Coffee
「Buy Me a Coffee」は、開発者を公的にサポートするための素晴らしい方法です。 素早く、簡単に、貢献は記録されるので、あなたがPySimpleGUIのサポーターであることを他の人に見せられます。寄付を非公開にもできます。
<a href="https://www.buymeacoffee.com/PySimpleGUI" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/arial-yellow.png" alt="Buy Me A Coffee" width="217px" ></a>
### GitHubスポンサー
<a href="https://github.com/sponsors/PySimpleGUI" target="_blank"><img src="https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=%3Curl%3E&color=f88379"></a>
[GitHub定期的なスポンサーシップ](https://github.com/sponsorsー/PySimpleGUI)は、継続的にさまざまなレベルのサポートでプロジェクトをスポンサーする方法です。これにより、多くのオープンソース開発者が企業レベルのスポンサーシップを受けられます。
プロジェクトに金銭的に貢献していただけると、非常にありがたいです。オープンソースの開発者であることは、経済的に困難です。YouTube動画のクリエイターは、動画作成で生計を立てています。オープンソース開発者にとってはまだそれほど簡単ではありません。
# 感謝の気持ちをこめて
<!--
To everyone that's helped, in whatever fashion, I'm very very grateful.
Even taking a moment to say "thank you" helps, and a HUGE number of you have done that. It's been an amazing number actually. I value these thanks and find inspiration in the words alone. Every message is a little push forward. It adds a little bit of energy and keeps the whole project's momentum. I'm so very grateful to everyone that's helped in whatever form it's been.
-->
どんな形でも協力してくれた皆さんにはとても感謝しています。
一瞬でも "ありがとう "と言ってくれるだけでも助かるし、とても多くの人たちががそうしてくれましたた。 実際、驚くべき人数です。 私はこの感謝の気持ちを大切にしてその言葉だけでインスピレーションを得ています。 すべてのメッセージは少しずつ前進しています。 メッセージはちょっとしたエネルギーとなってプロジェクト全体の勢いを保っています。 どのような形であれ協力してくれた皆さんには本当に感謝しています。
# Contributing 👷
# 貢献:construction_worker:
現在、PySimpleGUIはオープンソースライセンスでライセンスされていますが、プロジェクト自体は製品のように構成されています。プルリクエストは受け付けていません。
コードに貢献する最良の方法の1つは、アプリケーションを書いて公開することです。ユーザーは他のユーザーが作ったものを見て刺激を受けます。GitHubリポジトリを作成してコードを投稿しte
、スクリーンショットをreadmeファイルに入れましょう。
不足している機能があったり、機能強化を提案したい場合は、[issueを開いてください](https://github.com/PySimpleGUI/PySimpleGUI/issues/new?assignees=&labels=&template=issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md&title=%5B+Enhancement%2FBug%2FQuestion%5D+My+problem+is.) 。
# 特別な感謝 :pray:
<!--
This version of the PySimpleGUI readme wouldn't have come together without the help from @M4cs. He's a fantastic developer and has been a PySimpleGUI supporter since the project's launch. @israel-dryer is another long-term supporter and has written several PySimpleGUI programs that pushed the envelope of the package's capabilities. The unique minesweeper that uses an image for the board was created by Israel. @jason990420 surprised many when he published the first card game using PySimpleGUI that you see pictured above as well as the first minesweeper game made with PySimpleGUI. @Chr0nicT is the youngest developer I've worked with, ever, on projects. This kid shocks me on a regular basis. Ask for a capability, such as the PySimpleGUI GitHub Issues form error checking bot, and it simply happens regardless of the technologies involved. I'm fortunate that we were introduced. Someday he's going to be whisked away, but until then we're all benefiting from his talent. The Japanese version of the readme was greatly improved with help from @okajun35. @nngogol has had a very large impact on the project, also getting involved with PySimpleGUI in the first year of initial release. He wrote a designer, came up with the familiar window[key] lookup syntax, wrote the tools that create the documentation, designed the first set of doc strings as well as tools that generate the online documenation using the PySimpleGUI code itself. PySimpleGUI would not be where it is today were it not for the help of these individuals.
The more than 2,200 GitHub repos that use PySimpleGUI are owed a "Thank You" as well, for it is you that has been the inspiration that fuels this project's engine.
The overseas users that post on Twitter overnight are the spark that starts the day's work on PySimpleGUI. They've been a source of positive energy that gets the development engine started and ready to run every day. As a token of appreciation, this readme file has been translated into Japanese.
You've all been the best user community an Open Source developer could hope for.
-->
このバージョンのPySimpleGUIreadmeは、[@M4cs](https://github.com/M4cs)の助けがなければ完成しませんでした。彼は素晴らしい開発者であり、プロジェクトの立ち上げ以来、PySimpleGUIのサポーターです。 [@israel-dryer](https://github.com/israel-dryer)は、もう1つの長期的なサポーターであり、パッケージの機能の限界を押し上げるいくつかのPySimpleGUIプログラムを作成しています。ボードの画像を使用するユニークな掃海艇は、israelによって作成されました。 [@jason990420](https://github.com/jason990420)は、上の写真にあるPySimpleGUIを使用した最初のカードゲームと、PySimpleGUIで作成された最初のマインスイーパゲームを公開したときに多くの人を驚かせました[@Chr0nicT](https://github.com/Chr0nicT)はこれまで一緒にプロジェクトを進めてきた中で最年少の開発者です。この子は定期的に私を驚かせてくれます。例えばPySimpleGUIのGitHub Issuesフォームのエラーチェックボットのような機能を求めると、関係する技術に関わらず簡単に実現してしまうのです。縁があって出会いました。いつの日か彼は去ってしまうかもしれませんが、それまでは私たちは彼の才能から恩恵を受けています。日本語版のreadmeは[@okajun35](https://github.com/okajun35)の助けを借りて大幅に改善されました。 [@nngogol](https://github.com/nngogol)はプロジェクトに非常に大きな影響を与え、初期リリースの最初の年には PySimpleGUIに関わってくれました。彼はデザイナーを書き、おなじみのwindow[key] ルックアップシンタックスを考案しました。またドキュメントを作成するツールを書きいて最初のdoc stringsを設定して、、PySimpleGUIコード自体を使ってオンライン・ドキュメントを生成するツールを作成しました。これらの人々の助けがなければPySimpleGUIは今日のようにはなりませんでした。
PySimpleGUIを使用する1,200を超えるGitHubリポジトリにも「ありがとう」があります。これは、。このプロジェクトのエンジンを動かしているのは、あなたのインスピレーションです。
一晩中Twitterに投稿してくれる海外のユーザーは、PySimpleGUIの一日の作業を始めるきっかけとなります。彼らはポジティブなエネルギーの源であり、開発エンジンを始動させ、毎日稼働させる準備をしてくれています。感謝の意を込めて、このreadmeファイルを[日本語](https://github.com/PySimpleGUI/PySimpleGUI/blob/master/readme.ja.md)に翻訳しました。
皆さんはオープンソース開発者が望む最高のユーザーコミュニティです。
&copy; Copyright 2021 PySimpleGUI

885
PySimpleGUI/readme.md Executable file
View File

@@ -0,0 +1,885 @@
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Logo%20with%20text%20for%20GitHub%20Top.png" alt="Python GUIs for Humans">
<h2 align="center">Python GUIs for Humans</h2>
</p>
<table>
<tr>
<td>
<img src="https://www.dropbox.com/s/6wzf3ebmj97v4zs/PySimpleGUI-GitHub-Udemy-Course.png?raw=1" width=200 alt="PySimpleGUI Udemy Course">
</td>
<td>
<h5>apply coupon for discount:<br>65DBBEA0EC4C3B093FD1</h6>
<a href="https://www.udemy.com/course/pysimplegui/?couponCode=65DBBEA0EC4C3B093FD1">click here to visit course page</a>
</td>
</tr>
</table>
Transforms the tkinter, Qt, WxPython, and Remi (browser-based) GUI frameworks into a simpler interface. The window definition is simplified by using Python core data types understood by beginners (lists and dictionaries). Further simplification happens by changing event handling from a callback-based model to a message passing one.
Your code is not _required_ to have an object oriented architecture which makes the package usable by a larger audience. While the architecture is simple to understand, it does not *necessarily* limit you to only simple problems.
Some programs are not well-suited for PySimpleGUI however. By definition, PySimpleGUI implements a subset of the underlying GUI frameworks' capabilities. It's difficult to define exactly which programs are well suited for PySimpleGUI and which are not. It depends on the details of your program. Duplicating Excel in every detail is an example of something not well suited for PySimpleGUI.
[Japanese version of this readme](https://github.com/PySimpleGUI/PySimpleGUI/blob/master/readme.ja.md).
PySimpleGUI needs your support. If you find PySimpleGUI useful, please consider sponsoring the project on GitHub or BuyMeACoffee. It's expensive working full-time on PySimpleGUI and also paying for ongoing expenses (domains, artists, software, consultants, sponsoring open source projects).
<a href="https://www.buymeacoffee.com/PySimpleGUI" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/arial-yellow.png" alt="Buy Me A Coffee" width="217px" ></a>
<a href="https://github.com/sponsors/PySimpleGUI" target="_blank"><img src="https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=%3Curl%3E&color=f88379"></a>
<hr>
# Statistics 📈
## PyPI Statistics & Versions
| TK | TK 2.7 | Qt| WxPython | Web (Remi) |
| -- | -- | -- | -- | -- |
| ![tkinter](https://img.shields.io/pypi/dm/pysimplegui?label=tkinter) | ![tkinter 2.7 downloads](https://img.shields.io/pypi/dm/pysimplegui27?label=tkinter%202.7) | ![qt](https://img.shields.io/pypi/dm/pysimpleguiqt?label=qt) | ![wx](https://img.shields.io/pypi/dm/pysimpleguiwx?label=wx) | ![web](https://img.shields.io/pypi/dm/pysimpleguiweb?label=web) |
| [![tkinter](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui) | [![tkinter27](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27) | [![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt) | [![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) | [![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) |
| ![tkinter](https://img.shields.io/pypi/v/pysimplegui.svg?label=tkinter%20PyPI%20Ver&color=red) | ![tkinter 2.7](https://img.shields.io/pypi/v/pysimplegui27.svg?label=tkinter%202.7%20PyPI%20Ver&color=red) | ![qt](https://img.shields.io/pypi/v/pysimpleguiqt.svg?label=qt%20PyPI%20Ver&color=red) | ![wx](https://img.shields.io/pypi/v/pysimpleguiwx.svg?label=wx%20PyPI%20Ver&color=red) | ![web](https://img.shields.io/pypi/v/pysimpleguiweb.svg?label=web%20PyPI%20Ver&color=red) |
| [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUI)](https://pypi.python.org/pypi/PySimpleGUI/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUI27)](https://pypi.python.org/pypi/PySimpleGUI27/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUIQt)](https://pypi.python.org/pypi/PySimpleGUIQt/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUIWx)](https://pypi.python.org/pypi/PySimpleGUIWx/) | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/PySimpleGUIWeb)](https://pypi.python.org/pypi/PySimpleGUIWeb/) |
--------------------------
## GitHub Statistics
| Issues | Commit Activity | Stars | Docs |
| -- | -- | -- | -- |
| ![GitHub issues](https://img.shields.io/github/issues-raw/PySimpleGUI/PySimpleGUI?color=blue) | ![commit activity](https://img.shields.io/github/commit-activity/m/PySimpleGUI/PySimpleGUI.svg?color=blue) | ![stars](https://img.shields.io/github/stars/PySimpleGUI/PySimpleGUI.svg?label=stars&maxAge=2592000) | ![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest) |
| ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/PySimpleGUI/PySimpleGUI?color=blue) | ![last commit](https://img.shields.io/github/last-commit/PySimpleGUI/PySimpleGUI.svg?color=blue) | |
<p align="center">
<img src="https://github-readme-stats.vercel.app/api/?username=PySimpleGUI&bg_color=3e7bac&title_color=ffdd55&icon_color=ffdd55&text_color=ffdd55&show_icons=true&count_private=true">
</p>
<hr>
<!-- Interesting stats but kinda cluttered [Alt](https://repobeats.axiom.co/api/embed/90d8cdfa8cb37d70903aa52f5b3592035330c3d6.svg "Repobeats analytics image") -->
# What Is PySimpleGUI ❓
PySimpleGUI is a Python package that enables Python programmers of all levels to create GUIs. You specify your GUI window using a "layout" which contains widgets (they're called "Elements" in PySimpleGUI). Your layout is used to create a window using one of the 4 supported frameworks to display and interact with your window. Supported frameworks include tkinter, Qt, WxPython, or Remi. The term "wrapper" is sometimes used for these kinds of packages.
Your PySimpleGUI code is simpler and shorter than writing directly using the underlying framework because PySimpleGUI implements much of the "boilerplate code" for you. Additionally, interfaces are simplified to require as little code as possible to get the desired result. Depending on the program and framework used, a PySimpleGUI program may require 1/2 to 1/10th amount of code to create an identical window using one of the frameworks directly.
While the goal is to encapsulate/hide the specific objects and code used by the GUI framework you are running on top of, if needed you can access the frameworks' dependent widgets and windows directly. If a setting or feature is not yet exposed or accessible using the PySimpleGUI APIs, you are not walled off from the framework. You can expand capabilities without directly modifying the PySimpleGUI package itself.
## Bridging the "GUI Gap"
Python has brought a large number of people into the programming community. The number of programs and the range of areas it touches is mindboggling. But more often than not, these technologies are out of reach of all but a handful of people. The majority of Python programs are "command line" based. This isn't a problem for programmer-types as we're all used to interacting with computers through a text interface. While programmers don't have a problem with command-line interfaces, most "normal people" do. This creates a digital divide, a "GUI Gap".
Adding a GUI to a program opens that program up to a wider audience. It becomes more approachable. GUIs can also make interacting with some programs easier, even for those that are comfortable with a command-line interface. And finally, some problems require a GUI.
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/GUI%20Gap%202020.png" width="600px">
</p>
## Recognition of Open Source Use
In the Demo Programs or one of the PySimpleGUI Account's Repos these packages were used at least one time. Some of your are the goodies on the right of the GUI gap.
If you use Open Source software in your project, be sure and supply information about the packages you used.
- chatterbot
- cv2
- fitz
- forecastio
- gtts
- matplotlib
- mido
- mpl_toolkits
- notifypy
- numpy
- pandas
- PIL
- praw
- psgtray
- psutil
- pyfiglet
- pygame
- pylab
- pymunk
- requests
- vlc
- win32api
- win32con
- win32gui
- win32process
#### LPLG3 as an Example
The licensing terms in the LLC3 Licensing, it states:
> 4. Combined Works.
> You may convey a Combined Work under terms of your choice that,
> taken together, effectively do not restrict modification of the
> portions of the Library contained in the Combined Work and reverse
> engineering for debugging such modifications, if you also do each of
> the following:
>
> a) Give prominent notice with each copy of the Combined Work that
> the Library is used in it and that the Library and its use are
> covered by this License.
>
> b) Accompany the Combined Work with a copy of the GNU GPL and this license
> document.
Since the above packages each have a similar license clause, I'm listing them here, in what I would consider a "prominent notice" location, that I'm using the fine works of these groups or individuals. They are used in the Demo Programs most likely or one of the Repos that are under this account as this list is all inclusive.
You all have my respect and admiration. You're enabling bigger things. What a special kind of thing to make. Who knows what you've enabled. I believe more people are getting over to your creations and getting to experience them.
tkinter team - PySimpleGUI would be nowhere without your lengthy work & continuous dedication. ONE GUI API for 3 different OS's? Really? With no code changes to move between? That's a huge accomplishment. You're #1 to me. Thank you for your hard work.
## Getting Over "The Bar"
It's been said by some that "the bar is pretty high" when it comes to learning GUI programming in Python.
> What happens when the bar is placed on the ground and can be stepped over?
This is one of the questions that the PySimpleGUI project has tried to answer. Here's a humorous look at what's been a not funny situation.
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/GettingOverThe%20GUILearningBar.jpg" width="600px">
</p>
The results have been fascinating to witness and it's been touching to read the accounts of the journeys of users.
Nothing prepared me for the emails that started to arrive soon after the first release of PySimpleGUI. They are heartwarming and heartbreaking tales of life-long dreams of creating a program that required a GUI. Some made a few attempts, giving up each time. Others never started once they started to research what was required.
After recounting the varied and long road to finding PySimpleGUI, the stories became similar. They each found success and expressed joy and gratitude. The joy expressed in these messages was unlike anything I had encountered in the entirety of career in the computing field.
It's been these emails and the messages of gratitude seen here in the GitHub Issues that made dedicating my life to his project a non-decision.
<hr>
## Subscribing to Announcements 📢
If you click the "Subscribe" button in [the Announcements GitHub Issue](https://github.com/PySimpleGUI/PySimpleGUI/issues/142), then you'll be notified when project news is published. This Issue is **the official location** to get the latest PySimpleGUI information. Information is posted frequently including release contents, tips & tricks, documentation updates, etc. There have been over 1,000 posts since the project started.
<hr>
# About Me 👋
Hi there! I'm Mike. You'll find me right here, on the PySimpleGUI GitHub, solving problems and continuously pushing PySimpleGUI forward. I've dedicated my days, nights, and weekends to the project and PySimpleGUI users. Our successes are ultimately shared. I'm successful when you're successful.
While I'm a relative newcomer to Python, I've been writing software since the 70s. The majority of my career was spent creating products in Silicon Valley. I bring to PySimpleGUI the same professionalism and dedication as I did to the corporate products I developed. You are my customers now.
## Project Goals 🥅
Two of the most important goals of the PySimpleGUI project:
* Having fun
* Your success
**Fun** as a goal on a serious project sounds odd, but it's a serious goal. I find writing these GUI programs to be a lot of fun. One reason is how little time it takes to write a complete solution. If we're not enjoying the process then someone's going to give up.
There is a significant amount of documentation, a cookbook, 100's of demo programs to get you immediately running, a detailed call reference, YouTube videos, online Trinket demos, and more... all working to create... a fun experience.
**Your Success** is a shared goal. PySimpleGUI was built for developers. You're my peeps. It's been an unexpected reward to see the results of the combined effort of users and PySimpleGUI. Use the documentation & other materials to help build your application. If you run into trouble, help is available by opening on [Issue on the PySimpleGUI GitHub](http://Issues.PySimpleGUI.org). Take a look at the section on Support below.
<hr>
# Educational Resources 📚
PySimpleGUI now has an official Udemy course! Check the header of this readme and the PySimpleGUI documentation for a coupon code. The course can be found at [www.udemy.com/PySimpleGUI](https://www.udemy.com/PySimpleGUI). **This course** is currently the only income source for the PySimpleGUI project other than sponsorships and donations.
[www.PySimpleGUI.org](http://www.PySimpleGUI.org)
is easy to remember and is where the documentation is located. You'll find tabs across the top that represent several different documents. The documentation is located on "Read The Docs" so that there is a table of contents for each document and they are easy to search.
There are 100s of pages of written documentation and 100s of example programs that will help you be effective very quickly. Rather than requiring days or weeks of investment to learn a single GUI package, you may be able to complete your project in a single afternoon when using PySimpleGUI.
## Example 1 - The One-Shot Window
This type of program is called a "one-shot" window because the window is displayed one time, the values collected, and then it is closed. It doesn't remain open for a long time like you would in a Word Processor.
### Anatomy of a Simple PySimpleGUI Program
There are 5 sections to a PySimpleGUI program
```python
import PySimpleGUI as sg # Part 1 - The import
# Define the window's contents
layout = [ [sg.Text("What's your name?")], # Part 2 - The Layout
[sg.Input()],
[sg.Button('Ok')] ]
# Create the window
window = sg.Window('Window Title', layout) # Part 3 - Window Defintion
# Display and interact with the Window
event, values = window.read() # Part 4 - Event loop or Window.read call
# Do something with the information gathered
print('Hello', values[0], "! Thanks for trying PySimpleGUI")
# Finish up by removing from the screen
window.close() # Part 5 - Close the Window
```
The code produces this window
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-tkinter.jpg">
</p>
<hr>
## Example 2 - Interactive Window
In this example, our window will remain on the screen until the user closes the window or clicks the Quit button. The main difference between the one-shot window you saw earlier and an interactive window is the addition of an "Event Loop". The Event Loop reads events and inputs from your window. The heart of your application lives in the event loop.
```python
import PySimpleGUI as sg
# Define the window's contents
layout = [[sg.Text("What's your name?")],
[sg.Input(key='-INPUT-')],
[sg.Text(size=(40,1), key='-OUTPUT-')],
[sg.Button('Ok'), sg.Button('Quit')]]
# Create the window
window = sg.Window('Window Title', layout)
# Display and interact with the Window using an Event Loop
while True:
event, values = window.read()
# See if user wants to quit or window was closed
if event == sg.WINDOW_CLOSED or event == 'Quit':
break
# Output a message to the window
window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI")
# Finish up by removing from the screen
window.close()
```
This is the window that Example 2 produces.
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Example2-1.jpg">
</p>
And here's what it looks like after you enter a value into the Input field and click the Ok button.
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Example2-2.jpg">
</p>
Let's take a quick look at some of the differences between this example and the one-shot window.
First, you'll notice differences in the layout. Two changes in particular are important. One is the addition of the `key` parameter to the `Input` element and one of the `Text` elements. A `key` is like a name for an element. Or, in Python terms, it's like a dictionary key. The `Input` element's key will be used as a dictionary key later in the code.
Another difference is the addition of this `Text` element:
```python
[sg.Text(size=(40,1), key='-OUTPUT-')],
```
There are 2 parameters, the `key` we already covered. The `size` parameter defines the size of the element in characters. In this case, we're indicating that this `Text` element is 40 characters wide, by 1 character high. Notice that there is no text string specified which means it'll be blank. You can easily see this blank row in the window that's created.
We also added a button, "Quit".
The Event Loop has our familiar `window.read()` call.
Following the read is this if statement:
```python
if event == sg.WINDOW_CLOSED or event == 'Quit':
break
```
This code is checking to see if the user closed the window by clicking the "X" or if they clicked the "Quit" button. If either of these happens, then the code will break out of the event loop.
If the window wasn't closed nor the Quit button clicked, then execution continues. The only thing that could have happened is the user clicked the "Ok" button. The last statement in the Event Loop is this one:
```python
window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI")
```
This statement updates the `Text` element that has the key `-OUTPUT-` with a string. `window['-OUTPUT-']` finds the element with the key `-OUTPUT-`. That key belongs to our blank `Text` element. Once that element is returned from the lookup, then its `update` method is called. Nearly all elements have an `update` method. This method is used to change the value of the element or to change some configuration of the element.
If we wanted the text to be yellow, then that can be accomplished by adding a `text_color` parameter to the `update` method so that it reads:
```python
window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI",
text_color='yellow')
```
After adding the `text_color` parameter, this is our new resulting window:
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Example2-3.jpg">
</p>
The parameters available for each element are documented in both the [call reference documentation](http://calls.PySimpleGUI.org) as well as the docstrings. PySimpleGUI has extensive documentation to help you understand all of the options available to you. If you lookup the `update` method for the `Text` element, you'll find this definition for the call:
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/TextUpdate.jpg">
</p>
As you can see several things can be changed for a `Text` element. The call reference documentation is a valuable resource that will make programming in PySimpleGUI, uhm, simple.
<hr>
## Jump Start! Get the Demo Programs & Demo Browser 🔎
The over 300 Demo Programs will give you a jump-start and provide many design patterns for you to learn how to use PySimpleGUI and how to integrate PySimpleGUI with other packages. By far the best way to experience these demos is using the Demo Browser. This tool enables you to search, edit and run the Demo Programs.
To get them installed quickly along with the Demo Browser, use `pip` to install `psgdemos`:
`python -m pip install psgdemos`
or if you're in Linux, Mac, etc, that uses `python3` instead of `python` to launch Python:
`python3 -m pip install psgdemos`
Once installed, launch the demo browser by typing `psgdemos` from the command line"
`psgdemos`
![SNAG-1543](https://user-images.githubusercontent.com/46163555/151877440-85ad9239-3219-4711-8cdf-9abc1501f05a.jpg)
-------------------------
## Layouts Are Funny LOL! 😆
Your window's layout is a "list of lists" (LOL). Windows are broken down into "rows". Each row in your window becomes a list in your layout. Concatenate together all of the lists and you've got a layout...a list of lists.
Here is the same layout as before with an extra `Text` element added to each row so that you can more easily see how rows are defined:
```python
layout = [ [sg.Text('Row 1'), sg.Text("What's your name?")],
[sg.Text('Row 2'), sg.Input()],
[sg.Text('Row 3'), sg.Button('Ok')] ]
```
Each row of this layout is a list of elements that will be displayed on that row in your window.
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/layout-with-rows.jpg">
</p>
Using lists to define your GUI has some huge advantages over how GUI programming is done using other frameworks. For example, you can use Python's list comprehension to create a grid of buttons in a single line of code.
These 3 lines of code:
```python
import PySimpleGUI as sg
layout = [[sg.Button(f'{row}, {col}') for col in range(4)] for row in range(4)]
event, values = sg.Window('List Comprehensions', layout).read(close=True)
```
produces this window which has a 4 x 4 grid of buttons:
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/4x4grid.jpg">
</p>
Recall how "fun" is one of the goals of the project. It's fun to directly apply Python's powerful basic capabilities to GUI problems. Instead of pages of code to create a GUI, it's a few (or often 1) lines of code.
## Collapsing Code
It's possible to condense a window's code down to a single line of code. The layout definition, window creation, display, and data collection can all be written in this line of code:
```python
event, values = sg.Window('Window Title', [[sg.Text("What's your name?")],[sg.Input()],[sg.Button('Ok')]]).read(close=True)
```
<p align="center">
<img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-tkinter.jpg">
</p>
The same window is shown and returns the same values as the example showing the sections of a PySimpleGUI program. Being able to do so much with so little enables you to quickly and easily add GUIs to your Python code. If you want to display some data and get a choice from your user, it can be done in a line of code instead of a page of code.
By using short-hand aliases, you can save even more space in your code by using fewer characters. All of the Elements have one or more shorter names that can be used. For example, the `Text` element can be written simply as `T`. The `Input` element can be written as `I` and the `Button` as `B`. Your single-line window code thus becomes:
```python
event, values = sg.Window('Window Title', [[sg.T("What's your name?")],[sg.I()],[sg.B('Ok')]]).read(close=True)
```
### Code Portability
PySimpleGUI is currently capable of running on 4 Python GUI Frameworks. The framework to use is specified using the import statement. Change the import and you'll change the underlying GUI framework. For some programs, no other changes are needed than the import statement to run on a different GUI framework. In the example above, changing the import from `PySimpleGUI` to `PySimpleGUIQt`, `PySimpleGUIWx`, `PySimpleGUIWeb` will change the framework.
| Import Statement | Resulting Window |
|--|--|
| PySimpleGUI | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-tkinter.jpg) |
| PySimpleGUIQt | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-Qt.jpg) |
| PySimpleGUIWx | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-WxPython.jpg) |
| PySimpleGUIWeb | ![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ex1-Remi.jpg) |
Porting GUI code from one framework to another (e.g. moving your code from tkinter to Qt) usually requires a rewrite of your code. PySimpleGUI is designed to enable you to have easy movement between the frameworks. Sometimes some changes are required of you, but the goal is to have highly portable code with minimal changes.
Some features, like a System Tray Icon, are not available on all of the ports. The System Tray Icon feature is available on the Qt and WxPython ports. A simulated version is available on tkinter. There is no support for a System Tray icon in the PySimpleGUIWeb port.
## Runtime Environments
| Environment | Supported |
|--|--|
| Python | Python 3.4+ |
| Operating Systems | Windows, Linux, Mac |
| Hardware | Desktop PCs, Laptops, Raspberry Pi, Android devices running PyDroid3 |
| Online | repli.it, Trinket.com (both run tkinter in a browser) |
| GUI Frameworks | tkinter, pyside2, WxPython, Remi |
## Integrations
Among the more than 200 "Demo Programs", you'll find examples of how to integrate many popular Python packages into your GUI.
Want to embed a Matplotlib drawing into your window? No problem, copy the demo code and instantly have a Matplotlib drawing of your dreams into your GUI.
These packages and more are ready for you to put into your GUI as there are demo programs or a demo repo available for each:
Package | Description |
|--|--|
Matplotlib | Many types of graphs and plots |
OpenCV | Computer Vision (often used for AI) |
VLC | Video playback |
pymunk | Physics engine|
psutil | System environment statistics |
prawn | Reddit API |
json | PySimpleGUI wraps a special API to store "User Settings" |
weather | Integrates with several weather APIs to make weather apps |
mido | MIDI playback |
beautiful soup | Web Scraping (GitHub issue watcher example) |
<hr>
# Installing 💾
Two common ways of installing PySimpleGUI:
1. pip to install from PyPI
2. Download the file PySimpleGUI.py and place in your application's folder
### Pip Installing & Upgrading
The current suggested way of invoking the `pip` command is by running it as a module using Python. Previously the command `pip` or `pip3` was directly onto a command-line / shell. The suggested way
Initial install for Windows:
`python -m pip install PySimpleGUI`
Initial install for Linux and MacOS:
`python3 -m pip install PySimpleGUI`
To upgrade using `pip`, you simply add 2 parameters to the line `--upgrade --no-cache-dir`.
Upgrade installation on Windows:
`python -m pip install --upgrade --no-cache-dir PySimpleGUI`
Upgrade for Linux and MacOS:
`python3 -m pip install --upgrade --no-cache-dir PySimpleGUI`
### Single File Installing
PySimpleGUI was created as a single .py file so that it would be very easy for you to install it, even on systems that are not connected to the internet like a Raspberry Pi. It's as simple as placing the PySimpleGUI.py file into the same folder as your application that imports it. Python will use your local copy when performing the import.
When installing using just the .py file, you can get it from either PyPI or if you want to run the most recent unreleased version then you'll download it from GitHub.
To install from PyPI, download either the wheel or the .gz file and unzip the file. If you rename the .whl file to .zip you can open it just like any normal zip file. You will find the PySimpleGUI.py file in one of the folders. Copy this file to your application's folder and you're done.
The PyPI link for the tkinter version of PySimpleGUI is:
https://pypi.org/project/PySimpleGUI/#files
The GitHub repo's latest version can be found here:
https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/PySimpleGUI.py
Now some of you are thinking, "yea, but, wait, having a single huge source file is a terrible idea". And, yea, *sometimes* it can be a terrible idea. In this case, the benefits greatly outweighed the downside. Lots of concepts in computer science are tradeoffs or subjective. As much as some would like it to be, not everything is black and white. Many times the answer to a question is "it depends".
## Galleries 🎨
Work on a more formal gallery of user-submitted GUIs as well as those found on GitHub is underway but as of this writing it's not complete. There are currently 2 places you can go to see some screenshots in a centralized way. Hopefully, a Wiki or other mechanism can be released soon to do justice to the awesome creations people are making.
### User Submitted Gallery
The first is a [user submitted screenshots issue](https://github.com/PySimpleGUI/PySimpleGUI/issues/10) located on the GitHub. It's an informal way for people to show off what they've made. It's not ideal, but it was a start.
### Massive Scraped GitHub Images
The second is a [massive gallery of over 3,000 images](https://www.dropbox.com/sh/g67ms0darox0i2p/AAAMrkIM6C64nwHLDkboCWnaa?dl=0) scraped from 1,000 projects on GitHub that are reportedly using PySimpleGUI. It's not been hand-filtered and there are plenty of old screenshots that were used in the early documentation. But, you may find something in there that sparks your imagination.
<hr>
# Uses for PySimpleGUI 🔨
The following sections showcase a fraction of the uses for PySimpleGUI. There are over 1,000 projects on GitHub alone that use PySimpleGUI. It's truly amazing how possibilities have opened up for so many people. Many users have spoken about previously attempting to create a GUI in Python and failing, but finally achieving their dreams when they tried PySimpleGUI.
## Your First GUI
Of course one of the best uses of PySimpleGUI is getting you into making GUIs for your Python projects. You can start as small as requesting a filename. For this, you only need to make a single call to one of the "high-level functions" called `popup`. There are all kinds of popups, some collect information.
`popup` on itself makes a window to display information. You can pass multiple parameters just like a print. If you want to get information, then you will call functions that start with `popup_get_` such as `popup_get_filename`.
Adding a single line to get a filename instead of specifying a filename on the command line can transform your program into one that "normal people" will feel comfortable using.
```python
import PySimpleGUI as sg
filename = sg.popup_get_file('Enter the file you wish to process')
sg.popup('You entered', filename)
```
This code will display 2 popup windows. One to get the filename, which can be browsed to or pasted into the input box.
<p align="center">
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/First_GUI1.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/First_GUI1.jpg" alt="img" width="400px"></a>
</p>
The other window will output what is collected.
<p align="center">
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/First_GUI2.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/First_GUI2.jpg" alt="img" width="175px"></a>
</p>
<br>
## Rainmeter-Style Windows
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/RainmeterStyleWidgets.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/RainmeterStyleWidgets.jpg" alt="img" align="right" width="500px"></a>
The default settings for GUI frameworks don't tend to produce the nicest looking windows. However, with some attention to detail, you can do several things to make windows look attractive. PySimpleGUI makes it easier to manipulate colors and features like removing the title bar. The result is windows that don't look like your typical tkinter windows.
Here is an example of how you can create windows that don't look like your typical tkinter in windows. In this example, the windows have their titlebars removed. The result is windows that look much like those found when using Rainmeter, a desktop widget program.
<br><br>
You can easily set the transparency of a window as well. Here are more examples of desktop widgets in the same Rainmeter style. Some are dim appearing because they are semi-transparent.
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/semi-transparent.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/semi-transparent.jpg" alt="img" align="right" width="500px"></a>
Both of these effects; removing the titlebar and making a window semi-transparent, are achieved by setting 2 parameters when creating the window. This is an example of how PySimpleGUI enables easy access to features. And because PySimpleGUI code is portable across the GUI frameworks, these same parameters work for the other ports such as Qt.
Changing the Window creation call in Example 1 to this line of code produces a similar semi-transparent window:
```python
window = sg.Window('My window', layout, no_titlebar=True, alpha_channel=0.5)
```
## Games
While not specifically written as a game development SDK, PySimpleGUI makes the development of some games quite easy.
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Chess.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Chess.png" alt="img" align="right" width="500px"></a>
This Chess program not only plays chess, but it integrates with the Stockfish chess-playing AI.
<br><br><br><br><br><br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Minesweeper.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Minesweeper.gif" alt="img" align="right" width="500px"></a>
Several variants of Minesweeper have been released by users.
<br><br><br><br>
<br><br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/minesweeper_israel_dryer.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/minesweeper_israel_dryer.png" alt="img" align="right" width="500px"></a>
<br><br><br><br><br><br><br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Solitaire.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Solitaire.gif" alt="img" align="right" width="500px"></a>
<br><br>
Card games work well with PySimpleGUI as manipulating images is simple when using the PySimpleGUI `Graph` element.
While not specifically written as a game development SDK, PySimpleGUI makes development of some games quite easy.
<br><br>
<br><br>
<br><br><br>
## Media Capture and Playback
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/OpenCV.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/OpenCV.jpg" alt="img" align="right" width="400px"></a>
Capturing and displaying video from your webcam in a GUI is 4 lines of PySimpleGUI code. Even more impressive is that these 4 lines of code work with the tkinter, Qt, and Web ports. You can display your webcam, in realtime, in a browser using the same code that displays the image using tkinter.
Media playback, audio and video, can also be achieved using the VLC player. A demo application is provided to you so that you have a working example to start from. Everything you see in this readme is available to you as a starting point for your own creations.
<br><br><br><br><br>
<br><br><br><br><br>
<br><br>
## Artificial Intelligence
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO_GIF.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO_GIF.gif" alt="img" align="right" width="500px"></a>
AI and Python have long been a recognized superpower when the two are paired together. What's often missing however is a way for users to interact with these AI algorithms familiarly, using a GUI.
These YOLO demos are a great example of how a GUI can make a tremendous difference in interacting with AI algorithms. Notice two sliders at the bottom of these windows. These 2 sliders change a couple of the parameters used by the YOLO algorithm.
If you were tuning your YOLO demo using only the command line, you would need to set the parameters, once, when you launch the application, see how they perform, stop the application, change the parameters, and finally restart the application with the new parameters.
<br><br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO%20Object%20Detection.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/YOLO%20Object%20Detection.jpg" alt="img" align="right" width="500px"></a>
Contrast those steps against what can be done using a GUI. A GUI enables you to modify these parameters in real-time. You can immediately get feedback on how they are affecting the algorithm.
<br><br><br><br><br>
<br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Colorizer.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Colorizer.jpg" alt="img" align="right" width="500px"></a>
There are SO many AI programs that have been published that are command-line driven. This in itself isn't a huge hurdle, but it's enough of a "pain in the ass" to type/paste the filename you want to colorize on the command line, run the program, then open the resulting output file in a file viewer.
GUIs have the power to **change the user experience**, to fill the "GUI Gap". With this colorizer example, the user only needs to supply a folder full of images, and then click on an image to both colorize and display the result.
The program/algorithm to do the colorization was freely available, ready to use. What was missing is the ease of use that a GUI could bring.
<hr>
## Graphing
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/CPU%20Cores%20Dashboard%202.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/CPU%20Cores%20Dashboard%202.gif" alt="img" align="right" width="500px"></a>
Displaying and interacting with data in a GUI is simple with PySimpleGUI. You have several options.
You can use the built-in drawing/graphing capabilities to produce custom graphs. This CPU usage monitor uses the `Graph` element
<br><br>
<br><br>
<br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib.jpg" alt="img" align="right" width="500px"></a>
Matplotlib is a popular choice with Python users. PySimpleGUI can enable you to embed Matplotlib graphs directly into your GUI window. You can even embed the interactive controls into your window if you want to retain the Matplotlib interactive features.
<br><br>
<br><br>
<br><br>
<br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib2.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Matplotlib2.jpg" alt="img" align="right" width="500px"></a>
Using PySimpleGUI's color themes, you can produce graphs that are a notch above default graphs that most people create in Matplotlib.
<br><br>
<br><br>
<br><br>
<br><br>
<br><br>
<br><br>
<br><br>
<hr>
## Front-ends
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/JumpCutter.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/JumpCutter.png" alt="img" align="right" width="500px"></a>
The "GUI Gap" mentioned earlier can be easily solved using PySimpleGUI. You don't even need to have the source code to the program you wish to add a GUI onto. A "front-end" GUI is one that collects information that is then passed to a command-line application.
Front-end GUIs are a fantastic way for a programmer to distribute an application that users were reluctant to use previously because they didn't feel comfortable using a command-line interface. These GUIs are your only choice for command-line programs that you don't have access to the source code for.
This example is a front-end for a program called "Jump Cutter". The parameters are collected via the GUI, a command-line is constructed using those parameters, and then the command is executed with the output from the command-line program being routed to the GUI interface. In this example, you can see in yellow the command that was executed.
<br><br>
<hr>
## Raspberry Pi
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Raspberry%20Pi.jpg"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Raspberry%20Pi.jpg" alt="img" align="right" width="500px"></a>
Because PySimpleGUI is compatible back to Python 3.4, it is capable of creating a GUI for your Raspberry Pi projects. It works particularly well when paired with a touchscreen. You can also use PySimpleGUIWeb to control your Pi if it doesn't have a monitor attached.
<br><br>
<br><br>
<br><br>
<br><br><br>
<hr>
## Easy Access to Advanced Features
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Customized%20Titlebar.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Customized%20Titlebar.gif" alt="img" align="right" width="500px"></a>
Because it's very easy to access many of the underlying GUI frameworks' features, it's possible to piece together capabilities to create applications that look nothing like those produced using the GUI framework directly.
For example, it's not possible to change the color/look-and-feel of a titlebar using tkinter or the other GUI packages, but with PySimpleGUI it's easy to create windows that appear as if they have a custom titlebar.
<br><br><br>
<a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Desktop%20Bouncing%20Balls.gif"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/Desktop%20Bouncing%20Balls.gif" alt="img" align="right" width="500px"></a>
Unbelievably, this window is using tkinter to achieve what appears to be something like a screensaver.
On windows, tkinter can completely remove the background from your application. Once again, PySimpleGUI makes accessing these capabilities trivial. Creating a transparent window requires adding a single parameter to the call that creates your `Window`. One parameter change can result in a simple application with this effect:
You can interact with everything on your desktop, clicking through a full-screen window.
<hr>
# Themes
Tired of the default grey GUIs? PySimpleGUI makes it trivial for your window to look nice by making a single call to the `theme` function. There are over 150 different color themes available for you to choose:
<p align="center">
<a href=""><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/ThemePreview.jpg" alt="img" width="900px"></a>
</p>
With most GUI frameworks, you must specify the color for every widget you create. PySimpleGUI takes this chore from you and will automatically color the Elements to match your chosen theme.
To use a theme, call the `theme` function with the name of the theme before creating your window. You can add spaces for readability. To set the theme to "Dark Grey 9":
```python
import PySimpleGUI as sg
sg.theme('dark grey 9')
```
This single line of code changes the window's appearance entirely:
<p align="center">
<a href=""><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/DarkGrey.jpg" alt="img" width="400px"></a>
</p>
The theme changed colors of the background, text, input background, input text, and button colors. In other GUI packages, to change color schemes like this, you would need to specify the colors of each widget individually, requiring numerous changes to your code.
<hr>
# Distribution
Want to share your PySimpleGUI program with friends and family that don't have Python installed on their computer? Try the GUI front-end for PyInstaller that you'll find in the [psgcompiler](https://github.com/PySimpleGUI/psgcompiler) project.
![](https://raw.githubusercontent.com/PySimpleGUI/psgcompiler/main/screenshot_for_readme/psgcompiler_screenshot.jpg?token=ALAGMY3Z33WHFX3RTFXEZ73BTEUPO)
<hr>
# Support 💪
Your first stop should be the [documentation](http://www.PySimpleGUI.org) and [demo programs](http://Demos.PySimpleGUI.org).
Be sure and install the Demo Browser (instructions in the Cookbook) so that you can search and run the 100s of demo programs.
![](https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_cookbook/Project_Browser_Main_Window_Explained.jpg)
If you still have a question or need help... no problem... help is available to you, at no cost. Simply [file an Issue](http://Issues.PySimpleGUI.org) on the PySimpleGUI GitHub repo and you'll get help.
Nearly all software companies have a form that accompanies bug reports. It's not a bad trade... fill in the form, get free software support. This information helps get you an answer efficiently.
In addition to requesting information such as the version numbers of PySimpleGUI and underlying GUI frameworks, you're also given a checklist of items that may help you solve your problem.
***Please fill in the form.*** It may feel pointless to you. It may feel painful, despite it taking just a moment. It helps get you a solution faster. If it wasn't useful and necessary information to help you get a speedy reply and fix, you wouldn't be asked to fill it out. "Help me help you".
# Supporting <a href="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/PSGSuperHero.png"><img src="https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/images/for_readme/PSGSuperHero.png" alt="img" width="90px"></a>
Financial support for the project is greatly appreciated. To be honest, financial help is needed. It's expensive just keeping the lights on. The domain name registrations, a long list of subscriptions for things like Trinket, consulting help, etc., quickly add up to a sizable recurring cost.
PySimpleGUI wasn't inexpensive to create. While a labor of love, it was very laborious over several years, and quite a bit was invested, and continues to be invested, in creating what you see today.
PySimpleGUI has an open-source license and it would be great if it could remain that way. If you or your company (especially if you're using PySimpleGUI in a company) are benefiting financially by using PySimpleGUI, you have the capability of extending the life of the project for you and other users.
### Buy Me A Coffee
Buy Me a Coffee is a great way to publicly support developers. It's quick, easy, and your contribution is recorded so that others can see that you're a supporter of PySimpleGUI. You can also choose to make your donation private.
<a href="https://www.buymeacoffee.com/PySimpleGUI" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/arial-yellow.png" alt="Buy Me A Coffee" width="217px" ></a>
### GitHub Sponsoring
<a href="https://github.com/sponsors/PySimpleGUI" target="_blank"><img src="https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=%3Curl%3E&color=f88379"></a>
The [GitHub recurring sponsorship](https://github.com/sponsors/PySimpleGUI) is how you can sponsor the project at varying levels of support on an ongoing basis. It's how many Open Source developers are able to receive corporate level sponsorship.
Your help in financially contributing to the project would be greatly appreciated. Being an Open Source developer is financially challenging. YouTube video creators are able to make a living creating videos. It's not so easy yet for Open Source developers.
# Thank you for the Thank You's
To everyone that's helped, in whatever fashion, I'm very very grateful.
Even taking a moment to say "thank you" helps, and a HUGE number of you have done that. It's been an amazing number actually. I value these thanks and find inspiration in the words alone. Every message is a little push forward. It adds a little bit of energy and keeps the whole project's momentum. I'm so very grateful to everyone that's helped in whatever form it's been.
# Contributing 👷
While PySimpleGUI is currently licensed under an open-source license, the project itself is structured like a proprietary product. Pull Requests are not accepted.
One of the best ways for you to contribute code is to write and publish applications. Users are inspired by seeing what other users build. Here's a simple set of steps you can take - Create a GitHub repo, post the code, and include a screenshot in your repo's readme file. Then come back to the PySimpleGUI repo and post a screenshot in Issue #10 or in the project's WIKI.
If there is a feature missing that you need or you have an enhancement to suggest, then [open an Issue](https://github.com/PySimpleGUI/PySimpleGUI/issues/new?assignees=&labels=&template=issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md&title=%5B+Enhancement%2FBug%2FQuestion%5D+My+problem+is...)
# Special Thanks 🙏
The PySimpleGUI team is tiny and they're all superstars. Every week I've been stunned by what they do. Dream-team is an understatement. Simply put [@Chr0nicT](https://github.com/Chr0nicT), [@jason990420](https://github.com/jason990420), [@Snaiel](https://github.com/snaiel) and Mike[@PySimpleGUI](https://github.com/PySimpleGUI) ***are*** PySimpleGUI.
This version of the PySimpleGUI readme wouldn't have come together without the help from [@M4cs](https://github.com/M4cs). He's a fantastic developer and has been a PySimpleGUI supporter since the project's launch. [@israel-dryer](https://github.com/israel-dryer) is another long-term supporter and has written several PySimpleGUI programs that pushed the envelope of the package's capabilities. The unique minesweeper that uses an image for the board was created by Israel. [@jason990420](https://github.com/jason990420) surprised many when he published the first card game using PySimpleGUI that you see pictured above as well as the first minesweeper game made with PySimpleGUI. [@Chr0nicT](https://github.com/Chr0nicT) is the youngest developer I've worked with, ever, on projects. This kid shocks me on a regular basis. Ask for a capability, such as the PySimpleGUI GitHub Issues form error checking bot, and it simply happens regardless of the technologies involved. I'm fortunate that we were introduced. Someday he's going to be whisked away, but until then we're all benefiting from his talent. [@Snaiel](https://github.com/snaiel) made the Udemy course happen. It wouldn't have been 1/4th of what it is without his amazing skills in video production, course design, marketing brilliance, and web programming. The Japanese version of the readme was greatly improved with help from [@okajun35](https://github.com/okajun35). [@nngogol](https://github.com/nngogol) has had a very large impact on the project, also getting involved with PySimpleGUI in the first year of initial release. He wrote a designer, came up with the familiar window[key] lookup syntax, wrote the tools that create the documentation, designed the first set of doc strings as well as tools that generate the online documenation using the PySimpleGUI code itself. PySimpleGUI would not be where it is today were it not for the help of these individuals.
The more than 4,000 GitHub repos that use PySimpleGUI are owed a "Thank You" as well, for it is *you* that has been the inspiration that fuels this project's engine.
The overseas users that post on Twitter overnight are the spark that starts the day's work on PySimpleGUI. They've been a source of positive energy that gets the development engine started and ready to run every day. As a token of appreciation, this readme file has been translated into [Japanese](https://github.com/PySimpleGUI/PySimpleGUI/blob/master/readme.ja.md).
PySimpleGUI users have been the best user community an Open Source developer could hope for. I've never seen expressions of gratitude and joy like PySimpleGUI users show on a daily basis.
© Copyright 2021, 2022 PySimpleGUI

9
PySimpleGUI/readthedocs.yml Executable file
View File

@@ -0,0 +1,9 @@
version: 2
python:
version: 3.6
install:
- requirements: docs/requirements.txt
mkdocs:
configuration: mkdocs.yml

45
PySimpleGUI/setup.py Executable file
View File

@@ -0,0 +1,45 @@
import setuptools
def readme():
try:
with open('README.md') as f:
return f.read()
except IOError:
return ''
setuptools.setup(
name="PySimpleGUI",
version="4.60.4",
author="PySimpleGUI",
author_email="PySimpleGUI@PySimpleGUI.org",
description="Python GUIs for Humans. Launched in 2018. It's 2022 & PySimpleGUI is an ACTIVE & supported project. Super-simple to create custom GUI's. 325+ Demo programs & Cookbook for rapid start. Extensive documentation. Main docs at www.PySimpleGUI.org. Fun & your success are the focus. Examples using Machine Learning (GUI, OpenCV Integration), Rainmeter Style Desktop Widgets, Matplotlib + Pyplot, PIL support, add GUI to command line scripts, PDF & Image Viewers. Great for beginners & advanced GUI programmers.",
long_description=readme(),
long_description_content_type="text/markdown",
keywords="GUI UI tkinter Qt WxPython Remi wrapper simple easy beginner novice student graphics progressbar progressmeter",
url="https://github.com/PySimpleGUI/PySimpleGUI",
packages=setuptools.find_packages(),
classifiers=(
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
"Topic :: Multimedia :: Graphics",
"Operating System :: OS Independent"
),
entry_points={
'gui_scripts': [
'psgissue=PySimpleGUI.PySimpleGUI:main_open_github_issue',
'psgmain=PySimpleGUI.PySimpleGUI:_main_entry_point',
'psgupgrade=PySimpleGUI.PySimpleGUI:_upgrade_entry_point',
'psghelp=PySimpleGUI.PySimpleGUI:main_sdk_help',
'psgver=PySimpleGUI.PySimpleGUI:main_get_debug_data',
'psgsettings=PySimpleGUI.PySimpleGUI:main_global_pysimplegui_settings',
],},
)

254
protocol.md Normal file
View File

@@ -0,0 +1,254 @@
# MT6 RFID 读卡器 USB HID 私有协议参考文档
## 1. 概述
本文档描述了一款 MT6 系列 RFID 读卡器(型号 `MT6_RF915_RW_WY`)通过 USB HID 接口与主机通信的私有协议。所有数据交互均使用 **USB HID Feature Report**控制传输Report 长度为 **256 字节**
通信过程遵循固定的四包模型SetReq / SetRes / GetReq / GetRes其中 **SetReq****GetRes** 包含有效载荷,另外两个为固定应答包,底层驱动已自动处理。
## 2. 通用帧格式
### 2.1 SetReq主机 → 设备Report ID = 0x01
主机发送的命令帧结构如下(从 Report ID 后开始计算偏移)。**SetReq 必须填充至 256 字节**,不足部分用 `0x00` 补齐。
| 偏移 | 长度 | 字段名 | 说明 |
|:---|:---|:---|:---|
| 0x00 | 1 | Report ID | 固定 `0x01` |
| 0x01 | 4 | Fixed | 固定 `0x00 0x00 0x00 0x00` |
| 0x05 | 2 | Frame Length | 从下一字段(`0x07`)到数据末尾(不含校验和结束符)的总字节数,小端序 |
| 0x07 | 2 | Constant | 固定 `0x00 0x02` |
| 0x09 | 2 | Data Length | 后续数据负载的字节数,小端序 |
| 0x0B | N | Data | 实际数据负载(命令参数) |
| 0x0B+N | 1 | Checksum | 校验字节,计算方法见第 3 节 |
| 0x0C+N | 1 | End Marker | 固定 `0x03` |
| 剩余 | - | Padding | 填充 `0x00`**256 字节** |
### 2.2 GetRes设备 → 主机Report ID = 0x03
设备返回的数据帧结构与 SetReq 相同,但 **GetRes 无需填充至 256 字节**,其实际有效长度由 USB 传输层决定。
**通用 Data 段格式**
| 偏移(相对 Data 段起点) | 长度 | 字段名 | 说明 |
|:---|:---|:---|:---|
| 0x00 | 1 | Status | 状态字节。`0x00` 表示成功,非零表示异常 |
| 0x01 | M | Response Data | 实际返回数据(长度由 Data Length - 1 决定) |
## 3. 校验算法
### 3.1 外层帧校验
**计算范围**`Data Length` 字段的 2 个字节 + `Data` 字段的全部 N 个字节。
**算法**逐字节异或XOR
```python
def calc_outer_checksum(data_len_bytes: bytes, payload: bytes) -> int:
result = 0
for b in data_len_bytes + payload:
result ^= b
return result
```
### 3.2 EPC 操作内部校验
#### 3.2.1 Payload Checksum累加和
**计算范围**:从 Card Op Command 字段开始,到 Payload 末尾(不含校验字节自身)。
**算法**:所有字节累加(无符号 8 位溢出,即模 256
#### 3.2.2 EPC CRC
**算法**CRC-16/GENIBUS
**参数**
- 多项式:`0x1021`
- 初始值:`0xFFFF`
- 输出异或:`0xFFFF`
- 输入/输出是否反转:`false` / `false`
**计算范围**EPC Len Indicator1 字节)+ EPC Status1 字节)+ EPC DataN 字节)
```python
import crcmod
crc16_genibus = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0xFFFF)
def calc_epc_crc(epc_len_indicator: int, epc_status: int, epc_data: bytes) -> int:
data = bytes([epc_len_indicator, epc_status]) + epc_data
return crc16_genibus(data)
```
## 4. 已知命令集
### 4.1 读版本号
- **功能**:获取设备固件版本字符串。
- **SetReq Data**1 字节):`c0`
- **SetReq 完整数据段**(填充前):
```
01 00 00 00 00 06 00 00 02 01 00 c0 c1 03
```
- **GetRes Data 段**
```
00 # Status = 成功
4d 54 36 5f 52 46 39 31 35 5f 52 57 ... 20 # ASCII 版本字符串
```
**注意**:版本字符串后的 `0x20` 为外层帧校验字节,`0x03` 为帧结束标志。
### 4.2 蜂鸣器控制
#### 打开蜂鸣器
- **SetReq Data**2 字节):`cd 01`
- **SetReq 数据段**
```
01 00 00 00 00 07 00 00 02 02 00 cd 01 ce 03
```
- **GetRes Data 段**`00 80`
#### 关闭蜂鸣器
- **SetReq Data**2 字节):`cd 00`
- **SetReq 数据段**
```
01 00 00 00 00 07 00 00 02 02 00 cd 00 cf 03
```
- **GetRes Data 段**`00 80`
### 4.3 设置功率
- **功能**:设置发射功率等级(取值范围 0~9
- **示例(功率 = 8SetReq Data**2 字节):`cc 08`
- **SetReq 数据段**
```
01 00 00 00 00 07 00 00 02 02 00 cc 08 c6 03
```
- **GetRes Data 段**`00 80`
### 4.4 设置工作模式
- **功能**:切换读卡器工作模式。
- **SetReq Data**2 字节):`0f 0X`,其中 `X` 为模式编号。
- `0f 01`:单标签巡查
- `0f 02`:被动模式
- `0f 03`:多标签巡查
- **示例被动模式SetReq 数据段**
```
01 00 00 00 00 07 00 00 02 02 00 0f 02 0f 03
```
- **GetRes Data 段**`00 80`
### 4.5 EPC 操作
所有 EPC 相关命令(读、选中、写)的 SetReq Data 段均遵循以下通用结构:
| 偏移 | 长度 | 字段名 | 说明 |
|:---|:---|:---|:---|
| 0x00 | 1 | Command | 固定 `ce` |
| 0x01 | 1 | Magic | 固定 `bb` |
| 0x02 | 2 | Card Op Command | 操作码,见各子命令 |
| 0x04 | 2 | Internal Length | 后续 Payload 的字节数(小端) |
| 0x06 | N | Payload | 具体操作参数 |
| 0x06+N | 1 | Payload Checksum | 从 Card Op Command 到 Payload 末尾的累加和(模 256 |
| 0x07+N | 1 | End Marker | 固定 `7e` |
#### 4.5.1 读取 EPC
**Card Op Command**`00 22`
##### SetReq
- Internal Length`00 00`
- Payload
- Payload Checksum`22`
- End Marker`7e`
- **完整 Data 段**`ce bb 00 22 00 00 22 7e`
##### GetRes
- Data 段结构(有卡):
| 偏移 | 长度 | 字段名 | 示例值 | 说明 |
|:---|:---|:---|:---|:---|
| 0x00 | 1 | Status | `00` | 成功 |
| 0x01 | 1 | Magic | `bb` | 固定 |
| 0x02 | 2 | Card Op Resp | `02 22` | 读卡成功标志 |
| 0x04 | 2 | Internal Length | `00 0b` | 后续数据长度 |
| 0x06 | 1 | RSSI | `d3` | 信号强度 |
| 0x07 | 1 | EPC Len Indicator | `18` | EPC 字节数 = 该值 ÷ 4 |
| 0x08 | 1 | EPC Status | `00` | 读取状态 |
| 0x09 | N | EPC Data | `11 22 33 44 55 66` | 实际 EPC |
| 0x09+N | 2 | EPC CRC | `75 ce` | CRC-16/GENIBUS |
| 0x0B+N | 1 | Payload Checksum | `c2` | 累加和 |
| 0x0C+N | 1 | End Marker | `7e` | 固定尾部 |
- 无卡时 Card Op Resp 为 `01 ff`Payload 仅含 RSSI 及累加和。
#### 4.5.2 选中卡
**Card Op Command**`00 0c`
##### SetReq
- Internal Length`00 09`
- Payload9 字节):
- 偏移 0x00~0x05保留字段`01 00 00 00 20 10`
- 偏移 0x06~0x07EPC Data如 `11 22`
- **完整 Data 段示例**`ce bb 00 0c 00 09 01 00 00 00 20 10 00 11 22 79 7e`
##### GetRes
- Data 段:
```
00 bb 01 0c 00 01 00 0e 7e
```
- Card Op Resp`01 0c`
- Internal Length`00 01`
- Payload`00`(选中成功标志)
- Payload Checksum`0e`
#### 4.5.3 写入 EPC
**Card Op Command**`00 49`
##### SetReq
- Internal Length`00 0f`
- Payload15 字节):
| 偏移 | 长度 | 字段名 | 示例值 | 说明 |
|:---|:---|:---|:---|:---|
| 0x00 | 6 | Reserved | `00 00 00 00 01 00` | 保留 |
| 0x06 | 1 | Word Count | `03` | = 2 + 新 EPC 字节数/2 |
| 0x07 | 2 | Old EPC CRC | `ca 9e` | 原卡 EPC 的 CRC-16/GENIBUS |
| 0x09 | 1 | EPC Len Indicator | `08` | 新 EPC 字节数 = 值 ÷ 4 |
| 0x0A | 1 | EPC Status | `00` | 固定 |
| 0x0B | N | New EPC Data | `11 23` | 新 EPC |
- Payload Checksum`00`
- End Marker`7e`
- **完整 Data 段示例**
```
ce bb 00 49 00 0f 00 00 00 00 01 00 00 00 03 ca 9e 08 00 11 23 00 7e
```
##### GetRes
- Data 段:
```
00 bb 01 49 00 06 04 08 00 11 22 00 8f 7e
```
- Card Op Resp`01 49`(写卡成功)
- Internal Length`00 06`
- Payload包含原 EPC `11 22` 等信息,用于确认
## 5. 附录:命令速查表
| 功能 | SetReq Data十六进制 | 说明 |
|:---|:---|:---|
| 读版本号 | `c0` | 返回 ASCII 字符串 |
| 打开蜂鸣器 | `cd 01` | |
| 关闭蜂鸣器 | `cd 00` | |
| 设置功率 = 8 | `cc 08` | 取值范围 0~9 |
| 设置单标签巡查 | `0f 01` | |
| 设置被动模式 | `0f 02` | |
| 设置多标签巡查 | `0f 03` | |
| 读取 EPC | `ce bb 00 22 00 00 22 7e` | 返回 EPC 数据 |
| 选中卡EPC=1122 | `ce bb 00 0c 00 09 01 00 00 00 20 10 00 11 22 79 7e` | Payload Checksum 需根据实际计算 |
| 写 EPC1122→1123 | `ce bb 00 49 00 0f 00 00 00 00 01 00 00 00 03 ca 9e 08 00 11 23 00 7e` | 注意 Word Count 和 Old EPC CRC |
---
**文档版本**2.2
**最后更新**2026-04-14
**适用设备**MT6_RF915_RW_WY 及兼容固件

551
rfid_tester.py Normal file
View File

@@ -0,0 +1,551 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MT6 RFID 读卡器测试程序
基于 USB HID 私有协议
"""
import sys
import os
import time
# 添加 PySimpleGUI 目录到路径
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'PySimpleGUI'))
import PySimpleGUI as sg
try:
import hid
except ImportError:
sg.popup_error('请安装 hidapi 库:\npip install hidapi')
sys.exit(1)
# ==================== 协议常量 ====================
REPORT_ID_SET_REQ = 0x01
REPORT_ID_GET_RES = 0x03
REPORT_SIZE = 256
# 设备信息
VENDOR_ID = 0xFFFF # 默认VID
PRODUCT_ID = 0x0035 # 默认PID
# ==================== 协议函数 ====================
def calc_outer_checksum(data_len_bytes: bytes, payload: bytes) -> int:
"""计算外层帧校验XOR"""
result = 0
for b in data_len_bytes + payload:
result ^= b
return result
def build_setreq_frame(data: bytes) -> bytes:
"""
构建 SetReq 帧
:param data: Data 段数据
:return: 完整的 256 字节帧
"""
# Frame Length: 从 0x07 到 Checksum包含校验和不含结束符
# = 2 (constant) + 2 (data length) + len(data) + 1 (checksum)
frame_length = 5 + len(data)
frame_length_bytes = frame_length.to_bytes(2, 'little')
# Data Length
data_length_bytes = len(data).to_bytes(2, 'little')
# Checksum
checksum = calc_outer_checksum(data_length_bytes, data)
# 构建帧
frame = bytearray(REPORT_SIZE)
frame[0] = REPORT_ID_SET_REQ
frame[1:5] = b'\x00\x00\x00\x00' # Fixed
frame[5:7] = frame_length_bytes # Frame Length
frame[7:9] = b'\x00\x02' # Constant
frame[9:11] = data_length_bytes # Data Length
frame[11:11+len(data)] = data # Data
frame[11+len(data)] = checksum # Checksum
frame[12+len(data)] = 0x03 # End Marker
return bytes(frame)
def parse_getres_frame(data: bytes) -> tuple:
"""
解析 GetRes 帧
:param data: 接收到的数据
:return: (status, response_data) 或 None
"""
if len(data) < 12:
return None
# 检查 Report ID
if data[0] != REPORT_ID_GET_RES:
return None
# 解析帧结构
frame_length = int.from_bytes(data[5:7], 'little')
data_length = int.from_bytes(data[9:11], 'little')
# 提取 Data 段
response_data = data[11:11+data_length]
if len(response_data) < 1:
return None
status = response_data[0]
return (status, response_data[1:])
# ==================== 命令函数 ====================
def cmd_get_version() -> bytes:
"""读版本号命令"""
return bytes([0xc0])
def cmd_buzzer(on: bool) -> bytes:
"""蜂鸣器控制命令"""
return bytes([0xcd, 0x01 if on else 0x00])
def cmd_set_power(power: int) -> bytes:
"""设置功率命令 (0-9)"""
power = max(0, min(9, power))
return bytes([0xcc, power])
def cmd_set_mode(mode: int) -> bytes:
"""设置工作模式命令
1: 单标签巡查
2: 被动模式
3: 多标签巡查
"""
return bytes([0x0f, mode])
def cmd_read_epc() -> bytes:
"""读取 EPC 命令"""
return bytes([0xce, 0xbb, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7e])
def cmd_select_card(epc_data: bytes) -> bytes:
"""选中卡命令"""
# 固定前缀 + EPC 数据
payload = bytes([0x01, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00]) + epc_data
# 计算 checksum
card_op_cmd = bytes([0x00, 0x0c])
checksum = 0
for b in card_op_cmd + payload:
checksum = (checksum + b) & 0xFF
internal_len = len(payload).to_bytes(2, 'little')
return bytes([0xce, 0xbb]) + card_op_cmd + internal_len + payload + bytes([checksum, 0x7e])
def cmd_write_epc(old_epc_crc: bytes, new_epc: bytes) -> bytes:
"""写入 EPC 命令"""
epc_len_indicator = (len(new_epc) * 4) // 4
if epc_len_indicator == 0:
epc_len_indicator = 8
word_count = 2 + len(new_epc) // 2
payload = bytes([0x00, 0x00, 0x00, 0x00, 0x01, 0x00]) # Reserved
payload += bytes([0x00, 0x00]) # Reserved
payload += bytes([word_count]) # Word Count
payload += old_epc_crc # Old EPC CRC
payload += bytes([epc_len_indicator, 0x00]) # EPC Len Indicator, Status
payload += new_epc # New EPC Data
# 计算 checksum
card_op_cmd = bytes([0x00, 0x49])
checksum = 0
for b in card_op_cmd + len(payload).to_bytes(2, 'little') + payload:
checksum = (checksum + b) & 0xFF
internal_len = len(payload).to_bytes(2, 'little')
return bytes([0xce, 0xbb]) + card_op_cmd + internal_len + payload + bytes([checksum, 0x7e])
# ==================== 设备管理类 ====================
class RFIDDevice:
def __init__(self):
self.device = None
self.vendor_id = VENDOR_ID
self.product_id = PRODUCT_ID
def list_devices(self):
"""列出所有 HID 设备"""
devices = []
try:
for d in hid.enumerate():
devices.append({
'vendor_id': d['vendor_id'],
'product_id': d['product_id'],
'manufacturer_string': d.get('manufacturer_string', ''),
'product_string': d.get('product_string', ''),
'serial_number': d.get('serial_number', ''),
'interface_number': d.get('interface_number', -1),
'path': d['path']
})
except Exception as e:
print(f"枚举设备失败: {e}")
return devices
def connect(self, vendor_id=None, product_id=None):
"""连接设备"""
if vendor_id:
self.vendor_id = vendor_id
if product_id:
self.product_id = product_id
try:
self.device = hid.device()
self.device.open(self.vendor_id, self.product_id)
return True, f"已连接到设备 (VID: 0x{self.vendor_id:04x}, PID: 0x{self.product_id:04x})"
except Exception as e:
return False, f"连接失败: {e}"
def disconnect(self):
"""断开连接"""
if self.device:
try:
self.device.close()
except:
pass
self.device = None
return "已断开连接"
def is_connected(self):
"""检查是否已连接"""
return self.device is not None
def send_command(self, cmd_data: bytes):
"""发送命令并接收响应"""
if not self.device:
return None, "设备未连接"
try:
# 构建并发送 SetReq
frame = build_setreq_frame(cmd_data)
self.device.send_feature_report(frame)
# 接收 GetRes
time.sleep(0.1)
response = self.device.get_feature_report(REPORT_ID_GET_RES, REPORT_SIZE)
# 解析响应
result = parse_getres_frame(bytes(response))
if result is None:
return None, "响应格式错误"
status, data = result
return data, None
except Exception as e:
return None, f"通信错误: {e}"
# ==================== GUI 界面 ====================
def create_window():
"""创建主窗口"""
sg.theme('LightBlue2')
# 设备连接区域
device_frame = [
[sg.Text('VID (十六进制):'), sg.Input('FFFF', size=(8, 1), key='-VID-'),
sg.Text('PID (十六进制):'), sg.Input('0035', size=(8, 1), key='-PID-'),
sg.Button('枚举设备', key='-ENUM-'),
sg.Button('连接', key='-CONNECT-'),
sg.Button('断开', key='-DISCONNECT-')],
[sg.Text('状态: ', size=(12, 1)), sg.Text('未连接', key='-STATUS-', text_color='red')]
]
# 基本命令区域
basic_frame = [
[sg.Button('读取版本号', key='-VERSION-', size=(15, 1)),
sg.Button('打开蜂鸣器', key='-BUZZER_ON-', size=(15, 1)),
sg.Button('关闭蜂鸣器', key='-BUZZER_OFF-', size=(15, 1))],
[sg.Text('功率 (0-9):'), sg.Slider(range=(0, 9), default_value=8, orientation='h', size=(20, 15), key='-POWER-'),
sg.Button('设置功率', key='-SET_POWER-')],
[sg.Text('工作模式:'),
sg.Radio('单标签巡查', 'mode', key='-MODE1-', default=True),
sg.Radio('被动模式', 'mode', key='-MODE2-'),
sg.Radio('多标签巡查', 'mode', key='-MODE3-'),
sg.Button('设置模式', key='-SET_MODE-')]
]
# EPC 操作区域
epc_frame = [
[sg.Button('读取 EPC', key='-READ_EPC-', size=(15, 1)),
sg.Button('选中卡', key='-SELECT_CARD-', size=(15, 1))],
[sg.Text('EPC 数据 (十六进制):'), sg.Input('', size=(40, 1), key='-EPC_DATA-')],
[sg.Text('新 EPC (十六进制):'), sg.Input('', size=(40, 1), key='-NEW_EPC-')],
[sg.Button('写入 EPC', key='-WRITE_EPC-', size=(15, 1))]
]
# 日志输出区域
log_frame = [
[sg.Multiline('', size=(80, 15), key='-LOG-', autoscroll=True, disabled=True)]
]
layout = [
[sg.Frame('设备连接', device_frame)],
[sg.Frame('基本命令', basic_frame)],
[sg.Frame('EPC 操作', epc_frame)],
[sg.Frame('日志', log_frame)],
[sg.Button('清空日志', key='-CLEAR_LOG-'), sg.Button('退出', key='-EXIT-')]
]
return sg.Window('MT6 RFID 读卡器测试程序', layout, finalize=True)
def log_message(window, message, is_hex=False):
"""输出日志消息"""
timestamp = time.strftime('%H:%M:%S')
if is_hex:
if isinstance(message, bytes):
hex_str = ' '.join(f'{b:02x}' for b in message)
window['-LOG-'].print(f'[{timestamp}] {hex_str}')
else:
window['-LOG-'].print(f'[{timestamp}] {message}')
else:
window['-LOG-'].print(f'[{timestamp}] {message}')
def hex_to_bytes(hex_str: str) -> bytes:
"""十六进制字符串转字节"""
hex_str = hex_str.replace(' ', '').replace(',', '')
return bytes.fromhex(hex_str)
def main():
"""主函数"""
window = create_window()
rfid = RFIDDevice()
device_list = []
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, '-EXIT-'):
rfid.disconnect()
break
# 枚举设备
if event == '-ENUM-':
device_list = rfid.list_devices()
if device_list:
log_message(window, f"找到 {len(device_list)} 个 HID 设备")
device_strs = []
for i, d in enumerate(device_list):
s = f"[{i}] VID:0x{d['vendor_id']:04x} PID:0x{d['product_id']:04x} " \
f"IF:{d['interface_number']} {d['manufacturer_string']} {d['product_string']}"
device_strs.append(s)
log_message(window, s)
# 创建设备选择窗口
select_layout = [
[sg.Listbox(values=device_strs, size=(80, min(10, len(device_strs))), key='-SELECTED-')],
[sg.Button('使用选中设备'), sg.Button('取消')]
]
select_window = sg.Window('选择设备', select_layout, modal=True)
while True:
sel_event, sel_values = select_window.read()
if sel_event in (sg.WIN_CLOSED, '取消'):
select_window.close()
break
if sel_event == '使用选中设备':
selected_idx = sel_values.get('-SELECTED-', [])
if selected_idx:
idx = device_strs.index(selected_idx[0])
d = device_list[idx]
window['-VID-'].update(f"{d['vendor_id']:04x}")
window['-PID-'].update(f"{d['product_id']:04x}")
log_message(window, f"已选择设备: VID=0x{d['vendor_id']:04x}, PID=0x{d['product_id']:04x}, IF={d['interface_number']}")
select_window.close()
break
else:
log_message(window, "未找到 HID 设备")
# 连接设备
if event == '-CONNECT-':
try:
vid = int(values['-VID-'], 16)
pid = int(values['-PID-'], 16)
success, msg = rfid.connect(vid, pid)
log_message(window, msg)
if success:
window['-STATUS-'].update('已连接', text_color='green')
else:
window['-STATUS-'].update('连接失败', text_color='red')
except ValueError:
log_message(window, "请输入有效的十六进制 VID/PID")
# 断开连接
if event == '-DISCONNECT-':
msg = rfid.disconnect()
log_message(window, msg)
window['-STATUS-'].update('未连接', text_color='red')
# 读取版本号
if event == '-VERSION-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
log_message(window, "发送命令: 读版本号")
data, err = rfid.send_command(cmd_get_version())
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应 (hex): ", is_hex=True)
log_message(window, data, is_hex=True)
try:
version = data.decode('ascii', errors='ignore')
log_message(window, f"版本: {version}")
except:
pass
# 蜂鸣器控制
if event == '-BUZZER_ON-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
log_message(window, "发送命令: 打开蜂鸣器")
data, err = rfid.send_command(cmd_buzzer(True))
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应: {data.hex() if data else '无数据'}")
if event == '-BUZZER_OFF-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
log_message(window, "发送命令: 关闭蜂鸣器")
data, err = rfid.send_command(cmd_buzzer(False))
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应: {data.hex() if data else '无数据'}")
# 设置功率
if event == '-SET_POWER-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
power = int(values['-POWER-'])
log_message(window, f"发送命令: 设置功率 = {power}")
data, err = rfid.send_command(cmd_set_power(power))
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应: {data.hex() if data else '无数据'}")
# 设置工作模式
if event == '-SET_MODE-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
mode = 1
if values['-MODE2-']:
mode = 2
elif values['-MODE3-']:
mode = 3
mode_names = {1: '单标签巡查', 2: '被动模式', 3: '多标签巡查'}
log_message(window, f"发送命令: 设置模式 = {mode_names.get(mode, mode)}")
data, err = rfid.send_command(cmd_set_mode(mode))
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应: {data.hex() if data else '无数据'}")
# 读取 EPC
if event == '-READ_EPC-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
log_message(window, "发送命令: 读取 EPC")
data, err = rfid.send_command(cmd_read_epc())
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应 (hex): ", is_hex=True)
log_message(window, data, is_hex=True)
# 解析 EPC
if data and len(data) > 10:
# 检查 Card Op Resp
if data[2:4] == b'\x02\x22':
# 有卡
rssi = data[6] if len(data) > 6 else 0
epc_len_indicator = data[7] if len(data) > 7 else 0
epc_len = epc_len_indicator // 4 if epc_len_indicator > 0 else 0
epc_data = data[9:9+epc_len] if len(data) > 9 else b''
log_message(window, f"RSSI: 0x{rssi:02x}")
log_message(window, f"EPC: {epc_data.hex()}")
window['-EPC_DATA-'].update(epc_data.hex())
elif data[2:4] == b'\x01\xff':
log_message(window, "无卡或读取失败")
else:
log_message(window, f"未知响应: {data[2:4].hex()}")
# 选中卡
if event == '-SELECT_CARD-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
epc_hex = values['-EPC_DATA-'].strip()
if not epc_hex:
log_message(window, "错误: 请输入 EPC 数据")
else:
try:
epc_data = hex_to_bytes(epc_hex)
log_message(window, f"发送命令: 选中卡 EPC={epc_data.hex()}")
data, err = rfid.send_command(cmd_select_card(epc_data))
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应 (hex): {data.hex() if data else '无数据'}")
if data and len(data) > 6:
if data[6] == 0x00:
log_message(window, "选中成功")
else:
log_message(window, f"选中失败: 0x{data[6]:02x}")
except ValueError:
log_message(window, "错误: EPC 数据格式错误,请使用十六进制")
# 写入 EPC
if event == '-WRITE_EPC-':
if not rfid.is_connected():
log_message(window, "错误: 设备未连接")
else:
new_epc_hex = values['-NEW_EPC-'].strip()
if not new_epc_hex:
log_message(window, "错误: 请输入新的 EPC 数据")
else:
try:
new_epc = hex_to_bytes(new_epc_hex)
# 这里需要一个旧的 EPC CRC暂时使用示例值
old_epc_crc = bytes([0xca, 0x9e]) # 需要根据实际 EPC 计算
log_message(window, f"发送命令: 写入 EPC={new_epc.hex()}")
data, err = rfid.send_command(cmd_write_epc(old_epc_crc, new_epc))
if err:
log_message(window, f"错误: {err}")
else:
log_message(window, f"响应 (hex): {data.hex() if data else '无数据'}")
except ValueError:
log_message(window, "错误: EPC 数据格式错误,请使用十六进制")
# 清空日志
if event == '-CLEAR_LOG-':
window['-LOG-'].update('')
window.close()
if __name__ == '__main__':
main()

228
test_protocol.py Normal file
View File

@@ -0,0 +1,228 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试 MT6 RFID 读卡器协议函数
"""
import sys
import os
# 添加 PySimpleGUI 目录到路径
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'PySimpleGUI'))
# 导入协议函数
from rfid_tester import (
calc_outer_checksum,
build_setreq_frame,
parse_getres_frame,
cmd_get_version,
cmd_buzzer,
cmd_set_power,
cmd_set_mode,
cmd_read_epc,
cmd_select_card,
cmd_write_epc,
)
def test_calc_outer_checksum():
"""测试校验和计算"""
print("\n=== 测试校验和计算 ===")
# 根据文档,读版本号命令的校验和应该是 0xc1
# Data Length: 01 00 (小端序)
# Data: c0
data_len = bytes([0x01, 0x00])
data = bytes([0xc0])
checksum = calc_outer_checksum(data_len, data)
print(f"读版本号校验和: 0x{checksum:02x} (期望: 0xc1)")
assert checksum == 0xc1, f"校验和计算错误: 期望 0xc1, 实际 0x{checksum:02x}"
# 打开蜂鸣器的校验和应该是 0xce
# Data Length: 02 00
# Data: cd 01
data_len = bytes([0x02, 0x00])
data = bytes([0xcd, 0x01])
checksum = calc_outer_checksum(data_len, data)
print(f"打开蜂鸣器校验和: 0x{checksum:02x} (期望: 0xce)")
assert checksum == 0xce, f"校验和计算错误: 期望 0xce, 实际 0x{checksum:02x}"
# 设置功率=8的校验和应该是 0xc6
# Data Length: 02 00
# Data: cc 08
data_len = bytes([0x02, 0x00])
data = bytes([0xcc, 0x08])
checksum = calc_outer_checksum(data_len, data)
print(f"设置功率=8校验和: 0x{checksum:02x} (期望: 0xc6)")
assert checksum == 0xc6, f"校验和计算错误: 期望 0xc6, 实际 0x{checksum:02x}"
print("校验和测试通过!")
def test_build_setreq_frame():
"""测试帧构建"""
print("\n=== 测试帧构建 ===")
# 测试读版本号命令
cmd = cmd_get_version()
frame = build_setreq_frame(cmd)
# 根据文档,应该是: 01 00 00 00 00 06 00 00 02 01 00 c0 c1 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x01, 0x00, 0xc0, 0xc1, 0x03])
print(f"读版本号帧 (前14字节): {frame[:14].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:14] == expected, f"读版本号帧不匹配"
assert len(frame) == 256, f"帧长度应为256字节实际为{len(frame)}"
print("读版本号帧测试通过!")
# 测试打开蜂鸣器命令
cmd = cmd_buzzer(True)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 cd 01 ce 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0xcd, 0x01, 0xce, 0x03])
print(f"打开蜂鸣器帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"打开蜂鸣器帧不匹配"
print("打开蜂鸣器帧测试通过!")
# 测试关闭蜂鸣器命令
cmd = cmd_buzzer(False)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 cd 00 cf 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0xcd, 0x00, 0xcf, 0x03])
print(f"关闭蜂鸣器帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"关闭蜂鸣器帧不匹配"
print("关闭蜂鸣器帧测试通过!")
# 测试设置功率命令
cmd = cmd_set_power(8)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 cc 08 c6 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0xcc, 0x08, 0xc6, 0x03])
print(f"设置功率=8帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"设置功率帧不匹配"
print("设置功率帧测试通过!")
# 测试设置被动模式命令
cmd = cmd_set_mode(2)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 0f 02 0f 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0f, 0x02, 0x0f, 0x03])
print(f"设置被动模式帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"设置模式帧不匹配"
print("设置模式帧测试通过!")
# 测试读取 EPC 命令
cmd = cmd_read_epc()
frame = build_setreq_frame(cmd)
print(f"读取EPC帧 (前20字节): {frame[:20].hex()}")
# 验证帧结构
assert frame[0] == 0x01, "Report ID 应为 0x01"
assert frame[1:5] == b'\x00\x00\x00\x00', "固定字段应为 0x00000000"
assert frame[7:9] == b'\x00\x02', "Constant 应为 0x0002"
print("读取EPC帧测试通过!")
def test_parse_getres_frame():
"""测试响应帧解析"""
print("\n=== 测试响应帧解析 ===")
# 模拟读版本号成功的响应
# Report ID: 0x03
# 响应数据: 00 + 版本字符串 "MT6_RF915_RW"
version_str = b"MT6_RF915_RW"
response = bytearray()
response.append(0x03) # Report ID
response.extend([0x00, 0x00, 0x00, 0x00]) # Fixed
frame_len = 2 + 2 + 1 + len(version_str) # constant + data_len + status + version
response.extend(frame_len.to_bytes(2, 'little')) # Frame Length
response.extend([0x00, 0x02]) # Constant
data_len = 1 + len(version_str)
response.extend(data_len.to_bytes(2, 'little')) # Data Length
response.append(0x00) # Status = 成功
response.extend(version_str) # Version string
# 计算校验和
checksum = calc_outer_checksum(data_len.to_bytes(2, 'little'), bytes([0x00]) + version_str)
response.append(checksum)
response.append(0x03) # End Marker
result = parse_getres_frame(bytes(response))
assert result is not None, "解析失败"
status, data = result
print(f"状态: 0x{status:02x} (期望: 0x00)")
print(f"数据: {data}")
assert status == 0x00, f"状态应为 0x00实际为 0x{status:02x}"
assert data.decode('ascii').startswith("MT6"), "版本字符串应包含 MT6"
print("响应帧解析测试通过!")
def test_command_functions():
"""测试命令生成函数"""
print("\n=== 测试命令生成函数 ===")
# 测试读版本号命令
cmd = cmd_get_version()
print(f"读版本号命令: {cmd.hex()}")
assert cmd == bytes([0xc0]), f"读版本号命令应为 c0"
# 测试蜂鸣器命令
cmd = cmd_buzzer(True)
print(f"打开蜂鸣器命令: {cmd.hex()}")
assert cmd == bytes([0xcd, 0x01]), f"打开蜂鸣器命令应为 cd 01"
cmd = cmd_buzzer(False)
print(f"关闭蜂鸣器命令: {cmd.hex()}")
assert cmd == bytes([0xcd, 0x00]), f"关闭蜂鸣器命令应为 cd 00"
# 测试设置功率命令
cmd = cmd_set_power(5)
print(f"设置功率=5命令: {cmd.hex()}")
assert cmd == bytes([0xcc, 0x05]), f"设置功率=5命令应为 cc 05"
# 测试设置模式命令
cmd = cmd_set_mode(1)
print(f"设置单标签巡查模式命令: {cmd.hex()}")
assert cmd == bytes([0x0f, 0x01]), f"设置单标签巡查模式命令应为 0f 01"
cmd = cmd_set_mode(2)
print(f"设置被动模式命令: {cmd.hex()}")
assert cmd == bytes([0x0f, 0x02]), f"设置被动模式命令应为 0f 02"
# 测试读取 EPC 命令
cmd = cmd_read_epc()
print(f"读取EPC命令: {cmd.hex()}")
assert cmd == bytes([0xce, 0xbb, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7e]), f"读取EPC命令不匹配"
print("命令生成函数测试通过!")
def main():
"""主测试函数"""
print("=" * 60)
print("MT6 RFID 读卡器协议函数测试")
print("=" * 60)
try:
test_calc_outer_checksum()
test_build_setreq_frame()
test_parse_getres_frame()
test_command_functions()
print("\n" + "=" * 60)
print("所有测试通过!")
print("=" * 60)
return 0
except AssertionError as e:
print(f"\n测试失败: {e}")
return 1
except Exception as e:
print(f"\n测试出错: {e}")
import traceback
traceback.print_exc()
return 1
if __name__ == '__main__':
sys.exit(main())