flexgui 1.0.2__tar.gz → 1.1.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.
- {flexgui-1.0.2 → flexgui-1.1.0}/PKG-INFO +37 -4
- {flexgui-1.0.2 → flexgui-1.1.0}/README.md +36 -3
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/__init__.py +1 -1
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/app.py +30 -9
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/builder.py +5 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/designer.py +540 -107
- flexgui-1.1.0/flexgui/editor.py +505 -0
- flexgui-1.1.0/flexgui/thuvien.py +295 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/pyproject.toml +1 -1
- flexgui-1.0.2/flexgui/editor.py +0 -277
- {flexgui-1.0.2 → flexgui-1.1.0}/LICENSE +0 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/mode.py +0 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/registry.py +0 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/runtime.py +0 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/theme.py +0 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/triggers.py +0 -0
- {flexgui-1.0.2 → flexgui-1.1.0}/flexgui/widgets.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flexgui
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Thư viện GUI Python kéo-thả-thiết-kế trên tkinter — FlexGUI Studio tích hợp (design mode + mini VS Code cho trigger)
|
|
5
5
|
Keywords: gui,tkinter,designer,drag-and-drop,visual-designer,no-code,vietnamese,flexgui
|
|
6
6
|
Author: FlexGUI Team
|
|
@@ -73,13 +73,21 @@ flexgui.setup() # hoặc: from flexgui import design; design.mode = True
|
|
|
73
73
|
Chạy `python myapp.py` → **Studio tự mở giao diện trống** (hoặc nạp
|
|
74
74
|
thiết kế đã lưu). Tính năng:
|
|
75
75
|
|
|
76
|
-
- Kéo thả mượt (canvas item — không tàn ảnh), **snap lưới 10px** (bật/tắt)
|
|
76
|
+
- Kéo thả mượt (canvas item — không tàn ảnh), **snap lưới 10px** (bật/tắt),
|
|
77
|
+
**lưới chấm** kiểu Figma
|
|
77
78
|
- **Resize 8 núm** quanh thành phần đang chọn
|
|
78
79
|
- **Multi-select**: Ctrl/Shift + click, quét vùng chuột, kéo cả cụm
|
|
79
80
|
- Đổi z-order (menu chuột phải), nhân bản `Ctrl+D`, undo/redo `Ctrl+Z/Y`
|
|
80
81
|
- Bảng thuộc tính bên phải: chữ, tọa độ, kích thước **pixel WYSIWYG**,
|
|
81
82
|
màu chữ/nền, cỡ chữ, **độ trong suốt 0–100%**, ẩn khi chạy, khoá...
|
|
82
|
-
- **
|
|
83
|
+
- **Start F5** — Studio **hóa thành GUI demo thật** ngay trong cửa sổ
|
|
84
|
+
(trigger chạy thật); `■ Stop` hoặc `Esc` quay về thiết kế
|
|
85
|
+
- **Thư viện F1** — tra cứu API + ví dụ (checkbox toggle, nhập input,
|
|
86
|
+
decorator, lệnh app…) — chèn code thẳng vào trigger được
|
|
87
|
+
- **Chuột phải → "Thuộc tính khi bắt đầu"** — chỉnh trạng thái ban đầu
|
|
88
|
+
của widget khi GUI start, hiện ngay trên canvas để dễ hình dung
|
|
89
|
+
- **Ẩn tạm trong studio** (menu chuột phải) — giấu widget để thiết kế đè
|
|
90
|
+
lên vùng nhiều nút chồng nhau; bảng góc trái-dưới liệt kê để hiện lại
|
|
83
91
|
- **Build .exe** bằng PyInstaller (nút ❖ — tự cài nếu thiếu)
|
|
84
92
|
- **Xuất .py** — 1 file tự chạy nhúng toàn bộ thiết kế + trigger
|
|
85
93
|
|
|
@@ -116,7 +124,10 @@ def on_text_5_change(): # gõ chữ trong text[5]
|
|
|
116
124
|
```
|
|
117
125
|
|
|
118
126
|
Quy ước tên hàm: `on_<loại>_<id>_<sự kiện>`
|
|
119
|
-
(`click` / `toggle` / `enter` / `change`).
|
|
127
|
+
(`click` / `toggle` / `enter` / `change`). Muốn sườn hàm nhanh thì bấm
|
|
128
|
+
**`+ Sườn hàm`** trên drawer (1.1.0: việc LƯU không tự sinh hàm nữa — tránh
|
|
129
|
+
file ngày càng dài; hàm mồ côi của widget đã xóa và hàm trùng tên được
|
|
130
|
+
**tự dọn** mỗi lần lưu).
|
|
120
131
|
|
|
121
132
|
Kiểu **decorator** mạnh hơn (cũng viết trong file trigger):
|
|
122
133
|
|
|
@@ -137,6 +148,18 @@ def dong_ho(): ...
|
|
|
137
148
|
def khoi_dong(): ...
|
|
138
149
|
```
|
|
139
150
|
|
|
151
|
+
### Mini VS Code trong Studio — giờ có phát hiện lỗi như VSCode
|
|
152
|
+
|
|
153
|
+
- **Bôi đen + Tab** → thụt lề **cả cụm dòng**; **bôi đen + Shift+Tab** →
|
|
154
|
+
bỏ thụt lề cả cụm (giữ nguyên vùng chọn để thao tác tiếp)
|
|
155
|
+
- **Tự kiểm tra lỗi** ~0.5s sau khi ngừng gõ:
|
|
156
|
+
- lỗi cú pháp Python → tô đỏ dòng + **bảng VẤN ĐỀ** (bấm vào dòng để
|
|
157
|
+
nhảy tới, như Problems của VS Code)
|
|
158
|
+
- cảnh báo **trigger mồ côi** — hàm `on_label_9_click` mà `label[9]`
|
|
159
|
+
không còn trong thiết kế
|
|
160
|
+
- cảnh báo **hàm trùng tên** — def lại 2 lần, bản sau đè bản trước
|
|
161
|
+
- Enter tự thụt lề theo dòng trên (an toàn bộ gõ tiếng Việt Unikey/Telex)
|
|
162
|
+
|
|
140
163
|
## 4. Chạy thật
|
|
141
164
|
|
|
142
165
|
Đổi 1 dòng trong `myapp.py`:
|
|
@@ -234,6 +257,16 @@ flexgui/
|
|
|
234
257
|
|
|
235
258
|
## Lịch sử phiên bản
|
|
236
259
|
|
|
260
|
+
- **1.1.0** — **Start/Stop thay cho "Xem trước"**: F5 biến Studio thành
|
|
261
|
+
**GUI demo thật ngay trong cửa sổ** (trigger chạy thật, đúng cỡ app);
|
|
262
|
+
`■ Stop` / `Esc` đưa về thiết kế. **Thư viện F1** (API + ví dụ chèn được).
|
|
263
|
+
**Chuột phải → Thuộc tính khi bắt đầu** (hiện ngay trên canvas). **Ẩn tạm
|
|
264
|
+
trong studio** + bảng góc hiện lại. Mini VS Code: **bôi đen + Tab /
|
|
265
|
+
Shift+Tab thụt cả cụm dòng** + **tự phát hiện lỗi** (cú pháp, trigger mồ
|
|
266
|
+
côi, hàm trùng) với bảng VẤN ĐỀ. **Fix bug lưu tự thêm hàm**: Lưu không
|
|
267
|
+
còn sinh sườn `def on_label_<id>_click` — chỉ bấm `+ Sườn hàm` mới sinh;
|
|
268
|
+
hàm mồ côi & trùng tên tự dọn khi lưu; xóa widget xóa luôn trigger của nó.
|
|
269
|
+
Đồ họa: nút Start xanh, lưới chấm Figma, thanh "đang chạy thử" nổi.
|
|
237
270
|
- **1.0.2** — **Sửa lỗi "Xem trước" (F5) mở lại Studio**: khi file người
|
|
238
271
|
dùng còn `flexgui.setup()` (hoặc `design.mode = True`, hoặc chạy với cờ
|
|
239
272
|
`--design`), bấm "Xem trước" trước đây làm cửa sổ preview tự hủy rồi mở
|
|
@@ -44,13 +44,21 @@ flexgui.setup() # hoặc: from flexgui import design; design.mode = True
|
|
|
44
44
|
Chạy `python myapp.py` → **Studio tự mở giao diện trống** (hoặc nạp
|
|
45
45
|
thiết kế đã lưu). Tính năng:
|
|
46
46
|
|
|
47
|
-
- Kéo thả mượt (canvas item — không tàn ảnh), **snap lưới 10px** (bật/tắt)
|
|
47
|
+
- Kéo thả mượt (canvas item — không tàn ảnh), **snap lưới 10px** (bật/tắt),
|
|
48
|
+
**lưới chấm** kiểu Figma
|
|
48
49
|
- **Resize 8 núm** quanh thành phần đang chọn
|
|
49
50
|
- **Multi-select**: Ctrl/Shift + click, quét vùng chuột, kéo cả cụm
|
|
50
51
|
- Đổi z-order (menu chuột phải), nhân bản `Ctrl+D`, undo/redo `Ctrl+Z/Y`
|
|
51
52
|
- Bảng thuộc tính bên phải: chữ, tọa độ, kích thước **pixel WYSIWYG**,
|
|
52
53
|
màu chữ/nền, cỡ chữ, **độ trong suốt 0–100%**, ẩn khi chạy, khoá...
|
|
53
|
-
- **
|
|
54
|
+
- **Start F5** — Studio **hóa thành GUI demo thật** ngay trong cửa sổ
|
|
55
|
+
(trigger chạy thật); `■ Stop` hoặc `Esc` quay về thiết kế
|
|
56
|
+
- **Thư viện F1** — tra cứu API + ví dụ (checkbox toggle, nhập input,
|
|
57
|
+
decorator, lệnh app…) — chèn code thẳng vào trigger được
|
|
58
|
+
- **Chuột phải → "Thuộc tính khi bắt đầu"** — chỉnh trạng thái ban đầu
|
|
59
|
+
của widget khi GUI start, hiện ngay trên canvas để dễ hình dung
|
|
60
|
+
- **Ẩn tạm trong studio** (menu chuột phải) — giấu widget để thiết kế đè
|
|
61
|
+
lên vùng nhiều nút chồng nhau; bảng góc trái-dưới liệt kê để hiện lại
|
|
54
62
|
- **Build .exe** bằng PyInstaller (nút ❖ — tự cài nếu thiếu)
|
|
55
63
|
- **Xuất .py** — 1 file tự chạy nhúng toàn bộ thiết kế + trigger
|
|
56
64
|
|
|
@@ -87,7 +95,10 @@ def on_text_5_change(): # gõ chữ trong text[5]
|
|
|
87
95
|
```
|
|
88
96
|
|
|
89
97
|
Quy ước tên hàm: `on_<loại>_<id>_<sự kiện>`
|
|
90
|
-
(`click` / `toggle` / `enter` / `change`).
|
|
98
|
+
(`click` / `toggle` / `enter` / `change`). Muốn sườn hàm nhanh thì bấm
|
|
99
|
+
**`+ Sườn hàm`** trên drawer (1.1.0: việc LƯU không tự sinh hàm nữa — tránh
|
|
100
|
+
file ngày càng dài; hàm mồ côi của widget đã xóa và hàm trùng tên được
|
|
101
|
+
**tự dọn** mỗi lần lưu).
|
|
91
102
|
|
|
92
103
|
Kiểu **decorator** mạnh hơn (cũng viết trong file trigger):
|
|
93
104
|
|
|
@@ -108,6 +119,18 @@ def dong_ho(): ...
|
|
|
108
119
|
def khoi_dong(): ...
|
|
109
120
|
```
|
|
110
121
|
|
|
122
|
+
### Mini VS Code trong Studio — giờ có phát hiện lỗi như VSCode
|
|
123
|
+
|
|
124
|
+
- **Bôi đen + Tab** → thụt lề **cả cụm dòng**; **bôi đen + Shift+Tab** →
|
|
125
|
+
bỏ thụt lề cả cụm (giữ nguyên vùng chọn để thao tác tiếp)
|
|
126
|
+
- **Tự kiểm tra lỗi** ~0.5s sau khi ngừng gõ:
|
|
127
|
+
- lỗi cú pháp Python → tô đỏ dòng + **bảng VẤN ĐỀ** (bấm vào dòng để
|
|
128
|
+
nhảy tới, như Problems của VS Code)
|
|
129
|
+
- cảnh báo **trigger mồ côi** — hàm `on_label_9_click` mà `label[9]`
|
|
130
|
+
không còn trong thiết kế
|
|
131
|
+
- cảnh báo **hàm trùng tên** — def lại 2 lần, bản sau đè bản trước
|
|
132
|
+
- Enter tự thụt lề theo dòng trên (an toàn bộ gõ tiếng Việt Unikey/Telex)
|
|
133
|
+
|
|
111
134
|
## 4. Chạy thật
|
|
112
135
|
|
|
113
136
|
Đổi 1 dòng trong `myapp.py`:
|
|
@@ -205,6 +228,16 @@ flexgui/
|
|
|
205
228
|
|
|
206
229
|
## Lịch sử phiên bản
|
|
207
230
|
|
|
231
|
+
- **1.1.0** — **Start/Stop thay cho "Xem trước"**: F5 biến Studio thành
|
|
232
|
+
**GUI demo thật ngay trong cửa sổ** (trigger chạy thật, đúng cỡ app);
|
|
233
|
+
`■ Stop` / `Esc` đưa về thiết kế. **Thư viện F1** (API + ví dụ chèn được).
|
|
234
|
+
**Chuột phải → Thuộc tính khi bắt đầu** (hiện ngay trên canvas). **Ẩn tạm
|
|
235
|
+
trong studio** + bảng góc hiện lại. Mini VS Code: **bôi đen + Tab /
|
|
236
|
+
Shift+Tab thụt cả cụm dòng** + **tự phát hiện lỗi** (cú pháp, trigger mồ
|
|
237
|
+
côi, hàm trùng) với bảng VẤN ĐỀ. **Fix bug lưu tự thêm hàm**: Lưu không
|
|
238
|
+
còn sinh sườn `def on_label_<id>_click` — chỉ bấm `+ Sườn hàm` mới sinh;
|
|
239
|
+
hàm mồ côi & trùng tên tự dọn khi lưu; xóa widget xóa luôn trigger của nó.
|
|
240
|
+
Đồ họa: nút Start xanh, lưới chấm Figma, thanh "đang chạy thử" nổi.
|
|
208
241
|
- **1.0.2** — **Sửa lỗi "Xem trước" (F5) mở lại Studio**: khi file người
|
|
209
242
|
dùng còn `flexgui.setup()` (hoặc `design.mode = True`, hoặc chạy với cờ
|
|
210
243
|
`--design`), bấm "Xem trước" trước đây làm cửa sổ preview tự hủy rồi mở
|
|
@@ -41,24 +41,33 @@ class App:
|
|
|
41
41
|
goc : None = cửa sổ chính (tk.Tk)
|
|
42
42
|
tk widget = cửa sổ con (Toplevel) — dùng khi
|
|
43
43
|
Studio mở bản XEM TRƯỚC, không chặn Studio.
|
|
44
|
+
trong_khung : tk.Frame — chạy GẮN TRONG khung có sẵn (chế độ
|
|
45
|
+
START của Studio: cửa sổ Studio hóa thành app
|
|
46
|
+
demo thật, nút Stop đưa về thiết kế lại).
|
|
44
47
|
"""
|
|
45
48
|
|
|
46
49
|
def __init__(self, title="Ứng dụng FlexGUI", width=860, height=560,
|
|
47
|
-
bg=None, goc=None):
|
|
50
|
+
bg=None, goc=None, trong_khung=None):
|
|
48
51
|
self.title = title
|
|
49
52
|
self.width = int(width)
|
|
50
53
|
self.height = int(height)
|
|
51
54
|
self._nen = bg or MAU_APP["nen_mac_dinh"]
|
|
52
|
-
self.xem_truoc = goc is not None
|
|
55
|
+
self.xem_truoc = (goc is not None) or (trong_khung is not None)
|
|
56
|
+
self.trong_khung = trong_khung
|
|
53
57
|
self.dang_thiet_ke = False
|
|
58
|
+
self.hoi_dong = None # callback khi bản demo bị đóng
|
|
54
59
|
|
|
55
|
-
if
|
|
60
|
+
if trong_khung is not None:
|
|
61
|
+
# START trong Studio: root = khung nhúng (không phải cửa sổ)
|
|
62
|
+
self.root = trong_khung
|
|
63
|
+
elif goc is None:
|
|
56
64
|
self.root = tk.Tk()
|
|
57
65
|
else:
|
|
58
66
|
self.root = tk.Toplevel(goc)
|
|
59
67
|
self.root.title(title)
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
if trong_khung is None:
|
|
69
|
+
self.root.geometry(f"{self.width}x{self.height}")
|
|
70
|
+
self.root.minsize(320, 200)
|
|
62
71
|
self.root.configure(bg=self._nen)
|
|
63
72
|
self.khung = tk.Frame(self.root, bg=self._nen)
|
|
64
73
|
self.khung.pack(fill="both", expand=True)
|
|
@@ -200,8 +209,10 @@ class App:
|
|
|
200
209
|
self.dong_co.bat_dau()
|
|
201
210
|
|
|
202
211
|
if self.xem_truoc:
|
|
203
|
-
# Bản xem trước
|
|
204
|
-
|
|
212
|
+
# Bản demo/xem trước: đóng = dọn dẹp + destroy (Toplevel)
|
|
213
|
+
# hoặc trả quyền cho Studio (chế độ trong_khung)
|
|
214
|
+
if isinstance(self.root, (tk.Tk, tk.Toplevel)):
|
|
215
|
+
self.root.protocol("WM_DELETE_WINDOW", self._dong_xem_truoc)
|
|
205
216
|
else:
|
|
206
217
|
self.root.protocol("WM_DELETE_WINDOW", self._dong_app)
|
|
207
218
|
|
|
@@ -221,11 +232,21 @@ class App:
|
|
|
221
232
|
pass
|
|
222
233
|
|
|
223
234
|
def _dong_xem_truoc(self):
|
|
224
|
-
"""Đóng bản XEM TRƯỚC (Studio vẫn sống)."""
|
|
235
|
+
"""Đóng bản XEM TRƯỚC / demo START (Studio vẫn sống)."""
|
|
225
236
|
self.dong_co.dung()
|
|
226
237
|
try:
|
|
227
|
-
self.root.
|
|
238
|
+
if isinstance(self.root, (tk.Tk, tk.Toplevel)):
|
|
239
|
+
self.root.destroy()
|
|
240
|
+
elif self.root.winfo_exists():
|
|
241
|
+
self.root.destroy() # khung nhúng trong Studio
|
|
228
242
|
except Exception:
|
|
229
243
|
pass
|
|
230
244
|
if _reg._app_hien_tai() is self:
|
|
231
245
|
_reg._dat_app(None)
|
|
246
|
+
hoi = getattr(self, "hoi_dong", None)
|
|
247
|
+
if hoi is not None:
|
|
248
|
+
self.hoi_dong = None # tránh gọi 2 lần
|
|
249
|
+
try:
|
|
250
|
+
hoi()
|
|
251
|
+
except Exception:
|
|
252
|
+
pass
|
|
@@ -28,9 +28,14 @@ def xuat_file_dung(duong_dan, thiet_ke, nguon_trigger):
|
|
|
28
28
|
nguon_trigger : chuỗi code trigger (file .triggers.py)
|
|
29
29
|
Trả về đường dẫn đã ghi.
|
|
30
30
|
"""
|
|
31
|
+
import copy
|
|
31
32
|
import pprint
|
|
32
33
|
|
|
33
34
|
ten = os.path.splitext(os.path.basename(duong_dan))[0]
|
|
35
|
+
# bỏ cờ studio-only (an_tam) — file chạy LUÔN hiện đầy đủ widget
|
|
36
|
+
thiet_ke = copy.deepcopy(thiet_ke)
|
|
37
|
+
for d in thiet_ke.get("components", []):
|
|
38
|
+
d.pop("an_tam", None)
|
|
34
39
|
body = (
|
|
35
40
|
f"# {'=' * 74}\n"
|
|
36
41
|
f"# {ten} — sinh bởi FlexGUI Studio\n"
|