Python tkinter GUIプログラミング アウトライン2

 今日も見に来てくださって、ありがとうございます。石川さんです。

 前回、アウトラインの案として、キャンバスの中に、create_window()でキャンバスを追加する、というやり方で実装してみましたが、Toplevel()で別ウィンドウとして実装した方がよいかも、ということで、前回のソースコードに追記してみました。

出来上がりイメージ

Outlineサンプル

 Toplevel()を継承したOutlineウィンドウを追加しました。

ソースコード

 ソースコードは以下の通りです。

import tkinter as tk

class Outline(tk.Toplevel):
    def __init__(self, master=None, cnf={}, **kw):
        super().__init__(master, cnf, **kw)
        self.title("Outline")
        self.canvas = tk.Canvas(self, background="lightblue")
        self.canvas.pack(fill=tk.BOTH,expand=True)
        master.update()
        print(master.winfo_width(),master.winfo_height())
        w, h = master.winfo_width()//5, master.winfo_height()//5
        self.geometry(str(w)+"x"+str(h))
        self.resizable(0,0)
        self.attributes("-toolwindow",1)
        self.attributes("-topmost",1)

    def get_canvas(self):
        return self.canvas

class Application(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Canvas outline sample")
        self.outline = None
        self.outline_item = None
        
        self.canvas = tk.Canvas(self, background="white")
        self.canvas.pack(fill=tk.BOTH,expand=True)
        self.canvas.bind("<1>",self.update_outline)
        self.canvas.bind("<Configure>",self.update_outline)
        
        self.focus_force()
        
        self.outline_window = Outline(master=self)

    def update_outline(self, event):
        if self.outline == None or self.outline_item == None:
            self.outline = o = tk.Canvas(self, background="lightblue")
            c = self.canvas
            width, height = c.winfo_width(), c.winfo_height()
            w, h = width//5, height//5
            x, y = width - w//2, height - h//2
            self.outline_item = c.create_window(x, y, width=w, height=h, window=o)
            return

        if event.type == tk.EventType.Configure:
            c = self.canvas
            width, height = c.winfo_width(), c.winfo_height()
            w, h = width//5, height//5
            x, y = width - w//2, height - h//2
            oi = self.outline_item
            x0, y0 = c.coords(oi)
            dx = x - x0
            dy = y - y0
            c.move(oi,dx,dy)
            c.itemconfigure(oi,width=w,height=h)
            self.outline_window.geometry(str(w)+"x"+str(h))

        elif event.type == tk.EventType.Button:
            c = self.canvas
            x, y = event.x, event.y
            c.create_rectangle(x, y, x+100, y+100)
            o = self.outline
            o.create_rectangle(x//5,y//5,(x+100)//5,(y+100)//5)
            c = self.outline_window.get_canvas()
            c.create_rectangle(x//5,y//5,(x+100)//5,(y+100)//5)
    
if __name__ == "__main__":
    application = Application()
    application.mainloop()

詳細

 3~18行目まででOutlineウィンドウを追加しました。ポイントは9行目のmaster.update()でしょうか。これを実行することで待機中のイベントが実行されて、ウィンドウのサイズが計算されます。もし実行しない場合は、master.winfo_width()master.winfo_height()が計算されていない状態、1と1になって、とっても小さいウィンドウが表示されます。ほとんど何も見えません。

 13、14行目は、それぞれ、self.resizable(0,0)でサイズの変更をできないようにして、self.attributes("-toolwindow",1)で最小化と最大化のボタンを非表示にしています。15行目のself.attributes("-topmost",1)では、ずっと画面の一番上に表示されるように設定しています。常に前面で表示されるようになります。

 57行目で、メインウィンドウの大きさが変わった時に同じようにアウトラインも大きさが変わるように動作させています。

まとめ

 浮かんだウィンドウの方が、しっくりきますね。キャンバス上の実装はそのままでは移動できませんので、移動できるという点でも優れていると思います。本体部分がちゃんと作れれば、アウトライン部分も割と簡単に実装できそうですね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。