diff --git a/waypoint_manager/scripts/devel_GUI.py b/waypoint_manager/scripts/devel_GUI.py index b964bca..b721f99 100755 --- a/waypoint_manager/scripts/devel_GUI.py +++ b/waypoint_manager/scripts/devel_GUI.py @@ -1,15 +1,125 @@ -import rospy +#import rospy import tkinter as tk +import numpy as np +import ruamel.yaml +from PIL import Image, ImageTk +from pathlib import Path + +#===== Applicationクラスの定義 tk.Frameクラスを継承 =====# class Application(tk.Frame): + + #--- コンストラクタ --- + # プログラムを実行したときに最初にすべき処理を全て記述する + def __init__(self, master): + super().__init__(master) # スーパークラスのコンストラクタを実行 + self.master.title("Waypoints Manager") + + ## 画面上のメニューを作成 + self.menu_bar = tk.Menu(self) # メニューバーを配置 + self.file_menu = tk.Menu(self.menu_bar, tearoff=tk.OFF) # バーに追加するメニューを作成 + self.menu_bar.add_cascade(label="File", menu=self.file_menu) # Fileメニューとしてバーに追加 + self.file_menu.add_command(label="Save", command=self.menu_save_clicked, accelerator="Ctrl+S") # FileメニューにSaveコマンドを追加 + self.file_menu.add_command(label="Save As", command=self.menu_saveas_clicked, accelerator="Ctrl+Shift+S") # 同様にSave Asコマンドを追加 + self.bind_all("", self.menu_save_clicked) #キーボードショートカットを設定 + self.bind_all("", self.menu_saveas_clicked) + self.master.config(menu=self.menu_bar) # 大元に作成したメニューバーを設定 + self.update() # 情報を更新 + + ## map.pgm と map.yaml の読み込み + map_path = '..\..\waypoint_nav\maps\map' # .pgmと.yamlの手前までのパス + self.__map_img_pil = Image.open(Path(map_path+'.pgm')) # .pgmをplillowで読み込む オリジナル画像を保持するため再代入禁止 + with open(map_path+'.yaml') as file: # .yamlを読み込む  + self.__map_yaml = ruamel.yaml.YAML().load(file) # こちらも再代入禁止 + + ## canvasを配置し画像を描画 + self.canvas = tk.Canvas(self.master, background="#008B8B") # 画像を描画するキャンバス + self.canvas.pack(expand=True, fill=tk.BOTH) # キャンバスを配置 + self.update() # 情報の更新をする(canvasのサイズなどの情報が更新される) + + ## 画像をキャンバスのサイズにフィッティングして描画 + self.canv_w = self.canvas.winfo_width() # canvasの幅を取得 + self.canv_h = self.canvas.winfo_height() # canvasの高さを取得 + if (self.canv_w / self.canv_h) > (self.__map_img_pil.width / self.__map_img_pil.height): + # キャンバスの方が横長 画像をキャンバスの縦に合わせてリサイズ + scale = self.canv_h / self.__map_img_pil.height + img_w = int(self.__map_img_pil.width * scale) + img = self.__map_img_pil.resize((img_w, self.canv_h), resample=Image.Resampling.NEAREST) + else: + # キャンバスの方が縦長 画像をキャンバスの横に合わせてリサイズ + scale = self.canv_w / self.__map_img_pil.width + img_h = int(self.__map_img_pil.height * scale) + img = self.__map_img_pil.resize((self.canv_w, img_h), resample=Image.Resampling.NEAREST) + self.draw_img_tk = ImageTk.PhotoImage(img) # pilフォーマットの画像をtkinterのフォーマットに変換 + self.canvas.create_image(self.canv_w/2, self.canv_h/2, image=self.draw_img_tk) # 画像の描画 + self.update() + + ## 右クリックしたときに表示するポップアップメニューを作成 + self.popup_menu = tk.Menu(self, tearoff=tk.OFF) + self.popup_menu.add_command(label="add waypoint", command=self.add_waypoint) + # 右クリックしたときの座標を保持する変数 + self.right_click_coord = None + + ## マウスイベントを設定 + self.master.bind("", self.mouse_wheel) + self.master.bind("", self.left_click_move) + self.master.bind("", self.right_click) + return + + + + #--- Fileメニューの"Save"がクリックされたときに実行されるコールバック関数 --- + def menu_save_clicked(self, event=None): + print("Clicked \"Save\"") + return - # Constructer - def __init__(self, master=None): - super().__init__(master) + #--- Fileメニューの"Save As"がクリックされたときに実行されるコールバック関数 --- + def menu_saveas_clicked(self, event=None): + print("Clicked \"Save As\"") + return + + + + #--- マウスを左クリックしながらドラッグしたときのコールバック関数 --- + def left_click_move(self, event): + print("x=" + str(event.x) + " y=" + str(event.y)) + return + + + + #--- 右クリックしたときのコールバック関数 --- + def right_click(self, event): + self.popup_menu.post(event.x_root, event.y_root) + self.right_click_coord = [event.x, event.y] + return + + + + #--- マウスホイールを回転したとき(タッチパッドをドラッグしたとき)のコールバック関数 --- + def mouse_wheel(self, event): + if event.delta > 0: + # 上に回転(タッチパッドなら下にドラッグ)=> 拡大 + print(event.x, event.y, event.delta) + else: + # 下に回転(タッチパッドなら上にドラッグ)=> 縮小 + print(event.x, event.y, event.delta) + # 回転の向きに対するevent.deltaの正負はプラットフォームにより異なる可能性あり + return + + + + #--- 右クリックしてポップアップメニューのadd waypointをクリックしたときのコールバック関数 --- + def add_waypoint(self): + print("Clicked \"add waypoint\"") + + + +#===== メイン処理 プログラムはここから実行される =====# if __name__ == "__main__": - #rospy.init_node("manager_GUI") # maybe no mean - root = tk.Tk() - app = Application(master = root) + #rospy.init_node("manager_GUI") + root = tk.Tk() # 大元になるウィンドウ + root.state("zoomed") # ウィンドウを最大化 + app = Application(master=root) # tk.Frameを継承したApplicationクラスのインスタンス app.mainloop()