SwiftGUI 0.11.20__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swiftgui-0.11.20 → swiftgui-0.12.0}/PKG-INFO +35 -34
- swiftgui-0.12.0/README.md +100 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/pyproject.toml +1 -1
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Base.py +22 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/GlobalOptions.py +3 -2
- swiftgui-0.12.0/src/SwiftGUI/Validate/Base.py +119 -0
- swiftgui-0.12.0/src/SwiftGUI/Validate/Common.py +82 -0
- swiftgui-0.12.0/src/SwiftGUI/Validate/Regex.py +20 -0
- swiftgui-0.12.0/src/SwiftGUI/Validate/__init__.py +4 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Combobox.py +7 -3
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Input.py +2 -2
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Spinbox.py +20 -15
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/__init__.py +2 -0
- swiftgui-0.11.20/README.md +0 -99
- {swiftgui-0.11.20 → swiftgui-0.12.0}/LICENSE +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/BasePopup.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Arc.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Bitmap.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Element.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Image.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Line.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Oval.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Polygon.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Rectangle.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Text.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/_Base.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/__init__.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Colors.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/BaseCombinedElement.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/Calendar.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/Console.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/Form.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/MultistateButton.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Compat.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Debug.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/DecoratorKeys.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/ElementFlags.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Events.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Examples/AllElements.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Examples/AllThemes.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Examples/GlobalOptionBrowser.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Examples/Previews.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Examples/__init__.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Exceptions.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/ColorChooserButton.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/ComboboxMapping.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/FileBrowseButton.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Image.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/ImageButton.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/PythonConsole.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Separator.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Spacer.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/TabFrame.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Table.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extras/SwiftGUI.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Extras/__init__.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Files/ConfigFile.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Files/ConfigurationEditor.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Files/DictFile.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Files/ProgramDirectory.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Files/__init__.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Fonts.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/KeyFunctions.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Literals.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Popups/ElementPopup.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Popups/ListPicker.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Popups/SmallPopups.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Popups/TooltipPopup.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Popups/VirtualKeyboard.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Popups/__init__.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Themes/FourColors.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Themes/Thematic.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Themes/_BaseTheme.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Themes/__init__.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Tools.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Tooltips.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Utilities/Images.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Utilities/Threads.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Button.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Canvas.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Checkbox.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Frame.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/GridFrame.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/LabelFrame.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Listbox.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Notebook.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Progressbar.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Radiobutton.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Scale.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Scrollbar.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/TKContainer.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Text.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/TextField.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Treeview.py +0 -0
- {swiftgui-0.11.20 → swiftgui-0.12.0}/src/SwiftGUI/Windows.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SwiftGUI
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: An easy-to-use package for quickly creating smaller and bigger GUIs
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -21,7 +21,6 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
# SwiftGUI
|
|
24
|
-
|
|
25
24
|
A python-package to easily create user-interfaces (GUIs).
|
|
26
25
|
|
|
27
26
|
While most packages focus either on small, or big applications, SwiftGUI does both.
|
|
@@ -32,20 +31,20 @@ Has some minor optimizations when running in Python 3.12+.
|
|
|
32
31
|
# Getting started / documentation
|
|
33
32
|
[Start your journey here](https://github.com/CheesecakeTV/SwiftGUI-Docs/blob/main/01%20Basic%20tutorials/01%20Getting-started.md)
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
[Documentation](https://github.com/CheesecakeTV/SwiftGUI-Docs).
|
|
36
35
|
|
|
37
|
-
#
|
|
36
|
+
# Vibe-coding free
|
|
38
37
|
No AI was used in writing this code.
|
|
39
38
|
|
|
40
39
|
The only way I used it was to research really specific topics with tkinter.
|
|
41
40
|
|
|
42
|
-
I did not use AI to write, check, correct, or refractor code.
|
|
43
|
-
|
|
44
41
|
Even the documentation was written completely AI-free.
|
|
45
42
|
Takes me around 2 hours per document, but that's a good price for keeping everything slop-free.
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
Yes, this does slow down development quite a bit, but I trust myself to be more reliable than an AI agent.
|
|
45
|
+
|
|
46
|
+
# 38 different elements, 9 different canvas-elements
|
|
47
|
+
(Version 0.12.0)
|
|
49
48
|
|
|
50
49
|
`import SwiftGUI as sg`
|
|
51
50
|
|
|
@@ -60,18 +59,14 @@ This applies the `Emerald`-theme, my personal favorite.
|
|
|
60
59
|
|
|
61
60
|
See which themes are available by calling `sg.Examples.preview_all_themes()`.
|
|
62
61
|
|
|
63
|
-
#
|
|
64
|
-
|
|
62
|
+
# Final minor version before Beta starts!
|
|
63
|
+
You might have noticed that updates for SwiftGUI are rarer than they used to be.
|
|
64
|
+
That's actually a good sign, it means I find less things to add/correct.
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
Names and functions/methods might change, which could potentially mess up your code.
|
|
66
|
+
There will not be version 0.13.0, but 1.0.0 instead.
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
If changes can't be avoided, there will be a separate changelog which shows everything you need to
|
|
72
|
-
adjust so you may update without issues.
|
|
73
|
-
|
|
74
|
-
Don't worry too much though, the package is pretty much ready for beta-phase.
|
|
68
|
+
I do have a couple of major tasks on my list before rolling out 1.0 though.
|
|
69
|
+
Fixing the treeview for example.
|
|
75
70
|
|
|
76
71
|
# Installation
|
|
77
72
|
Install using pip:
|
|
@@ -79,27 +74,28 @@ Install using pip:
|
|
|
79
74
|
pip install SwiftGUI
|
|
80
75
|
```
|
|
81
76
|
|
|
82
|
-
|
|
77
|
+
Regularely update SwiftGUI for the newest features and bugfixes:
|
|
83
78
|
```bash
|
|
84
79
|
pip install SwiftGUI -U
|
|
85
80
|
```
|
|
86
81
|
|
|
87
82
|
# NOT a clone of PySimpleGUI
|
|
88
|
-
SwiftGUI is it's own package with its own functionality.
|
|
83
|
+
SwiftGUI is it's own package, with its own functionality.
|
|
89
84
|
|
|
90
85
|
I really liked PySimpleGUI (until they went "premium"),
|
|
91
|
-
but once you work a lot with it, you'll notice
|
|
86
|
+
but once you work a lot with it, you'll notice its downsides more and more.
|
|
92
87
|
|
|
93
|
-
|
|
94
|
-
So if you know PySimpleGUI, you
|
|
88
|
+
The basics of SwiftGUI are almost the same as PySimpleGUI.
|
|
89
|
+
So if you know PySimpleGUI, you already know many concepts of SwiftGUI.
|
|
95
90
|
|
|
96
|
-
|
|
97
|
-
- Written tutorials (see "getting started"
|
|
98
|
-
-
|
|
99
|
-
- Application notes, which are short descriptions of actual applications
|
|
91
|
+
There is already a collection of helpful learning material, including:
|
|
92
|
+
- Written tutorials (see "getting started" above)
|
|
93
|
+
- Application notes, which summarize different tutorials regarding specific applications
|
|
100
94
|
- Examples, which show an actual application of SwiftGUI
|
|
101
95
|
- The GitHub forum ([discussions](https://github.com/CheesecakeTV/SwiftGUI/discussions)) for questions
|
|
102
96
|
|
|
97
|
+
Video tutorials are planned for version 1.0.0.
|
|
98
|
+
|
|
103
99
|
## Why SwiftGUI instead of PySimpleGUI?
|
|
104
100
|
I have a lot of experience with `PySimpleGUI`, used it for years.\
|
|
105
101
|
It is very useful for smaller applications.
|
|
@@ -107,15 +103,20 @@ It is very useful for smaller applications.
|
|
|
107
103
|
Unfortunately, at a certain level of complexity, you'll hit a wall.\
|
|
108
104
|
All those simple features that make PySimpleGUI great, are suddenly very annoying.
|
|
109
105
|
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
In the earlier versions of SwiftGUI, it was ment to "fix" annoying things in PySimpleGUI.
|
|
107
|
+
For example:
|
|
108
|
+
- You are forced to use the event-loop for every tiny functionality
|
|
109
|
+
- You can pretty much forget about editing elements, since they are implemented so convoluded
|
|
110
|
+
- Some elements throw events wrong, including sg.Table and sg.Input
|
|
112
111
|
|
|
113
|
-
SwiftGUI
|
|
114
|
-
That makes it easy to "copy and paste" parts of the layout.
|
|
112
|
+
Nowadays, SwiftGUI's functionality goes far beyond what PySimpleGUI has to offer.
|
|
115
113
|
|
|
116
|
-
|
|
114
|
+
The reason is simple:
|
|
115
|
+
SwiftGUI is built for modularity and expandability.
|
|
116
|
+
You can easily create templates, themes, custom popups, modify elements, etc.
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
Also, SwiftGUI works a lot better with multiple windows.
|
|
119
|
+
Creating a second window is almost as simple as creating a single one.
|
|
120
120
|
|
|
121
|
+
A lot more features are described/mentioned in the documentation.
|
|
121
122
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
|
|
2
|
+
# SwiftGUI
|
|
3
|
+
A python-package to easily create user-interfaces (GUIs).
|
|
4
|
+
|
|
5
|
+
While most packages focus either on small, or big applications, SwiftGUI does both.
|
|
6
|
+
|
|
7
|
+
## Compatible with Python 3.10 and above
|
|
8
|
+
Has some minor optimizations when running in Python 3.12+.
|
|
9
|
+
|
|
10
|
+
# Getting started / documentation
|
|
11
|
+
[Start your journey here](https://github.com/CheesecakeTV/SwiftGUI-Docs/blob/main/01%20Basic%20tutorials/01%20Getting-started.md)
|
|
12
|
+
|
|
13
|
+
[Documentation](https://github.com/CheesecakeTV/SwiftGUI-Docs).
|
|
14
|
+
|
|
15
|
+
# Vibe-coding free
|
|
16
|
+
No AI was used in writing this code.
|
|
17
|
+
|
|
18
|
+
The only way I used it was to research really specific topics with tkinter.
|
|
19
|
+
|
|
20
|
+
Even the documentation was written completely AI-free.
|
|
21
|
+
Takes me around 2 hours per document, but that's a good price for keeping everything slop-free.
|
|
22
|
+
|
|
23
|
+
Yes, this does slow down development quite a bit, but I trust myself to be more reliable than an AI agent.
|
|
24
|
+
|
|
25
|
+
# 38 different elements, 9 different canvas-elements
|
|
26
|
+
(Version 0.12.0)
|
|
27
|
+
|
|
28
|
+
`import SwiftGUI as sg`
|
|
29
|
+
|
|
30
|
+
Call `sg.Examples.preview_all_elements()` for an overview of all currently available elements.
|
|
31
|
+
|
|
32
|
+
# Does your GUI look bad?
|
|
33
|
+
`import SwiftGUI as sg`
|
|
34
|
+
|
|
35
|
+
Just call `sg.Themes.FourColors.Emerald()` before creating the layout.
|
|
36
|
+
|
|
37
|
+
This applies the `Emerald`-theme, my personal favorite.
|
|
38
|
+
|
|
39
|
+
See which themes are available by calling `sg.Examples.preview_all_themes()`.
|
|
40
|
+
|
|
41
|
+
# Final minor version before Beta starts!
|
|
42
|
+
You might have noticed that updates for SwiftGUI are rarer than they used to be.
|
|
43
|
+
That's actually a good sign, it means I find less things to add/correct.
|
|
44
|
+
|
|
45
|
+
There will not be version 0.13.0, but 1.0.0 instead.
|
|
46
|
+
|
|
47
|
+
I do have a couple of major tasks on my list before rolling out 1.0 though.
|
|
48
|
+
Fixing the treeview for example.
|
|
49
|
+
|
|
50
|
+
# Installation
|
|
51
|
+
Install using pip:
|
|
52
|
+
```bash
|
|
53
|
+
pip install SwiftGUI
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Regularely update SwiftGUI for the newest features and bugfixes:
|
|
57
|
+
```bash
|
|
58
|
+
pip install SwiftGUI -U
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
# NOT a clone of PySimpleGUI
|
|
62
|
+
SwiftGUI is it's own package, with its own functionality.
|
|
63
|
+
|
|
64
|
+
I really liked PySimpleGUI (until they went "premium"),
|
|
65
|
+
but once you work a lot with it, you'll notice its downsides more and more.
|
|
66
|
+
|
|
67
|
+
The basics of SwiftGUI are almost the same as PySimpleGUI.
|
|
68
|
+
So if you know PySimpleGUI, you already know many concepts of SwiftGUI.
|
|
69
|
+
|
|
70
|
+
There is already a collection of helpful learning material, including:
|
|
71
|
+
- Written tutorials (see "getting started" above)
|
|
72
|
+
- Application notes, which summarize different tutorials regarding specific applications
|
|
73
|
+
- Examples, which show an actual application of SwiftGUI
|
|
74
|
+
- The GitHub forum ([discussions](https://github.com/CheesecakeTV/SwiftGUI/discussions)) for questions
|
|
75
|
+
|
|
76
|
+
Video tutorials are planned for version 1.0.0.
|
|
77
|
+
|
|
78
|
+
## Why SwiftGUI instead of PySimpleGUI?
|
|
79
|
+
I have a lot of experience with `PySimpleGUI`, used it for years.\
|
|
80
|
+
It is very useful for smaller applications.
|
|
81
|
+
|
|
82
|
+
Unfortunately, at a certain level of complexity, you'll hit a wall.\
|
|
83
|
+
All those simple features that make PySimpleGUI great, are suddenly very annoying.
|
|
84
|
+
|
|
85
|
+
In the earlier versions of SwiftGUI, it was ment to "fix" annoying things in PySimpleGUI.
|
|
86
|
+
For example:
|
|
87
|
+
- You are forced to use the event-loop for every tiny functionality
|
|
88
|
+
- You can pretty much forget about editing elements, since they are implemented so convoluded
|
|
89
|
+
- Some elements throw events wrong, including sg.Table and sg.Input
|
|
90
|
+
|
|
91
|
+
Nowadays, SwiftGUI's functionality goes far beyond what PySimpleGUI has to offer.
|
|
92
|
+
|
|
93
|
+
The reason is simple:
|
|
94
|
+
SwiftGUI is built for modularity and expandability.
|
|
95
|
+
You can easily create templates, themes, custom popups, modify elements, etc.
|
|
96
|
+
|
|
97
|
+
Also, SwiftGUI works a lot better with multiple windows.
|
|
98
|
+
Creating a second window is almost as simple as creating a single one.
|
|
99
|
+
|
|
100
|
+
A lot more features are described/mentioned in the documentation.
|
|
@@ -766,6 +766,28 @@ class BaseWidget(BaseElement):
|
|
|
766
766
|
def __repr__(self) -> str:
|
|
767
767
|
return f"<sg.{self.__class__.__name__} element with key={self.key} at {id(self)}>"
|
|
768
768
|
|
|
769
|
+
def _update_special_key(self,key:str,new_val:Any) -> bool|None:
|
|
770
|
+
|
|
771
|
+
match key:
|
|
772
|
+
case "validatecommand":
|
|
773
|
+
if new_val is None:
|
|
774
|
+
return True
|
|
775
|
+
|
|
776
|
+
if not self.has_flag(ElementFlag.IS_CREATED):
|
|
777
|
+
self.update_after_window_creation(validatecommand=new_val)
|
|
778
|
+
return True
|
|
779
|
+
|
|
780
|
+
as_tuple = tuple(new_val)
|
|
781
|
+
self._tk_kwargs["validatecommand"] = (
|
|
782
|
+
self.tk_widget.register(as_tuple[0]),
|
|
783
|
+
*as_tuple[1:],
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
case _:
|
|
787
|
+
return super()._update_special_key(key, new_val)
|
|
788
|
+
|
|
789
|
+
return True
|
|
790
|
+
|
|
769
791
|
class MixinScrollbar:
|
|
770
792
|
"""
|
|
771
793
|
Base for every widget that has a scrollbar.
|
|
@@ -5,7 +5,7 @@ from collections.abc import Iterable
|
|
|
5
5
|
from os import PathLike
|
|
6
6
|
from typing import Literal, Union, Any, Callable
|
|
7
7
|
|
|
8
|
-
from SwiftGUI import Literals, Color, font_windows, Font, Extras
|
|
8
|
+
from SwiftGUI import Literals, Color, font_windows, Font, Extras, Validate
|
|
9
9
|
from SwiftGUI.Utilities.Images import file_from_b64
|
|
10
10
|
import SwiftGUI as sg
|
|
11
11
|
|
|
@@ -306,7 +306,7 @@ class Input(Common,Common_Textual,Common_Field_Background):
|
|
|
306
306
|
relief: Literals.relief = None
|
|
307
307
|
exportselection: bool = None
|
|
308
308
|
validate: Literals.validate = None
|
|
309
|
-
validatecommand:
|
|
309
|
+
validatecommand: Validate.BaseValidate = None
|
|
310
310
|
insertbackground_color: str | Color = None
|
|
311
311
|
#
|
|
312
312
|
# Mixed options
|
|
@@ -544,6 +544,7 @@ class TabFrame(Frame):
|
|
|
544
544
|
class Spinbox(Button, Input):
|
|
545
545
|
default_value: float = None
|
|
546
546
|
value_type: type = float
|
|
547
|
+
allow_empty: bool = True
|
|
547
548
|
cursor_button: Literals.cursor = None
|
|
548
549
|
background_color_button: Color | str = None
|
|
549
550
|
relief_button_down: Literals.relief = None
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
class Substitutions:
|
|
3
|
+
action_code = "%d" # 0 for deletion, 1 for insertion, -1 for focus or backend-change
|
|
4
|
+
index = "%i" # Index where a deletion/addition was attempted. -1 if none was attempted
|
|
5
|
+
new_value = "%P" # Value after the change, if allowed
|
|
6
|
+
old_value = "%s" # Value before the change
|
|
7
|
+
changed_text = "%S" # The text that was inserted/deleted
|
|
8
|
+
validate = "%v" # This element's validate option
|
|
9
|
+
callback_reason = "%V" # The reason for this callback: 'focusin', 'focusout', 'key', or 'forced' if the text was changed from the backend
|
|
10
|
+
widget_name = "%W" # The name of the TKINTER-widget. This is not the element-key!!!
|
|
11
|
+
|
|
12
|
+
class BaseValidate:
|
|
13
|
+
substitutions: tuple[str, ...] = tuple() # https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/entry-validation.html
|
|
14
|
+
|
|
15
|
+
def __iter__(self): # Generate the tuple that is passed to the tk.widget (after registering the function) later
|
|
16
|
+
return iter((
|
|
17
|
+
self._callback,
|
|
18
|
+
*self.substitutions,
|
|
19
|
+
))
|
|
20
|
+
|
|
21
|
+
def _callback(self, *args) -> bool:
|
|
22
|
+
"""
|
|
23
|
+
Overwrite this to specify the actual validation
|
|
24
|
+
:return:
|
|
25
|
+
"""
|
|
26
|
+
return True
|
|
27
|
+
|
|
28
|
+
class BaseValidateValue(BaseValidate):
|
|
29
|
+
substitutions = (
|
|
30
|
+
Substitutions.new_value,
|
|
31
|
+
Substitutions.callback_reason,
|
|
32
|
+
Substitutions.old_value,
|
|
33
|
+
Substitutions.changed_text,
|
|
34
|
+
Substitutions.action_code,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
#validate_backend_change: bool = False,
|
|
40
|
+
):
|
|
41
|
+
self._validate_backend_change = False # This doesn't work...
|
|
42
|
+
|
|
43
|
+
def _callback(self, val: str, reason: str, val_before: str, changed_val: str, action_code: str) -> bool:
|
|
44
|
+
"""
|
|
45
|
+
Gets called by tkinter.
|
|
46
|
+
All checks must pass to allow the action.
|
|
47
|
+
"""
|
|
48
|
+
if (not self._validate_backend_change) and reason == "forced":
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
if action_code == "0": # Deletion
|
|
52
|
+
if not self.is_valid_deletion(val, val_before, changed_val):
|
|
53
|
+
return False
|
|
54
|
+
elif action_code == "1": # Insertion
|
|
55
|
+
if not self.is_valid_insertion(val, val_before, changed_val):
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
return self.is_valid_full_value(val)
|
|
59
|
+
|
|
60
|
+
def is_valid_full_value(self, val: str) -> bool:
|
|
61
|
+
"""Called on every check with the full value after the change"""
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
def is_valid_insertion(self, val: str, val_before: str, inserted_val: str) -> bool:
|
|
65
|
+
"""Called when text is inserted by the user"""
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
def is_valid_deletion(self, val: str, val_before: str, deleted_val: str) -> bool:
|
|
69
|
+
"""Called when text is deleted by the user"""
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
def __or__(self, other: "BaseValidateValue") -> "Union":
|
|
73
|
+
return Union(self, other)
|
|
74
|
+
|
|
75
|
+
def __and__(self, other: "BaseValidateValue") -> "Chain":
|
|
76
|
+
return Chain(self, other)
|
|
77
|
+
|
|
78
|
+
def __neg__(self) -> "Negate":
|
|
79
|
+
return Negate(self)
|
|
80
|
+
|
|
81
|
+
class Chain(BaseValidateValue):
|
|
82
|
+
|
|
83
|
+
def __init__(self, *validators: BaseValidateValue):
|
|
84
|
+
"""
|
|
85
|
+
Is valid, if ALL passed value-validators passes the value-test
|
|
86
|
+
:param validators:
|
|
87
|
+
"""
|
|
88
|
+
self._validators = validators
|
|
89
|
+
super().__init__()
|
|
90
|
+
|
|
91
|
+
def _callback(self, *args) -> bool:
|
|
92
|
+
return all(map(lambda a: a._callback(*args), self._validators))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Union(BaseValidateValue):
|
|
96
|
+
|
|
97
|
+
def __init__(self, *validators: BaseValidateValue):
|
|
98
|
+
"""
|
|
99
|
+
Is valid, if ANY passed value-validator passes the value-test
|
|
100
|
+
:param validators:
|
|
101
|
+
"""
|
|
102
|
+
self._validators = validators
|
|
103
|
+
super().__init__()
|
|
104
|
+
|
|
105
|
+
def _callback(self, *args) -> bool:
|
|
106
|
+
return any(map(lambda a: a._callback(*args), self._validators))
|
|
107
|
+
|
|
108
|
+
class Negate(BaseValidateValue):
|
|
109
|
+
def __init__(self, validator: BaseValidateValue):
|
|
110
|
+
"""
|
|
111
|
+
Is valid, if the passed validator is not valid
|
|
112
|
+
:param validator:
|
|
113
|
+
"""
|
|
114
|
+
self._validator = validator
|
|
115
|
+
super().__init__()
|
|
116
|
+
|
|
117
|
+
def _callback(self, *args) -> bool:
|
|
118
|
+
return not self._validator._callback(*args)
|
|
119
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from typing import Iterable, Callable
|
|
2
|
+
|
|
3
|
+
from SwiftGUI.Validate import BaseValidateValue
|
|
4
|
+
|
|
5
|
+
class CanConvertTo(BaseValidateValue):
|
|
6
|
+
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
*types: type,
|
|
10
|
+
allow_empty: bool = True,
|
|
11
|
+
exception: type[BaseException] = ValueError,
|
|
12
|
+
):
|
|
13
|
+
"""
|
|
14
|
+
Valid, if the value can be converted to ANY passed type
|
|
15
|
+
:param types: Types to convert into
|
|
16
|
+
:param allow_empty: True, if the value is allowed to be an empty string
|
|
17
|
+
:param exception: This exception will be checked. You can almost always leave it ValueError. If not, change it to Exception.
|
|
18
|
+
:param validate_backend_change:
|
|
19
|
+
"""
|
|
20
|
+
self._types = types
|
|
21
|
+
self._allow_empty = allow_empty
|
|
22
|
+
self._exception = exception
|
|
23
|
+
|
|
24
|
+
super().__init__()
|
|
25
|
+
|
|
26
|
+
def is_valid_full_value(self, val: str) -> bool:
|
|
27
|
+
if self._allow_empty and not val:
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
return any(map(lambda a:self._can_convert_to(val, a), self._types))
|
|
31
|
+
|
|
32
|
+
def _can_convert_to(self, val: str, this_type: type) -> bool:
|
|
33
|
+
try:
|
|
34
|
+
this_type(val)
|
|
35
|
+
except self._exception:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
return True
|
|
39
|
+
|
|
40
|
+
class MaxLength(BaseValidateValue):
|
|
41
|
+
|
|
42
|
+
def __init__(self, max_len: int):
|
|
43
|
+
"""
|
|
44
|
+
The value can not be longer than max_len characters
|
|
45
|
+
:param max_len:
|
|
46
|
+
"""
|
|
47
|
+
self._max_len = max_len
|
|
48
|
+
super().__init__()
|
|
49
|
+
|
|
50
|
+
def is_valid_full_value(self, val: str) -> bool:
|
|
51
|
+
return len(val) <= self._max_len
|
|
52
|
+
|
|
53
|
+
class ForbidDeletions(BaseValidateValue):
|
|
54
|
+
def is_valid_deletion(self, val: str, val_before: str, deleted_val: str) -> bool:
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
class ForbidInsertions(BaseValidateValue):
|
|
58
|
+
def is_valid_insertion(self, val: str, val_before: str, inserted_val: str) -> bool:
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
class WhitelistCharacters(BaseValidateValue):
|
|
62
|
+
def __init__(self, characters: Iterable[str]):
|
|
63
|
+
"""
|
|
64
|
+
Forbid every character not passed.
|
|
65
|
+
Case sensitive
|
|
66
|
+
:param characters:
|
|
67
|
+
"""
|
|
68
|
+
self._chars = set(characters)
|
|
69
|
+
super().__init__()
|
|
70
|
+
|
|
71
|
+
def is_valid_insertion(self, val: str, val_before: str, inserted_val: str) -> bool:
|
|
72
|
+
return all(map(lambda a:a in self._chars, inserted_val))
|
|
73
|
+
|
|
74
|
+
class FullValueFunction(BaseValidateValue):
|
|
75
|
+
def __init__(self, function: Callable[[str], bool]):
|
|
76
|
+
self._fct = function
|
|
77
|
+
super().__init__()
|
|
78
|
+
|
|
79
|
+
def is_valid_full_value(self, val: str) -> bool:
|
|
80
|
+
return self._fct(val)
|
|
81
|
+
|
|
82
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from SwiftGUI.Validate import BaseValidateValue
|
|
3
|
+
|
|
4
|
+
class ReFullMatch(BaseValidateValue):
|
|
5
|
+
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
pattern: str,
|
|
9
|
+
):
|
|
10
|
+
"""
|
|
11
|
+
The full value must match the passed regex-pattern
|
|
12
|
+
:param pattern:
|
|
13
|
+
"""
|
|
14
|
+
self._compiled = re.compile(pattern)
|
|
15
|
+
super().__init__()
|
|
16
|
+
|
|
17
|
+
def is_valid_full_value(self, val: str) -> bool:
|
|
18
|
+
return bool(self._compiled.fullmatch(val))
|
|
19
|
+
|
|
20
|
+
|
|
@@ -4,7 +4,8 @@ from typing import Any, Iterable, Callable, Hashable
|
|
|
4
4
|
from SwiftGUI.Base import run_after_window_creation
|
|
5
5
|
from SwiftGUI.Compat import Self
|
|
6
6
|
|
|
7
|
-
from SwiftGUI import GlobalOptions, BaseWidgetTTK, Literals, Color, ElementFlag, Scrollbar, MixinElementWithValue
|
|
7
|
+
from SwiftGUI import GlobalOptions, BaseWidgetTTK, Literals, Color, ElementFlag, Scrollbar, MixinElementWithValue, \
|
|
8
|
+
Validate
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class Combobox(MixinElementWithValue, BaseWidgetTTK):
|
|
@@ -57,8 +58,8 @@ class Combobox(MixinElementWithValue, BaseWidgetTTK):
|
|
|
57
58
|
|
|
58
59
|
exportselection: bool = None,
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
validate: Literals.validate = None,
|
|
62
|
+
validatecommand: Validate.BaseValidate = None,
|
|
62
63
|
|
|
63
64
|
height: int = None,
|
|
64
65
|
width: int = None,
|
|
@@ -155,6 +156,9 @@ class Combobox(MixinElementWithValue, BaseWidgetTTK):
|
|
|
155
156
|
font_overstrike=font_overstrike,
|
|
156
157
|
|
|
157
158
|
insertbackground = insertbackground,
|
|
159
|
+
|
|
160
|
+
validate=validate,
|
|
161
|
+
validatecommand=validatecommand,
|
|
158
162
|
)
|
|
159
163
|
|
|
160
164
|
@BaseWidgetTTK._run_after_window_creation
|
|
@@ -3,7 +3,7 @@ import tkinter.font as font
|
|
|
3
3
|
from collections.abc import Iterable, Callable
|
|
4
4
|
from typing import Literal, Any, Hashable
|
|
5
5
|
|
|
6
|
-
from SwiftGUI import ElementFlag, BaseWidget, GlobalOptions, Literals, Color, MixinElementWithValue
|
|
6
|
+
from SwiftGUI import ElementFlag, BaseWidget, GlobalOptions, Literals, Color, MixinElementWithValue, Validate
|
|
7
7
|
from SwiftGUI.Compat import Self
|
|
8
8
|
|
|
9
9
|
|
|
@@ -61,7 +61,7 @@ class Input(MixinElementWithValue, BaseWidget):
|
|
|
61
61
|
relief: Literals.relief = None,
|
|
62
62
|
exportselection: bool = None,
|
|
63
63
|
validate: Literals.validate = None,
|
|
64
|
-
validatecommand:
|
|
64
|
+
validatecommand: Validate.BaseValidate = None,
|
|
65
65
|
#
|
|
66
66
|
fonttype: str = None,
|
|
67
67
|
fontsize: int = None,
|
|
@@ -3,7 +3,7 @@ import tkinter.font as font
|
|
|
3
3
|
from collections.abc import Iterable, Callable
|
|
4
4
|
from typing import Literal, Any, Hashable
|
|
5
5
|
|
|
6
|
-
from SwiftGUI import ElementFlag, BaseWidget, GlobalOptions, Literals, Color, MixinElementWithValue
|
|
6
|
+
from SwiftGUI import ElementFlag, BaseWidget, GlobalOptions, Literals, Color, MixinElementWithValue, Validate
|
|
7
7
|
from SwiftGUI.Compat import Self
|
|
8
8
|
|
|
9
9
|
|
|
@@ -11,6 +11,7 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
11
11
|
_tk_widget_class: type = tk.Spinbox # Class of the connected widget
|
|
12
12
|
tk_widget: tk.Spinbox
|
|
13
13
|
defaults = GlobalOptions.Spinbox # Default values (Will be applied to kw_args-dict and passed onto the tk_widget
|
|
14
|
+
_value_type: type = str # Set in update_initial
|
|
14
15
|
|
|
15
16
|
_transfer_keys = {
|
|
16
17
|
"background_color_disabled": "disabledbackground",
|
|
@@ -48,6 +49,7 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
48
49
|
|
|
49
50
|
default_value: Any = None,
|
|
50
51
|
value_type: type = None,
|
|
52
|
+
allow_empty: bool = None,
|
|
51
53
|
|
|
52
54
|
cursor: Literals.cursor = None,
|
|
53
55
|
cursor_button: Literals.cursor = None,
|
|
@@ -159,7 +161,7 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
159
161
|
self._key_function = key_function
|
|
160
162
|
|
|
161
163
|
self._default_val = default_value
|
|
162
|
-
self.
|
|
164
|
+
self._allow_empty = self.defaults.single("allow_empty", allow_empty, default=True)
|
|
163
165
|
|
|
164
166
|
self._update_initial(cursor=cursor, cursor_button=cursor_button,
|
|
165
167
|
takefocus=takefocus, justify=justify, background_color=background_color,
|
|
@@ -178,6 +180,7 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
178
180
|
number_min=number_min, number_max=number_max, increment=increment, width=width,
|
|
179
181
|
repeatdelay=repeatdelay, repeatinterval=repeatinterval, state=state,
|
|
180
182
|
insertbackground_color=insertbackground_color,
|
|
183
|
+
value_type=value_type,
|
|
181
184
|
# validate = "key", # This restricts the user to one type of value
|
|
182
185
|
# validatecommand = (self.parent.register(self._validate), "%P"), # This too
|
|
183
186
|
**tk_kwargs)
|
|
@@ -217,8 +220,15 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
217
220
|
case "font_overstrike":
|
|
218
221
|
self._overstrike = self.defaults.single(key,new_val)
|
|
219
222
|
self.add_flags(ElementFlag.UPDATE_FONT)
|
|
223
|
+
case "value_type":
|
|
224
|
+
self._value_type = new_val
|
|
225
|
+
self._update_initial(
|
|
226
|
+
validate="key",
|
|
227
|
+
validatecommand=Validate.CanConvertTo(new_val, allow_empty=self._allow_empty),
|
|
228
|
+
)
|
|
229
|
+
|
|
220
230
|
case _: # Not a match
|
|
221
|
-
|
|
231
|
+
return super()._update_special_key(key, new_val)
|
|
222
232
|
|
|
223
233
|
return True
|
|
224
234
|
|
|
@@ -242,16 +252,16 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
242
252
|
except tk.TclError: # _tk_target_value isn't used
|
|
243
253
|
pass
|
|
244
254
|
|
|
245
|
-
|
|
255
|
+
if not self._last_viable_value:
|
|
256
|
+
return self._value_type()
|
|
246
257
|
|
|
247
|
-
|
|
248
|
-
try:
|
|
249
|
-
self._value_type(val)
|
|
250
|
-
return True
|
|
251
|
-
except (ValueError, TypeError):
|
|
252
|
-
return False
|
|
258
|
+
return self._value_type(self._last_viable_value)
|
|
253
259
|
|
|
254
260
|
def set_value(self,val:Any) -> Self:
|
|
261
|
+
if self._allow_empty and not val:
|
|
262
|
+
self._prev_value = self._value_type()
|
|
263
|
+
return super().set_value(self._prev_value)
|
|
264
|
+
|
|
255
265
|
try:
|
|
256
266
|
# Try to convert and manually apply the new value
|
|
257
267
|
self._prev_value = self._value_type(val)
|
|
@@ -263,10 +273,5 @@ class Spinbox(MixinElementWithValue, BaseWidget):
|
|
|
263
273
|
def init_window_creation_done(self):
|
|
264
274
|
super().init_window_creation_done()
|
|
265
275
|
|
|
266
|
-
self._update_initial(
|
|
267
|
-
validate= "key",
|
|
268
|
-
validatecommand = (self.tk_widget.register(self._validate), "%P")
|
|
269
|
-
)
|
|
270
|
-
|
|
271
276
|
if self._default_val is not None:
|
|
272
277
|
self._tk_target_value.set(self._default_val)
|
|
@@ -6,6 +6,8 @@ logger.debug("Beginning to load SwiftGUI")
|
|
|
6
6
|
loaded_addons: set[str] = set() # Contains all included SwiftGUI-addons.
|
|
7
7
|
# If you'd like your own addon officially included, create an issue on GitHub.
|
|
8
8
|
|
|
9
|
+
from . import Validate
|
|
10
|
+
|
|
9
11
|
from .Exceptions import *
|
|
10
12
|
|
|
11
13
|
from . import Extras
|
swiftgui-0.11.20/README.md
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# SwiftGUI
|
|
3
|
-
|
|
4
|
-
A python-package to easily create user-interfaces (GUIs).
|
|
5
|
-
|
|
6
|
-
While most packages focus either on small, or big applications, SwiftGUI does both.
|
|
7
|
-
|
|
8
|
-
## Compatible with Python 3.10 and above
|
|
9
|
-
Has some minor optimizations when running in Python 3.12+.
|
|
10
|
-
|
|
11
|
-
# Getting started / documentation
|
|
12
|
-
[Start your journey here](https://github.com/CheesecakeTV/SwiftGUI-Docs/blob/main/01%20Basic%20tutorials/01%20Getting-started.md)
|
|
13
|
-
|
|
14
|
-
The documentation now has [its own repository](https://github.com/CheesecakeTV/SwiftGUI-Docs).
|
|
15
|
-
|
|
16
|
-
# Completely vibe-coding free
|
|
17
|
-
No AI was used in writing this code.
|
|
18
|
-
|
|
19
|
-
The only way I used it was to research really specific topics with tkinter.
|
|
20
|
-
|
|
21
|
-
I did not use AI to write, check, correct, or refractor code.
|
|
22
|
-
|
|
23
|
-
Even the documentation was written completely AI-free.
|
|
24
|
-
Takes me around 2 hours per document, but that's a good price for keeping everything slop-free.
|
|
25
|
-
|
|
26
|
-
# 35 different elements, 9 different canvas-elements
|
|
27
|
-
(Version 0.11.0)
|
|
28
|
-
|
|
29
|
-
`import SwiftGUI as sg`
|
|
30
|
-
|
|
31
|
-
Call `sg.Examples.preview_all_elements()` for an overview of all currently available elements.
|
|
32
|
-
|
|
33
|
-
# Does your GUI look bad?
|
|
34
|
-
`import SwiftGUI as sg`
|
|
35
|
-
|
|
36
|
-
Just call `sg.Themes.FourColors.Emerald()` before creating the layout.
|
|
37
|
-
|
|
38
|
-
This applies the `Emerald`-theme, my personal favorite.
|
|
39
|
-
|
|
40
|
-
See which themes are available by calling `sg.Examples.preview_all_themes()`.
|
|
41
|
-
|
|
42
|
-
# Alpha-phase!
|
|
43
|
-
I am already using SwiftGUI for smaller projects and personally, like it a lot so far.
|
|
44
|
-
|
|
45
|
-
However, until version 1.0.0, downward-compatability is not a priority.
|
|
46
|
-
Names and functions/methods might change, which could potentially mess up your code.
|
|
47
|
-
|
|
48
|
-
For version 1.0.0, I'll sort and standardize names, so they are easier to remember.
|
|
49
|
-
After version 1.0.0, there will be little to no changes that might break existing code.
|
|
50
|
-
If changes can't be avoided, there will be a separate changelog which shows everything you need to
|
|
51
|
-
adjust so you may update without issues.
|
|
52
|
-
|
|
53
|
-
Don't worry too much though, the package is pretty much ready for beta-phase.
|
|
54
|
-
|
|
55
|
-
# Installation
|
|
56
|
-
Install using pip:
|
|
57
|
-
```bash
|
|
58
|
-
pip install SwiftGUI
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Update SwiftGUI for the newest features and elements:
|
|
62
|
-
```bash
|
|
63
|
-
pip install SwiftGUI -U
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
# NOT a clone of PySimpleGUI
|
|
67
|
-
SwiftGUI is it's own package with its own functionality.
|
|
68
|
-
|
|
69
|
-
I really liked PySimpleGUI (until they went "premium"),
|
|
70
|
-
but once you work a lot with it, you'll notice the downsides of it more and more.
|
|
71
|
-
|
|
72
|
-
**SwiftGUI can be used very simmilar to PySimpleGUI**, but has a lot of additional features.\
|
|
73
|
-
So if you know PySimpleGUI, you won't need to start from scratch.
|
|
74
|
-
|
|
75
|
-
Also, there will be a lot of learning-material, including
|
|
76
|
-
- Written tutorials (see "getting started" below)
|
|
77
|
-
- Video tutorials (Planned for version 1.0.0)
|
|
78
|
-
- Application notes, which are short descriptions of actual applications
|
|
79
|
-
- Examples, which show an actual application of SwiftGUI
|
|
80
|
-
- The GitHub forum ([discussions](https://github.com/CheesecakeTV/SwiftGUI/discussions)) for questions
|
|
81
|
-
|
|
82
|
-
## Why SwiftGUI instead of PySimpleGUI?
|
|
83
|
-
I have a lot of experience with `PySimpleGUI`, used it for years.\
|
|
84
|
-
It is very useful for smaller applications.
|
|
85
|
-
|
|
86
|
-
Unfortunately, at a certain level of complexity, you'll hit a wall.\
|
|
87
|
-
All those simple features that make PySimpleGUI great, are suddenly very annoying.
|
|
88
|
-
|
|
89
|
-
What annoys me the most is that PySimpleGUI forces you to use only the event-loop for functionality.
|
|
90
|
-
That means, every tiny tiniest functionality needs a key and code in the event-loop.
|
|
91
|
-
|
|
92
|
-
SwiftGUI on the other hand offers many different ways to connect layout with functionality.
|
|
93
|
-
That makes it easy to "copy and paste" parts of the layout.
|
|
94
|
-
|
|
95
|
-
SwiftGUI also supports multiple windows much better, with every window having its own event-loop.
|
|
96
|
-
|
|
97
|
-
On top of that, SwiftGUI enables expandability everywhere.
|
|
98
|
-
You can easily create your own elements, themes, popups and templates.
|
|
99
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|