はねまわるウインドウな例
つかまえられないメインフォーム
tags: | gui, tips |
---|---|
created: | 2006-03-12T12:45:52 |
勝手に動き回る迷惑なGUIを作成してみました。
リソース内容
今回XRCを使っていません。
img2pyを用いて、「shape_image.png」を Pythonコードに変換した「shape_image.py」から 画像を取り出して使っています。
img2pyの使い方
以下のようにすると、
img2py shape_image.png shape_image.py
イメージからpythonコードを生成します。
こうして作成されたコードはモジュールとして利用でき、 以下のように利用できます。
import shape_image
bmp = shape_image.getBitmap()
bmpはビットマップオブジェクト(wxBitmap)インスタンスです。
メインコード
bounds.py
#!/usr/bin/local/python
# -*- coding: utf-8 -*-
import sys
import os
import wx
import wx_utils
import shape_image
import math
class MainFrame(wx.Frame):
u"""MainFrame class deffinition.
"""
binder = wx_utils.bind_manager()
def __init__(self, parent=None):
wx.Frame.__init__(self, parent, style = wx.FRAME_SHAPED | wx.NO_BORDER)
self.bmp = shape_image.getBitmap()
self.SetClientSize(self.bmp.GetSize())
self.SetShape(wx.RegionFromBitmap(self.bmp))
self.binder.bindall(self)
self.offset = tuple(i/2.0 for i in self.bmp.GetSize())
self.position = tuple(i/2.0 for i in wx.GetDisplaySize())
self.radius = self.offset[0]
self.xmin = self.radius
self.xmax = wx.GetDisplaySize()[0] - self.radius
self.ymin = self.radius
self.ymax = wx.GetDisplaySize()[1] - self.radius
self.vector = (0.0, 0.0)
self.timer = wx.Timer(self)
self.timer.Start(1)
def push(self, new):
nx, ny = new
vx, vy = self.vector
self.vector = (vx*0.99+nx, vy*0.99+ny)
@binder(wx.EVT_TIMER)
def OnUpdate(self, event):
px, py = self.position
vx, vy = self.vector
px += vx
py += vy
self.position = (px, py)
fx, fy = 0,0
if px<self.xmin:
fx = self.xmin-px
if px>self.xmax:
fx = self.xmax-px
if py<self.ymin:
fy = self.ymin-py
if py>self.ymax:
fy = self.ymax-py
self.push((fx,fy))
tx, ty = self.offset
self.SetPosition((px-tx, py-ty))
@binder(wx.EVT_LEFT_DOWN)
def OnLeftDown(self, event):
wx.SafeShowMessage(u'メッセージ', u'つかまった!')
self.Close()
@binder(wx.EVT_MOTION)
def OnMouseOver(self, event):
x, y = self.offset
px, py = event.GetPosition()
x -= px
y -= py
distance = math.sqrt(x*x+y*y)
rate = (self.radius - distance)/distance
fx, fy = x*rate, y*rate
self.push((fx,fy))
@binder(wx.EVT_PAINT)
def OnPaint(self, event):
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bmp, 0,0, True)
# startup application.
if __name__=='__main__':
app = wx.App(False)
frame = MainFrame()
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
解説
概要
シェイプドウインドウやタイマーイベント、 マウスモーション検知イベント利用のサンプルになっています。
マウスカーソルを検知すると逃げる方向に最短方向に逃げます。
ペナルティ法?の衝突シミュレーション演算を入れてますので ビリヤードのようにリアルに跳ね返ります。
一応ウインドウのリージョン内で左クリックできるとメッセージが出て終了しますが、 私は成功出来たことがありません。
タイマーイベントは10ms以下の周期はガタガタと揺れまくりです。
こういった高頻度のタイマーイベントの処理にはもうひとつwx.EVT_IDLEがありますが、 こちらはベストの最短頻度で処理をさせたい時に便利です。
ただし、周期はばらばらです。