ikkVisualKit 0.0.0__py3-none-any.whl

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.
@@ -0,0 +1,102 @@
1
+ # DialogOk.py
2
+ import customtkinter as tk
3
+ from .CdialogBase import CdialogBase, CdialogResult, CdialogIcon
4
+
5
+ class CdialogOk(CdialogBase):
6
+
7
+ def __init__(self, parent, title="OK", message="Message", icon=None,
8
+ size=(700, 400), msg_font_size=18, msg_wraplength=420,
9
+ btn_width=150, btn_height=50, btn_font_size=14, blink=False, blink_speed=500):
10
+ self._message = message
11
+ self._icon = icon
12
+ self._msg_font_size = msg_font_size
13
+ self._msg_wraplength = msg_wraplength
14
+ self._btn_width = btn_width
15
+ self._btn_height = btn_height
16
+ self._btn_font_size = btn_font_size
17
+ self._blink = blink
18
+ self._blink_speed = blink_speed
19
+ self._msg_label = None
20
+ self._blink_state = True
21
+ super().__init__(parent, title=title, size=size)
22
+
23
+ def _build(self, root):
24
+ root.configure(padx=20, pady=20)
25
+
26
+ container = tk.CTkFrame(root)
27
+ container.pack(expand=True)
28
+
29
+ if self._icon:
30
+ icon_label = tk.CTkLabel(container, bitmap=self._icon.value)
31
+ icon_label.pack(side="left", padx=(0, 15))
32
+ #表示するメッセージ
33
+ msg = tk.CTkLabel(
34
+ container,
35
+ text=self._message,
36
+ font=("Meiryo", self._msg_font_size),
37
+ wraplength=self._msg_wraplength,
38
+ justify="left"
39
+ )
40
+ msg.pack(side="left")
41
+ self._msg_label = msg
42
+
43
+ # 点滅機能が有効な場合
44
+ if self._blink:
45
+ self._start_blink()
46
+ #OKボタン
47
+ btn = tk.CTkButton(
48
+ root,
49
+ text="OK",
50
+ width=self._btn_width,
51
+ height=self._btn_height,
52
+ font=("Meiryo", self._btn_font_size),
53
+ command=lambda: self._action_handle(CdialogResult.OK)
54
+ )
55
+ btn.pack(pady=15)
56
+
57
+ btn.focus_set()
58
+
59
+ root.bind("<Return>", lambda e: self._action_handle(CdialogResult.OK))
60
+ root.bind("<Escape>", lambda e: self._action_handle(CdialogResult.OK))
61
+
62
+ # ---------------------------------
63
+ def _start_blink(self):
64
+ """メッセージラベルを点滅させる"""
65
+ if self._msg_label:
66
+ self._toggle_blink()
67
+
68
+ def _toggle_blink(self):
69
+ """点滅のトグル"""
70
+ if self._msg_label:
71
+ if self._blink_state:
72
+ self._msg_label.configure(text_color="gray")
73
+ else:
74
+ self._msg_label.configure(text_color="white")
75
+ self._blink_state = not self._blink_state
76
+ self._msg_label.after(self._blink_speed, self._toggle_blink)
77
+ #####################################################################
78
+ #
79
+ #####################################################################
80
+ if __name__ == "__main__":
81
+ #TKのルート
82
+ root = tk.CTk()
83
+ #
84
+ def test_ok():
85
+ dlg = CdialogOk(root,
86
+ message="メッセージ",
87
+ size=(800, 400), # ダイアログのサイズ
88
+ msg_font_size=30, # メッセージのフォントサイズ
89
+ msg_wraplength=620, # メッセージの折り返し幅
90
+ btn_width=300, # ボタンの幅
91
+ btn_height=120, # ボタンの高さ
92
+ btn_font_size=30, # ボタンのフォントサイズ
93
+ blink=True, # 点滅有効
94
+ blink_speed=500) # 点滅速度(ミリ秒)
95
+ # dlg = CdialogOk(root, message="処理が完了しました。", icon=DialogIcon.INFO)
96
+ result = dlg.show()
97
+ print(result)
98
+
99
+ root.geometry("800x400")
100
+ root.title("OK Dialog テスト")
101
+ tk.CTkButton(root, text="ここを押してダイアログを表示", command=test_ok).pack(pady=20)
102
+ root.mainloop()
@@ -0,0 +1,91 @@
1
+ # DialogYesNo.py
2
+ import customtkinter as tk
3
+ from .CdialogBase import CdialogBase, CdialogResult
4
+
5
+ class CdialogYesNo(CdialogBase):
6
+
7
+ def __init__(self, parent, title="Confirm", message="実行しますか?",
8
+ size=(600, 300), msg_font_size=18, msg_wraplength=420,
9
+ btn_width=100, btn_height=50, btn_font_size=14, default_button="YES"):
10
+ self._message = message
11
+ self._msg_font_size = msg_font_size
12
+ self._msg_wraplength = msg_wraplength
13
+ self._btn_width = btn_width
14
+ self._btn_height = btn_height
15
+ self._btn_font_size = btn_font_size
16
+ self._default_button = default_button # "YES" or "NO"
17
+ self._yes_btn = None
18
+ self._no_btn = None
19
+ super().__init__(parent, title=title, size=size)
20
+
21
+ def _build(self, root):
22
+ root.configure(padx=20, pady=20)
23
+
24
+ label = tk.CTkLabel(
25
+ root,
26
+ text=self._message,
27
+ font=("Meiryo", self._msg_font_size),
28
+ wraplength=self._msg_wraplength,
29
+ justify="center"
30
+ )
31
+ label.pack(pady=10)
32
+
33
+ frame = tk.CTkFrame(root)
34
+ frame.pack(pady=10)
35
+
36
+ yes_btn = tk.CTkButton(
37
+ frame,
38
+ text="YES",
39
+ width=self._btn_width,
40
+ height=self._btn_height,
41
+ font=("Meiryo", self._btn_font_size),
42
+ command=lambda: self._action_handle(CdialogResult.YES)
43
+ )
44
+ yes_btn.pack(side="left", padx=10)
45
+
46
+ no_btn = tk.CTkButton(
47
+ frame,
48
+ text="NO",
49
+ width=self._btn_width,
50
+ height=self._btn_height,
51
+ font=("Meiryo", self._btn_font_size),
52
+ command=lambda: self._action_handle(CdialogResult.NO)
53
+ )
54
+ no_btn.pack(side="right", padx=10)
55
+
56
+ self._yes_btn = yes_btn
57
+ self._no_btn = no_btn
58
+
59
+ # デフォルトボタンにフォーカスを設定
60
+ if self._default_button == "NO":
61
+ no_btn.focus_set()
62
+ else:
63
+ yes_btn.focus_set()
64
+
65
+ root.bind("<Return>", lambda e: self._action_handle(CdialogResult.YES))
66
+ root.bind("<Escape>", lambda e: self._action_handle(CdialogResult.NO))
67
+ #####################################################################
68
+ #サンプル
69
+ #####################################################################
70
+ if __name__ == "__main__":
71
+ root = tk.CTk()
72
+ root.geometry("800x400")
73
+ root.title("YES/NO Dialog テスト")
74
+
75
+ def test_yesno():
76
+ dlg = CdialogYesNo(root,
77
+ message="削除しますか?",
78
+ size=(700, 400), # ダイアログのサイズ
79
+ msg_font_size=24, # メッセージのフォントサイズ
80
+ msg_wraplength=550, # メッセージの折り返し幅
81
+ btn_width=150, # ボタンの幅
82
+ btn_height=60, # ボタンの高さ
83
+ btn_font_size=16, # ボタンのフォントサイズ
84
+ default_button="NO") # デフォルト選択("YES" or "NO")
85
+ result = dlg.show()
86
+ print(result)
87
+
88
+
89
+ tk.CTkButton(root, text="YES/NO", command=test_yesno).pack(pady=20)
90
+
91
+ root.mainloop()
@@ -0,0 +1,97 @@
1
+ # DialogBase.py
2
+ from enum import Enum
3
+ import tkinter as tk
4
+
5
+
6
+ class DialogResult(Enum):
7
+ NONE = 0
8
+ OK = 1
9
+ CANCEL = 2
10
+ CLOSED = 3
11
+ YES = 4
12
+ NO = 5
13
+
14
+
15
+ class DialogIcon(Enum):
16
+ INFO = "info"
17
+ WARNING = "warning"
18
+ ERROR = "error"
19
+
20
+ class DialogBase:
21
+ """
22
+ Toplevel ベースのモーダルダイアログ基底クラス
23
+ """
24
+
25
+ def __init__(self, parent: tk.Tk, title="Dialog", size=(400, 200)):
26
+ self._parent = parent
27
+ self._result = DialogResult.NONE
28
+
29
+ self._tkRoot = tk.Toplevel(parent)
30
+ self._tkRoot.title(title)
31
+ self._tkRoot.geometry(f"{size[0]}x{size[1]}")
32
+ self._tkRoot.protocol("WM_DELETE_WINDOW", self._on_window_close)
33
+
34
+ self._tkRoot.transient(parent)
35
+ self._tkRoot.resizable(False, False)
36
+ self._tkRoot.withdraw()
37
+
38
+ self._build(self._tkRoot)
39
+
40
+ # ---------------------------------
41
+ def _build(self, root: tk.Toplevel):
42
+ pass
43
+
44
+ # ---------------------------------
45
+ def _on_window_close(self):
46
+ self._result = DialogResult.CLOSED
47
+ self._tkRoot.destroy()
48
+
49
+ # ---------------------------------
50
+ def _action_handle(self, result: DialogResult):
51
+ self._result = result
52
+ self._tkRoot.destroy()
53
+
54
+ # ---------------------------------
55
+ def show(self) -> DialogResult:
56
+ self._result = DialogResult.NONE
57
+
58
+ self._center_to_parent()
59
+
60
+ self._tkRoot.deiconify()
61
+ self._tkRoot.lift()
62
+ self._tkRoot.grab_set()
63
+ self._tkRoot.focus_set()
64
+ self._parent.wait_window(self._tkRoot)
65
+
66
+ return self._result
67
+
68
+ # ---------------------------------
69
+ def _center_to_parent(self):
70
+ self._parent.update_idletasks()
71
+
72
+ px = self._parent.winfo_x()
73
+ py = self._parent.winfo_y()
74
+ pw = self._parent.winfo_width()
75
+ ph = self._parent.winfo_height()
76
+
77
+ w = self._tkRoot.winfo_reqwidth()
78
+ h = self._tkRoot.winfo_reqheight()
79
+
80
+ x = px + (pw - w) // 2
81
+ y = py + (ph - h) // 2
82
+
83
+ self._tkRoot.geometry(f"+{x}+{y}")
84
+
85
+ #####################################################################
86
+ # 使用例(単体テスト)
87
+ #####################################################################
88
+ if __name__ == "__main__":
89
+ root = tk.Tk()
90
+ root.withdraw()
91
+
92
+
93
+ dlg = DialogBase(root, title="Dialog Example", size=(400, 200))
94
+ result = dlg.show()
95
+ print(f"Dialog result: {result}")
96
+
97
+ root.destroy()
@@ -0,0 +1,59 @@
1
+ # DialogOk.py
2
+ import tkinter as tk
3
+ from .DialogBase import DialogBase, DialogResult, DialogIcon
4
+
5
+ class DialogOk(DialogBase):
6
+
7
+ def __init__(self, parent, title="OK", message="Message", icon=None):
8
+ self._message = message
9
+ self._icon = icon
10
+ super().__init__(parent, title=title, size=(420, 200))
11
+
12
+ def _build(self, root):
13
+ root.configure(padx=20, pady=20)
14
+
15
+ container = tk.Frame(root)
16
+ container.pack(expand=True)
17
+
18
+ if self._icon:
19
+ icon_label = tk.Label(container, bitmap=self._icon.value)
20
+ icon_label.pack(side="left", padx=(0, 15))
21
+
22
+ msg = tk.Label(
23
+ container,
24
+ text=self._message,
25
+ font=("Meiryo", 14),
26
+ wraplength=320,
27
+ justify="left"
28
+ )
29
+ msg.pack(side="left")
30
+
31
+ btn = tk.Button(
32
+ root,
33
+ text="OK",
34
+ width=10,
35
+ command=lambda: self._action_handle(DialogResult.OK)
36
+ )
37
+ btn.pack(pady=15)
38
+
39
+ btn.focus_set()
40
+
41
+ root.bind("<Return>", lambda e: self._action_handle(DialogResult.OK))
42
+ root.bind("<Escape>", lambda e: self._action_handle(DialogResult.OK))
43
+ #####################################################################
44
+ #
45
+ #####################################################################
46
+ if __name__ == "__main__":
47
+ root = tk.Tk()
48
+ root.geometry("500x300")
49
+ root.title("Dialog Test")
50
+
51
+
52
+ def test_ok():
53
+ dlg = DialogOk(root, message="処理が完了しました。", icon=DialogIcon.INFO)
54
+ result = dlg.show()
55
+ print(result)
56
+
57
+ tk.Button(root, text="OK", command=test_ok).pack(pady=20)
58
+
59
+ root.mainloop()
@@ -0,0 +1,110 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+
4
+ from .DialogBase import DialogBase, DialogResult
5
+
6
+
7
+ class DialogSelectReaderPort(DialogBase):
8
+ def __init__(self, parent, candidates, title="バーコードリーダー選択", message: str | None = None):
9
+ self._candidates = candidates
10
+ self._selection = None
11
+ self._message = message or "keyword に一致する機器が見つかりませんでした。\n同種の機器が接続されている場合は、使用する COM ポートを選択してください。"
12
+ super().__init__(parent, title=title, size=(860, 420))
13
+
14
+ def _build(self, root):
15
+ root.configure(padx=16, pady=16)
16
+
17
+ tk.Label(
18
+ root,
19
+ text=self._message,
20
+ font=("Meiryo", 11),
21
+ justify="left",
22
+ anchor="w",
23
+ ).pack(fill="x", pady=(0, 10))
24
+
25
+ list_frame = ttk.Frame(root)
26
+ list_frame.pack(fill="both", expand=True)
27
+
28
+ columns = ("port", "description", "vid_pid", "serial", "manufacturer")
29
+ tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=9, selectmode="browse")
30
+ tree.heading("port", text="COM")
31
+ tree.heading("description", text="説明")
32
+ tree.heading("vid_pid", text="VID/PID")
33
+ tree.heading("serial", text="Serial")
34
+ tree.heading("manufacturer", text="Manufacturer")
35
+ tree.column("port", width=90, anchor="center")
36
+ tree.column("description", width=320, anchor="w")
37
+ tree.column("vid_pid", width=120, anchor="center")
38
+ tree.column("serial", width=150, anchor="w")
39
+ tree.column("manufacturer", width=130, anchor="w")
40
+
41
+ scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=tree.yview)
42
+ tree.configure(yscrollcommand=scrollbar.set)
43
+ tree.pack(side="left", fill="both", expand=True)
44
+ scrollbar.pack(side="left", fill="y", padx=(8, 0))
45
+
46
+ for index, candidate in enumerate(self._candidates):
47
+ vid = candidate.get("vid", "")
48
+ pid = candidate.get("pid", "")
49
+ vid_pid = f"{vid}/{pid}" if vid and pid else vid or pid
50
+ tree.insert(
51
+ "",
52
+ "end",
53
+ iid=str(index),
54
+ values=(
55
+ candidate.get("port", ""),
56
+ candidate.get("description", ""),
57
+ vid_pid,
58
+ candidate.get("serial_number", ""),
59
+ candidate.get("manufacturer", ""),
60
+ ),
61
+ )
62
+
63
+ if self._candidates:
64
+ tree.selection_set("0")
65
+ tree.focus("0")
66
+ self._tree = tree
67
+
68
+ button_frame = ttk.Frame(root)
69
+ button_frame.pack(fill="x", pady=(14, 0), side="bottom")
70
+
71
+ ttk.Button(
72
+ button_frame,
73
+ text="今回だけ接続",
74
+ command=lambda: self._select(False),
75
+ ).pack(side="left")
76
+ ttk.Button(
77
+ button_frame,
78
+ text="今後も優先",
79
+ command=lambda: self._select(True),
80
+ ).pack(side="left", padx=(8, 0))
81
+ ttk.Button(
82
+ button_frame,
83
+ text="キャンセル",
84
+ command=lambda: self._action_handle(DialogResult.CANCEL),
85
+ ).pack(side="right")
86
+
87
+ root.bind("<Escape>", lambda _event: self._action_handle(DialogResult.CANCEL))
88
+ root.bind("<Return>", lambda _event: self._select(False))
89
+ tree.bind("<Double-1>", lambda _event: self._select(False))
90
+
91
+ def _get_selected_candidate(self):
92
+ selection = self._tree.selection()
93
+ if not selection:
94
+ return None
95
+ return self._candidates[int(selection[0])]
96
+
97
+ def _select(self, remember: bool) -> None:
98
+ candidate = self._get_selected_candidate()
99
+ if candidate is None:
100
+ return
101
+ self._selection = {
102
+ "port": candidate.get("port", ""),
103
+ "remember": remember,
104
+ "candidate": candidate,
105
+ }
106
+ self._action_handle(DialogResult.OK)
107
+
108
+ def show_selection(self):
109
+ self.show()
110
+ return self._selection
@@ -0,0 +1,62 @@
1
+ # DialogYesNo.py
2
+ import tkinter as tk
3
+ from .DialogBase import DialogBase, DialogResult
4
+
5
+ class DialogYesNo(DialogBase):
6
+
7
+ def __init__(self, parent, title="Confirm", message="実行しますか?"):
8
+ self._message = message
9
+ super().__init__(parent, title=title, size=(420, 220))
10
+
11
+ def _build(self, root):
12
+ root.configure(padx=20, pady=20)
13
+
14
+ label = tk.Label(
15
+ root,
16
+ text=self._message,
17
+ font=("Meiryo", 14),
18
+ wraplength=360,
19
+ justify="center"
20
+ )
21
+ label.pack(pady=10)
22
+
23
+ frame = tk.Frame(root)
24
+ frame.pack(pady=10)
25
+
26
+ yes_btn = tk.Button(
27
+ frame,
28
+ text="YES",
29
+ width=8,
30
+ command=lambda: self._action_handle(DialogResult.YES)
31
+ )
32
+ yes_btn.pack(side="left", padx=10)
33
+
34
+ no_btn = tk.Button(
35
+ frame,
36
+ text="NO",
37
+ width=8,
38
+ command=lambda: self._action_handle(DialogResult.NO)
39
+ )
40
+ no_btn.pack(side="right", padx=10)
41
+
42
+ yes_btn.focus_set()
43
+
44
+ root.bind("<Return>", lambda e: self._action_handle(DialogResult.YES))
45
+ root.bind("<Escape>", lambda e: self._action_handle(DialogResult.NO))
46
+ #####################################################################
47
+ #サンプル
48
+ #####################################################################
49
+ if __name__ == "__main__":
50
+ root = tk.Tk()
51
+ root.geometry("500x300")
52
+ root.title("Dialog Test")
53
+
54
+ def test_yesno():
55
+ dlg = DialogYesNo(root, message="削除しますか?")
56
+ result = dlg.show()
57
+ print(result)
58
+
59
+
60
+ tk.Button(root, text="YES/NO", command=test_yesno).pack(pady=20)
61
+
62
+ root.mainloop()
@@ -0,0 +1,21 @@
1
+ from .DialogBase import DialogBase, DialogResult, DialogIcon
2
+ from .DialogOk import DialogOk
3
+ from .DialogYesNo import DialogYesNo
4
+ from .DialogSelectReaderPort import DialogSelectReaderPort
5
+ from .CdialogBase import CdialogBase, CdialogResult, CdialogIcon
6
+ from .CdialogOk import CdialogOk
7
+ from .CdialogYesNo import CdialogYesNo
8
+
9
+ __all__ = [
10
+ "DialogBase",
11
+ "DialogResult",
12
+ "DialogIcon",
13
+ "DialogOk",
14
+ "DialogYesNo",
15
+ "DialogSelectReaderPort",
16
+ "CdialogBase",
17
+ "CdialogResult",
18
+ "CdialogIcon",
19
+ "CdialogOk",
20
+ "CdialogYesNo"
21
+ ]