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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

ウィンドウ

コンピューター用語において、ウィンドウとはユーザとプログラムのやり取りを可能にするGUIの枠組みのことをいいます。

Python

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

Q&A

1回答

4621閲覧

wxpythonでウィンドウ枠を透過させて手前に画像やgifを表示させたい。

dendenmushi

総合スコア98

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

ウィンドウ

コンピューター用語において、ウィンドウとはユーザとプログラムのやり取りを可能にするGUIの枠組みのことをいいます。

Python

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

0グッド

0クリップ

投稿2020/10/04 07:57

前提・実現したいこと

以前の質問wxpythonで透過gifと背景gifを同時に重ねて再生表示する方法と似ている質問になります。以下のgif動画の一番下にある箇所をなくし、ウィンドウそのものを透過させたいです。
イメージ説明

開発環境

win10
python3.7
wxpython

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

挑戦した方法はselfをSetTransparent効果にさせて透明化する方法です。
問題としては上の桜吹雪index.gifも透明になってしまい、全体的に透明化してしまいました。
イメージ説明

該当のソースコード

python

1import wx 2import wx.adv 3 4 5def callLaterTimedGen(gen, done=None, stop=None): 6 def next_gen(): 7 interval = next(gen, stop) 8 if interval is not stop: 9 wx.CallLater(interval, next_gen) 10 wx.CallAfter(next_gen) 11 return gen 12 13 14class MyFrame(wx.Frame): 15 def __init__(self, parent=None, *args, **kw): 16 super().__init__(parent, *args, **kw) 17 18 self.menubar = wx.MenuBar(wx.MB_DOCKABLE) 19 self.filem = wx.Menu() 20 self.filem.Append(wx.ID_EXIT, '&Transparency') 21 22 self.menubar.Append(self.filem, '&File') 23 self.SetMenuBar(self.menubar) 24 self.Bind(wx.EVT_MENU, self.OnTrans) 25 26 self.bmp1 = None 27 self.bmp2 = None 28 self.Bind(wx.EVT_PAINT, self.OnPaint) 29 self.Bind(wx.EVT_TIMER, lambda _: self.Refresh()) 30 31 self.timer = wx.Timer(self) 32 self.timer.Start(200) 33 34 # panel = wx.Panel(self) 35 36 # self.gen1 = callLaterTimedGen(gifAnimation("unnamed.gif", self.SetBitmap1)) 37 self.gen2 = callLaterTimedGen(gifAnimation("index.gif", self.SetBitmap2, useMask=(0, 0, 0))) 38 39 #ボタンの作成 40 self.Button1=wx.Button(self, label="exit",pos=(20,100)) 41 self.Button2=wx.Button(self, label="print",pos=(20,150)) 42 43 #ボタンを割り当て 44 self.Bind(wx.EVT_BUTTON, self.close, self.Button1) 45 self.Bind(wx.EVT_BUTTON, self.printer, self.Button2) 46 47 self.Show(True) 48 49 self.transp = False 50 wx.CallLater(250, self.OnTrans, None) 51 52 def OnTrans(self, event): 53 if self.transp == False: 54 self.SetTransparent(30) 55 self.transp = True 56 else: 57 self.SetTransparent(255) 58 self.transp = False 59 60 def close(self,event): 61 self.Close(True) 62 63 def printer(self, event): 64 print("Button2") 65 self.gen1.close() 66 self.gen1 = callLaterTimedGen(gifAnimation("someiyoshino2.gif", self.SetBitmap1)) 67 68 def SetBitmap1(self, bmp): 69 self.bmp1 = bmp 70 71 def SetBitmap2(self, bmp): 72 self.bmp2 = bmp 73 74 def OnPaint(self, event): 75 dc = wx.PaintDC(self) 76 if self.bmp1: 77 # 背景 (mask: False) 78 dc.DrawBitmap(self.bmp1, 0, 0, False) 79 if self.bmp2: 80 # 透過 (mask: True) 81 dc.DrawBitmap(self.bmp2, 0, 0, True) 82 83 84def gifAnimation(filepath, setBitmap, useMask=None): 85 anim = wx.adv.Animation(filepath) 86 # self.transp = False 87 from itertools import cycle 88 for idx in cycle(range(anim.GetFrameCount())): 89 print('idx', idx) 90 delay = anim.GetDelay(idx)/10 91 print('delay', delay) 92 frame = anim.GetFrame(idx) 93 print('frame', frame) 94 if useMask: 95 frame.SetMaskColour(*useMask) 96 yield delay 97 setBitmap(frame.ConvertToBitmap()) 98 99 100def main(): 101 app = wx.App() 102 win = MyFrame(None, wx.ID_ANY, "ウィンドウ透過GIF重ね合わせテスト", size = (600,400)) 103 win.Centre() 104 win.Show() 105 106 app.MainLoop() 107 108 109if __name__ == '__main__': 110 main()

共有ファイル

夜桜index.gifの配置場所(google drive)

試したこと

この問題に対して以下のサイトなどを参照しました。

wxPython - 透明/アルファの背景を描画する(カスタムウィジェット/パネル用)
⇒目的のものと違っているようでした。

wxpythonはパネル上に矩形を描画しません
⇒以下のような確かにウィンドウを透明化した上に描画していますが、gif動画となるとPaintというわけにはいかないため、表示できませんでした。
イメージ説明
コードは以下です。

python

1import wx 2from PIL import Image, ImageDraw 3import wx.adv 4def callLaterTimedGen(gen, done=None, stop=None): 5 def next_gen(): 6 interval = next(gen, stop) 7 if interval is not stop: 8 wx.CallLater(interval, next_gen) 9 wx.CallAfter(next_gen) 10 return gen 11 12class Frame(wx.Frame): 13 def __init__(self): 14 15 super(Frame, self).__init__(None) 16 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) 17 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) 18 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) 19 self.Bind(wx.EVT_PAINT, self.OnPaint) 20 def OnEraseBackground(self, event): 21 pass # do nothing 22 def OnLeftDown(self, event): 23 print(event.GetPosition()) 24 def OnKeyDown(self, event): 25 if event.GetKeyCode() == wx.WXK_ESCAPE: 26 self.Close() 27 else: 28 event.Skip() 29 30 def SetBitmap2(self, bmp): 31 self.bmp2 = bmp 32 def OnPaint(self, event): 33 dc = wx.PaintDC(self) 34 dc.SetPen(wx.Pen('#d4d4d4')) 35 dc.SetBrush(wx.Brush('#c56c00')) 36 dc.DrawRectangle(10, 15, 90, 60) 37 print("Button2") 38 self.gen2 = callLaterTimedGen(gifAnimation("someiyoshino2.gif", self.SetBitmap2, useMask=(0, 0, 0))) 39 40 self.Show(True) 41 def printer(self, event): 42 print("Button2") 43 self.gen1.close() 44 self.gen1 = callLaterTimedGen(gifAnimation("someiyoshino2.gif", self.SetBitmap1)) 45 46def gifAnimation(filepath, setBitmap, useMask=None): 47 anim = wx.adv.Animation(filepath) 48 49 from itertools import cycle 50 for idx in cycle(range(anim.GetFrameCount())): 51 print('idx', idx) 52 delay = anim.GetDelay(idx)/10 53 print('delay', delay) 54 frame = anim.GetFrame(idx) 55 print('frame', frame) 56 if useMask: 57 frame.SetMaskColour(*useMask) 58 yield delay 59 setBitmap(frame.ConvertToBitmap()) 60 61if __name__ == '__main__': 62 app = wx.PySimpleApp() 63 frame = Frame() 64 frame.ShowFullScreen(True) 65 app.MainLoop()

selfごと透過しても目的は達成できなく、paintDCを使っても描画のみでgifを表示することができませんでした。
いっそのこと枠全体を.コンマでキャプチャして枠へ表示するという複雑な作りも考えましたができませんでした。2つのレイヤーを持たせるなどの方法もあるのでしょうか。

知見ある方アドバイス頂けないでしょうか。よろしくお願い致します。

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

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

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

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

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

teamikl

2020/10/04 22:56

ウィンドウそのものを透過させたいというと、SetTransparent だと思いました。 どのような透過なのかがイメージできないのですが、 背景画像の特定の色のみを透過ということですか? 例えば、白色の部分のみ後ろが透けて、ウィンドウ内からデスクトップの背景がみえるような。
dendenmushi

2020/10/05 02:09

teamiklさんありがとうございます。イメージとしてはレイヤーが2つで上のgifは通常色で桜が舞い、その下のレイヤーは全て透明で枠だけあり(枠ありなしこだわっていません)、デスクトップが見れる状態です。 白色の部分というより、gif以外全て透過しているイメージです。
guest

回答1

0

既存のコードとの兼ね合いがどうなるかわかりませんが、

半透明ではなく、特定の部分のみを透過するといった場合は、
「透過ウィンドウ」ではなく「非矩形ウィンドウ」にします。

OnPaint 内で、

  • bitmap の透過したい色を mask に設定
  • RegionFromBitmap で目的の Region を得る
  • Region を設定 SetClippingRegionAsRegion

 
Frame に対して非短形ウィンドウは SetShape で設定できますが、
毎フレーム形が変わるため、OnPaintイベント 内で Device Context に対して設定します。

ひとつ、心配なのは、アニメーションだという点。

毎フレーム処理していてはアニメーション速度に影響し遅くならないかという懸念があります。
GIFのフレーム数次第では事前計算しておく等も対策として考えられますが、
この点に関しては、実際に試したことはないのでわかりません。


他の解決策としては、GUIとは別に
透過画像を wx.ClientDC や wx.ScreenDC に直接描画する方法も考えられます。

この場合、ウィンドウは枠無しウィンドウにしてください。
描画する座標をウィンドウ位置からの相対的に求めることで、
擬似的に透過したウィンドウっぽくなります。

但し、この方法の場合、画像が描画されてる部分はマウスイベントやフォーカスを持てないので注意。
(スクリーンショットを取るブログラムで、ウィンドウのみを選択した場合に
スクリーンへの描画は含まれない等、いくつか弊害が考えられます)

追記: ScreenDC ではなく ClientDC なら大丈夫かもしれない(未検証)

現状のコードを直接変更してテストするのは、問題が複雑化するのでお勧めしません。
まずは各項目について単体のプログラムを書いて動作を確かめてみましょう。

  • 非短形ウィンドウ

 ・frame.SetShape(region)
・dc.SetClippingRegionAsRegion(region)

  • wx.ClientDC, wx.ScreenDC への直接描画

下のコードについて、気になった点

  • OnPaint 内でのタイマー呼び出しは、描画毎に呼び出されるので多重になってしまいそう。
  • OnPaintは何度も呼び出されるイベントなので、Showもここで呼び出すべきでは有りません。

投稿2020/10/05 02:43

編集2020/10/05 02:51
teamikl

総合スコア8760

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

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

dendenmushi

2020/10/05 08:00

後者の方法でまずは新しいプロジェクトで試してみようと思います。非矩形ウィンドウがいったいどんなものか把握していませんのでまずそれを調べるところから頑張ってみようと思います。ありがとうございます。
teamikl

2020/10/05 22:31 編集

レイヤーが2重なので、前者の方法で 透過にする範囲を事前に求めるのは難しそうですね。 こちらも徐々に、まずは静止画で非矩形ウィンドウ、 動画で~、動画で2重レイヤ~と段階を踏んで試していった方が良さそうです。 書き忘れましたが、SetShape を使う場合は、 Frame 初期化時の style オプションに wx.FRAME_SHAPED を指定します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問