Tkinterで時刻入力専用画面を作成します。
Python3 Tkinter 時間入力やテンキーなどの専用画面をウィジェットのすぐ下に表示したい
の回答を参考に、表示・非表示を切り替えるように作成しました。
仕様として
Treeviewレコードの時刻データ列をダブルクリックすると時刻入力画面が出て、時刻の変更が可能というものです。
時刻入力画面の左上の座標が、該当時刻列の左下。
ただし、①ディスプレイ上より右にはみ出る場合は、入力画面の左端を該当時刻列の右端に揃える。
②ディスプレイ上より下にはみ出る場合(タスクバーは考慮しない)は、入力画面の下端を該当時刻列の上端に揃える。
というふうにしたいです。
作ってみたのですが、
①は、惜しいような気もしますが目標より若干右よりなきがします。
②も目標より下にずれている感じです。
単に補正が必要なのか計算が間違っているのか分かりません。
分かる方教えていただけると幸いです。
(座標計算はpopup_time_input.pyのTimeInputクラスのcall_time_input関数でやってます)
また、他に改善点あればそちらもご指摘お願いします。
目標位置と実際の位置の差
黄:目標位置
緑:実際のウィンドウの端の位置
Python
1# main.py <- entry point 2 3import tkinter as tk 4from tkinter import ttk 5 6import popup_time_input 7 8class App(tk.Frame): 9 10 def __init__(self, master): 11 super().__init__(master) # tk.Frame(root) に相当 12 self.time_input = popup_time_input.TimeInput() 13 self.create_widgets() 14 15 16 def create_widgets(self): 17 self.tree = ttk.Treeview(root, selectmode="browse") 18 self.tree.pack() 19 20 # headings 21 columns = 2 22 self.tree["columns"] = tuple(range(columns)) 23 self.tree["show"] = "headings" 24 self.tree.heading(0, text="No.") 25 self.tree.heading(1, text="Time[hh:mm]") 26 27 # data 28 self.tree.insert("", "end", values=("1", "00:00")) 29 self.tree.insert("", "end", values=("2", "01:11")) 30 self.tree.insert("", "end", values=("3", "02:22")) 31 self.tree.insert("", "end", values=("4", "03:33")) 32 self.tree.insert("", "end", values=("5", "04:44")) 33 34 self.tree.bind("<Double-Button-1>", self.on_tree) 35 36 37 def on_tree(self, e): 38 tree = e.widget 39 selected = tree.selection() # 選択行 40 clickarea = tree.identify_region(e.x, e.y) # "heading" or "cell" 41 42 if len(selected) == 1 and clickarea == "cell": 43 # 列取得 44 x = tree.winfo_pointerx() - tree.winfo_rootx() 45 select_column_str = tree.identify_column(x) 46 select_column_int = int(select_column_str[1:]) 47 48 # 時刻列ダブルクリックで専用入力画面表示 49 if select_column_int == 2: 50 self.time_input.call_time_input(tree, select_column_int) 51 52 53if __name__ == "__main__": 54 root = tk.Tk() 55 app = App(root) 56 app.mainloop()
Python
1#popup_time_input.py 2 3import tkinter as tk 4from tkinter import ttk 5 6class TimeInput: 7 8 def __init__(self): 9 self.width = 400 10 self.height = 300 11 self.tree = None 12 self.tree_iid = None 13 self.select_column = None 14 15 self.input_window = tk.Toplevel() 16 self.input_window.withdraw() 17 self.input_window.title("InputWindow") 18 self.create_widgets() 19 self.input_window.protocol("WM_DELETE_WINDOW", lambda:None) 20 21 22 def create_widgets(self): 23 self.input_window.rowconfigure((0,1,2,3), weight=1) 24 self.input_window.columnconfigure((0,2), weight=1) 25 26 self.hour = tk.StringVar() 27 hour_entry = ttk.Entry(self.input_window, textvariable=self.hour) 28 hour_entry.grid(row=0, column=0) 29 colon = ttk.Label(self.input_window, text=":") 30 colon.grid(row=0, column=1) 31 self.minu = tk.StringVar() 32 minu_entry = ttk.Entry(self.input_window, textvariable=self.minu) 33 minu_entry.grid(row=0, column=2) 34 35 hourplus = ttk.Button(self.input_window, text="+", command=self.on_hourplus) 36 hourplus.grid(row=1, column=0, sticky="nsew") 37 minuplus = ttk.Button(self.input_window, text="+", command=self.on_minuplus) 38 minuplus.grid(row=1, column=2, sticky="nsew") 39 40 hourminus = ttk.Button(self.input_window, text="-", command=self.on_hourminus) 41 hourminus.grid(row=2, column=0, sticky="nsew") 42 minuminus = ttk.Button(self.input_window, text="-", command=self.on_minuminus) 43 minuminus.grid(row=2, column=2, sticky="nsew") 44 45 ok = ttk.Button(self.input_window, text="OK", command=self.on_ok) 46 ok.grid(row=3, column=0) 47 48 cancel = ttk.Button(self.input_window, text="cancel", command=self.on_cancel) 49 cancel.grid(row=3, column=2) 50 51 52 def on_hourplus(self): 53 # hour + 54 txt = self.hour.get() 55 try: 56 if int(txt) < 23: 57 txt = str((int(txt) + 1)).zfill(2) 58 else: 59 txt = "00" 60 self.hour.set(txt) 61 except: 62 pass 63 64 65 def on_minuplus(self): 66 # minutes + 67 txt = self.minu.get() 68 try: 69 if int(txt) < 59: 70 txt = str((int(txt) + 1)).zfill(2) 71 else: 72 txt = "00" 73 self.minu.set(txt) 74 except: 75 pass 76 77 78 def on_hourminus(self): 79 # hour - - 80 txt = self.hour.get() 81 try: 82 if int(txt) > 0: 83 txt = str((int(txt) - 1)).zfill(2) 84 else: 85 txt = "23" 86 self.hour.set(txt) 87 except: 88 pass 89 90 91 def on_minuminus(self): 92 # minutes - 93 txt = self.minu.get() 94 try: 95 if int(txt) > 0: 96 txt = str((int(txt) - 1)).zfill(2) 97 else: 98 txt = "59" 99 self.minu.set(txt) 100 except: 101 pass 102 103 104 def on_ok(self): 105 children = self.tree.get_children() 106 new_data = self.hour.get() + ":" + self.minu.get() 107 self.tree.set(self.tree_iid, self.select_column - 1, new_data) 108 self.input_window.grab_release() 109 self.input_window.withdraw() 110 111 112 def on_cancel(self): 113 self.input_window.grab_release() 114 self.input_window.withdraw() 115 116 117 def call_time_input(self, tree, select_column): 118 # 表示用関数(外部から呼ぶ) 119 self.tree = tree 120 self.select_column = select_column 121 122 is_select = tree.selection() 123 124 if is_select: 125 self.tree_iid = is_select[0] 126 value = tree.item(self.tree_iid)["values"][select_column - 1] 127 print("value: {}".format(value)) 128 self.hour.set(value[0:2]) 129 self.minu.set(value[3:5]) 130 131 # Treeview該当レコードの左下にウィンドウの左上を設定 132 x, y, w, h = tree.bbox(self.tree_iid, select_column - 1) 133 x += tree.winfo_rootx() 134 y += tree.winfo_rooty() + h 135 136 print(y) 137 print(h) 138 print(self.input_window.winfo_screenheight()) 139 print(self.input_window.winfo_height()) 140 141 # はみ出すようなら、Treeview該当レコードの右上にウィンドウの右下を設定 142 limitx = self.input_window.winfo_screenwidth() - self.input_window.winfo_width() 143 limity = self.input_window.winfo_screenheight() - self.input_window.winfo_height() 144 145 if x >= limitx: 146 x = x - self.input_window.winfo_width() 147 if y >= limity: 148 y = y - h - self.input_window.winfo_height() 149 150 geometry = f"{self.width}x{self.height}+{x}+{y}" 151 print("geometry: {}".format(geometry)) 152 self.input_window.geometry(geometry) 153 154 self.input_window.deiconify() 155 self.input_window.grab_set()
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/04/12 00:31 編集
2022/04/12 03:36
2022/04/12 04:21 編集
2022/04/13 07:45 編集
2022/04/13 08:42
2022/04/13 10:39 編集
2022/04/13 11:02
2022/04/14 01:49 編集
2022/04/14 07:19 編集