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

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

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

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

Q&A

解決済

1回答

3568閲覧

wxPythonを使ってスクロールと拡大縮小できるFrameを実装したいが画面が更新されない。

kagaribisou

総合スコア17

Python

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

0グッド

0クリップ

投稿2020/07/28 15:47

前提・実現したいこと

wxpython を使って、スクロール機能と子のPanelを拡大縮小できるFrameを実装したい。

発生している問題・エラーメッセージ

スクロールはできるが、拡大縮小した時に画面の更新ができない。

該当のソースコード

Python

1from wx import App, Frame, Panel, BoxSizer, Button 2from wx import ID_ANY, DefaultPosition, DefaultSize, DEFAULT_FRAME_STYLE, FrameNameStr, VERTICAL, EXPAND 3from wx import EVT_BUTTON 4from wx.lib.scrolledpanel import ScrolledPanel 5 6 7class ImageViewer(Frame): 8 def __init__(self, parent=None, id=ID_ANY, title="", pos=DefaultPosition, size=DefaultSize, style=DEFAULT_FRAME_STYLE, name=FrameNameStr): 9 super().__init__(parent=parent, id=id, title=title, pos=pos, size=size, style=style, name=name) 10 sizer = BoxSizer(VERTICAL) 11 self.SetSizer(sizer) 12 self.SetAutoLayout(True) 13 14 self.scroll_panel = ScrolledPanel(self) 15 self.scroll_panel.SetupScrolling() 16 17 self.img_sizer = BoxSizer() 18 self.scroll_panel.SetSizer(self.img_sizer) 19 20 self.img = Panel(self.scroll_panel, size=(20, 20)) 21 self.img_sizer.Add(self.img) 22 self.img.SetBackgroundColour('#0F0') 23 24 self.btn_panel = Panel(self) 25 btn_sizer = BoxSizer() 26 self.btn_panel.SetSizer(btn_sizer) 27 sizer.Add(self.scroll_panel, 1, EXPAND) 28 sizer.Add(self.btn_panel, 0, EXPAND) 29 self.SetAutoLayout(True) 30 31 zoom_in_btn = Button(self.btn_panel, label='+', size=(20, 20)) 32 zoom_in_btn.Bind(EVT_BUTTON, self.zoom_in) 33 btn_sizer.Add(zoom_in_btn) 34 35 zoom_out_btn = Button(self.btn_panel, label='-', size=(20, 20)) 36 zoom_out_btn.Bind(EVT_BUTTON, self.zoom_out) 37 btn_sizer.Add(zoom_out_btn) 38 39 self.Show() 40 41 def zoom_in(self, event): 42 self.img_sizer.Clear() 43 x, y = self.img.GetSize() 44 x *= 2 45 y *= 2 46 self.img = Panel(self.scroll_panel, size=(x, y)) 47 self.img_sizer.Add(self.img, 0) 48 self.img.SetBackgroundColour('#0F0') 49 50 self.scroll_panel.SetupScrolling() 51 self.scroll_panel.Refresh() 52 53 def zoom_out(self, event): 54 self.img_sizer.Clear() 55 x, y = self.img.GetSize() 56 x //= 2 57 y //= 2 58 self.img = Panel(self.scroll_panel, size=(x, y)) 59 self.img_sizer.Add(self.img, 0) 60 self.img.SetBackgroundColour('#0F0') 61 # 下これを有効にすると、zoom out の時も少し更新される。 62 # test = Panel(self.scroll_panel, size=(x, y)) 63 # self.img_sizer.Add(test, 0) 64 self.scroll_panel.SetupScrolling() 65 self.scroll_panel.Refresh() 66 67 68if __name__ == "__main__": 69 app = App() 70 ImageViewer() 71 app.MainLoop()

試したこと

Panel.Refresh()
Panel.Hide() -> Panel.Show()

補足情報(FW/ツールのバージョンなど)

Python 3.8.2
wxPython 4.1.0

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

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

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

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

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

guest

回答1

0

ベストアンサー

原因: ズームの度に毎回ウィジェットを生成していて、前のウィジェットが残っている。

ズームイン・アウトで色を変更すると、このような状態になってます。

イメージ説明

複数の問題があるのですが、

簡単な回避策(現状のコードから最小限で修正)する場合は、
明示的に破棄(widget.Destroy) します。

self.img.Destroy() self.img = Panel(self.scroll_panel, size=(x, y))

sizer.Clear にも、sizer.Clear(1) でウィジェットを破棄するdelete_windowオプションがありますが、
サイズ所得してから破棄しないといけないので、その場合はコード実行の順序を移動します。


問題の解決

おそらく、GetSize が効かないので毎回ウィジェットを生成することにしたのだと思いますが、

根本的な解決方法は、Panel は以前の self.img を再利用するようにして、
** GetMinSize ** でサイズを変更するとサイズ変更が反映されるようになります。

イメージ説明

python

1 2 def zoom_in(self, event): 3 x, y = self.img.GetSize() 4 x *= 2 5 y *= 2 6 self.img.SetMinSize((x, y)) 7 self.scroll_panel.SetupScrolling() 8 9 def zoom_out(self, event): 10 x, y = self.img.GetSize() 11 x //= 2 12 y //= 2 13 self.img.SetMinSize((x, y)) 14 self.scroll_panel.SetupScrolling()

※ 他、背景色は #0F0 -> #00FF00 としました。

投稿2020/07/29 01:30

teamikl

総合スコア8760

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

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

kagaribisou

2020/07/29 01:59

ありがとうございます!! 想定していた機能を実装できました。 SetMinSize()でサイズを変更できるのは盲点でした。 もう少しドキュメントを読み込みたいと思います。 解答ありがとうございました!!!
teamikl

2020/07/29 02:42

>SetMinSize()でサイズを変更できるのは盲点でした。 余談ですが、少し詳しく説明すると、ここを判明できたのは SetupScrollingのソースコードを読んで、内部でsizer.GetMinSize() としていたからでした。 https://github.com/wxWidgets/Phoenix/blob/33fa9afdcccd8418bf27f83b40aaec2377f4309c/wx/lib/scrolledpanel.py#L146 ドキュメントで言及してそうな箇所といえば、この一文のみですね。 > It is assumed that the :class:`ScrolledPanel` will have a sizer, as it is used to calculate the minimal virtual size of the panel and etc. 因みに、SetSizeが反映されない理由ですが、SetPosition や SetSize を使うウィジェットは、 sizerでレイアウト管理すること自体が pos,size 設定の競合になるので、 SetSize での変更が反映されるようにしたい場合は、img_sizer と SetupScrolling は使わずに SetSize 後、self.scroll_panel.SetScrollbars(20, 20, x//20, y//20) のようにします。 → 利用するクラスも ScrolledPanel ではなく wx.ScrolledWindow で良い。 ScrolledPanel.SetupScrolling は、どちらかというと、単一ウィジェットのサイズ変更ではなく、 sizer に新しいウィジェットが追加・削除された場合の利用を想定されてそう。 ---- 後、__init__内の SetupScrolling() の呼び出しですが、SetSizer の後が良いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問