質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1498閲覧

拡大プレビュー機能における、拡大表示部分のスクロールとカーソルの同期方法を知りたい。

samonji

総合スコア1

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/09/25 01:22

前提・実現したいこと

ECサイトで用いられているような、元画像上にあるカーソル位置周辺を隣に拡大表示させるアプリケーションを作成しています。
将来的には拡大画像に対して画像処理を行ったうえで表示させたいのですが、カーソル位置周辺をその都度クロップすると動作が重くなることが想定されるため、
あらかじめ拡大された元画像を拡大画像用キャンパスに描画しておいて、表示枠内に表示する範囲画像をカーソルの動きと同期させながらスクロールさせることで対応させたいと考えております。(下図が完成イメージ)

今のところ、

  1. 元画像上にあるカーソルの動きに合わせて周辺をクロップさせる。
  2. クロップ画像を元画像の隣に拡大画像として表示させ、カーソルの動きと同期させる。

はできたのですが、カーソルの動きと同期させながら拡大画像をスクロールさせるコードの作成方法がイメージできていません。
解決方法をご存じの方がいらっしゃれば、ぜひご教授ください。

イメージ説明

現在コード

Python3

1import tkinter as tk 2from PIL import Image, ImageTk 3from tkinter import font 4 5_squarelength = 256 6_framelength = 128 7 8class MainApplication(tk.Frame): 9 def __init__(self, master): 10 super().__init__(master) 11 self.master = master 12 self.master.geometry('1920x1080') 13 self.master.title("Image Viewer") 14 15 self.image = Image.open('任意画像') 16 self.resize_image = self.image.resize((600, 500)) 17 self.main_image = ImageTk.PhotoImage(self.resize_image) 18 19 self.create_widget() 20 21 22 def create_widget(self): 23 self.frame = tk.Frame(self.master, background='gray', width=1500, height=700) 24 self.frame.propagate(False) 25 self.frame.pack() 26 27 self.canvas1 = tk.Canvas(self.frame, width=self.resize_image.width, height=self.resize_image.height) 28 self.canvas2 = tk.Canvas(self.frame, width=_squarelength, height=_squarelength) 29 30 self.canvas1.place(x=50, y=100) 31 self.canvas2.place(x=758, y=100) 32 33 self.canvas1.create_image(0, 0, image=self.main_image, anchor=tk.NW) 34 35 canvas1にマウスが乗った場合、離れた場合のイベントをセット。 36 self.canvas1.bind('<Motion>', self.mouse_motion) 37 self.canvas1.bind('<Leave>', self.mouse_leave) 38 39 40 font = tk.font.Font(family='Arial', size=16, weight='bold') 41 image_title = tk.Label(text='元画像', bg = "gray", font=font) 42 image_title2 = tk.Label(text='拡大画像', bg = "gray", font=font) 43 44 image_title.place(x=50, y=60, anchor=tk.NW) 45 image_title2.place(x=758, y=60, anchor=tk.NW) 46 47 48 def mouse_motion(self, event): 49 マウス位置の座標を取得, 写真から切り出す座標定義 50 x = event.x 51 y = event.y 52 53 self.frame_rect(x, y) 54 self.canvas_set(x, y) 55 56 def frame_rect(self, x, y): 57 枠線描画を更新 58 self.frame_refresh() 59 self.crop_frame = (x-_framelength/2, y-_framelength/2, x+_framelength/2, y+_framelength/2) 60 self.rectframe = self.canvas1.create_rectangle(self.crop_frame, outline='#AAA', width=2, tag='rect') 61 62 def frame_refresh(self): 63 try: 64 self.canvas1.delete('rect') 65 except: 66 pass 67 68 def canvas_set(self, x, y): 69 枠線内をクロップ 70 zoom_mag = _squarelength / _framelength 71 croped = self.resize_image.crop(self.crop_frame) 72 zoom_image = croped.resize((int(croped.width*zoom_mag), int(croped.height*zoom_mag))) 73 74 ズームした画像を拡大画像canvasに入れる 75 self.image_refresh() 76 self.sub_image1 = ImageTk.PhotoImage(zoom_image) 77 self.sub_cv1 = self.canvas2.create_image(0, 0, image=self.sub_image1, anchor=tk.NW, tag='cv1') 78 79 80 def image_refresh(self): 81 try: 82 self.canvas2.delete('cv1') 83 except: 84 pass 85 86 def mouse_leave(self, event): 87 try: 88 self.canvas2.delete('cv1') 89 self.canvas1.delete('rect') 90 except: 91 pass 92 93if __name__ == '__main__': 94 root = tk.Tk() 95 app = MainApplication(master = root) 96 app.mainloop()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

同じようなトピックなので参考になるのではないでしょうか。利用ライブラリも同じtkinterです。

カーソル位置周辺をその都度クロップすると動作が重くなることが想定されるため、

これは実際にやってみると意外と許容範囲でした。
画像のサイズ・解像度にもよるのかもしれませんが。

一応、毎回クロップしない実装方法:

オリジナルサイズの画像をキャンバスに描画しておき、
表示部分を絞りスクロールさせることで対応します。

具体的には、

  • canvas.create_image でオリジナルサイズの画像を配置

 配置座標は中央指定なので、画像の大きさから計算します。

  • キャンバスのサイズ自体は表示部分の大きさにして、

 canvas.config(scrollregion=canvas.bbox("all")) でスクロール領域を指定
※ キャンバスには画像が一枚のみを想定。

  • canvas の xview_moveto, yview_moveto でスクロール

 引数に与える値は、0.0 ~ 1.0 の範囲なので、
キャンバスのサイズとマウスの座標からスクロール位置を計算します。


以前の回答のときに書いたサンプルコード
投稿してなかったようなので追記します。

プレビューに縮小画像は使ってませんが、
クロップの代替としてスクロールで対応する方法。

  • ※ repl.it サイト上で実行できるようには構成してません。
  • 起動時に test.jpg を読み込みます。適当な画像を用意してください。

投稿2020/09/25 01:44

編集2020/09/25 02:07
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

samonji

2020/09/25 07:31

ご回答いただきありがとうございます。 すでに似た質問があったのですね・・・。非常に参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問