3

wxPython の例から DragImage デモを変更して、画像を移動するだけでなく、画像をドラッグするとドラッグ可能な新しいコピーが生成され元の「ソース」画像が残るようにしようとしています。元の画像は、選択できる一連のウィジェットのようなものです。これらのいずれかをクリックしてドラッグすると、ソースウィジェットが残っている間にどこにでも配置できるウィジェットが生成されます (これは複数回実行できます)。

import os
import glob

import wx
import wx.lib.scrolledpanel as scrolled

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent)
        frm_pnl = MainPanel(self)

        self.Show()

class DragShape:
    def __init__(self, bmp):
        self.bmp = bmp
        self.pos = (0,0)
        self.shown = True
        self.text = None
        self.fullscreen = False

    def HitTest(self, pt):
        rect = self.GetRect()
        return rect.InsideXY(pt.x, pt.y)

    def GetRect(self):
        #return wx.Rect(self.pos[0], self.pos[1], self.bmp.GetWidth(), self.bmp.GetHeight())
        return wx.Rect(self.pos[0], self.pos[1], self.bmp.GetWidth()/2, self.bmp.GetHeight()/2)

    def Draw(self, dc, op = wx.COPY):
        if self.bmp.Ok():
            memDC = wx.MemoryDC()
            memDC.SelectObject(self.bmp)

            #dc.Blit(self.pos[0], self.pos[1],
            #        self.bmp.GetWidth(), self.bmp.GetHeight(),
            #        memDC, 0, 0, op, True)

            dc.Blit(self.pos[0], self.pos[1],
                    self.bmp.GetWidth()/2, self.bmp.GetHeight()/2,
                    memDC, 0, 0, op, True)

            return True
        else:
            return False

class MainPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, size = (900, 700))

        self.shapes = []

        #panel for mechanisms
        mechPnl = MechanismPanel(self)

        mechSzr = wx.BoxSizer(wx.HORIZONTAL)
        mechSzr.Add(mechPnl, 1)

        selfSizer = wx.BoxSizer(wx.VERTICAL)
        selfSizer.Add(mechSzr, 0, wx.EXPAND)
        selfSizer.Layout()
        self.SetSizer(selfSizer)

        self.dragImage = None
        self.dragShape = None
        self.hiliteShape = None

        self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))

        #self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        mechPnl.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        mechPnl.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
        mechPnl.Bind(wx.EVT_MOTION, self.OnMotion)
        mechPnl.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)

    # The mouse is moving
    def OnMotion(self, evt):
        print "On motion!"

        # Ignore mouse movement if we're not dragging.
        if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown():
            return

        # if we have a shape, but haven't started dragging yet
        if self.dragShape and not self.dragImage:

            # only start the drag after having moved a couple pixels
            tolerance = 2
            pt = evt.GetPosition()
            dx = abs(pt.x - self.dragStartPos.x)
            dy = abs(pt.y - self.dragStartPos.y)
            if dx <= tolerance and dy <= tolerance:
                return

            # refresh the area of the window where the shape was so it
            # will get erased.
            self.dragShape.shown = False
            self.RefreshRect(self.dragShape.GetRect(), True)
            self.Update()

            if self.dragShape.text:
                self.dragImage = wx.DragString(self.dragShape.text,
                                              wx.StockCursor(wx.CURSOR_HAND))
            else:
                self.dragImage = wx.DragImage(self.dragShape.bmp,
                                             wx.StockCursor(wx.CURSOR_HAND))

            hotspot = self.dragStartPos - self.dragShape.pos
            self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen)

            self.dragImage.Move(pt)
            self.dragImage.Show()


        # if we have shape and image then move it, posibly highlighting another shape.
        elif self.dragShape and self.dragImage:
            onShape = self.FindShape(evt.GetPosition())
            unhiliteOld = False
            hiliteNew = False

            # figure out what to hilite and what to unhilite
            if self.hiliteShape:
                if onShape is None or self.hiliteShape is not onShape:
                    unhiliteOld = True

            if onShape and onShape is not self.hiliteShape and onShape.shown:
                hiliteNew = True

            # if needed, hide the drag image so we can update the window
            if unhiliteOld or hiliteNew:
                self.dragImage.Hide()

            if unhiliteOld:
                dc = wx.ClientDC(self)
                self.hiliteShape.Draw(dc)
                self.hiliteShape = None

            if hiliteNew:
                dc = wx.ClientDC(self)
                self.hiliteShape = onShape
                self.hiliteShape.Draw(dc, wx.INVERT)

            # now move it and show it again if needed
            self.dragImage.Move(evt.GetPosition())
            if unhiliteOld or hiliteNew:
                self.dragImage.Show()

    # Left mouse button up.
    def OnLeftUp(self, evt):
        print "On left up!"

        if not self.dragImage or not self.dragShape:
            self.dragImage = None
            self.dragShape = None
            return

        # Hide the image, end dragging, and nuke out the drag image.
        self.dragImage.Hide()
        self.dragImage.EndDrag()
        self.dragImage = None

        if self.hiliteShape:
            self.RefreshRect(self.hiliteShape.GetRect())
            self.hiliteShape = None

        # reposition and draw the shape

        # Note by jmg 11/28/03 
        # Here's the original:
        #
        # self.dragShape.pos = self.dragShape.pos + evt.GetPosition() - self.dragStartPos
        #
        # So if there are any problems associated with this, use that as
        # a starting place in your investigation. I've tried to simulate the
        # wx.Point __add__ method here -- it won't work for tuples as we
        # have now from the various methods
        #
        # There must be a better way to do this :-)
        #

        self.dragShape.pos = (
            self.dragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0],
            self.dragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1]
            )

        self.dragShape.shown = True
        self.RefreshRect(self.dragShape.GetRect())
        self.dragShape = None

    # Fired whenever a paint event occurs
    def OnPaint(self, evt):
        print "On paint!"

        dc = wx.PaintDC(self)
        self.PrepareDC(dc)
        self.DrawShapes(dc)

    # Left mouse button is down.
    def OnLeftDown(self, evt):
        print "On left down!"

        # Did the mouse go down on one of our shapes?
        shape = self.FindShape(evt.GetPosition())

        # If a shape was 'hit', then set that as the shape we're going to
        # drag around. Get our start position. Dragging has not yet started.
        # That will happen once the mouse moves, OR the mouse is released.
        if shape:
            self.dragShape = shape
            self.dragStartPos = evt.GetPosition()

    # Go through our list of shapes and draw them in whatever place they are.
    def DrawShapes(self, dc):
        for shape in self.shapes:
            if shape.shown:
                shape.Draw(dc)

    # This is actually a sophisticated 'hit test', but in this
    # case we're also determining which shape, if any, was 'hit'.
    def FindShape(self, pt):
        for shape in self.shapes:
            if shape.HitTest(pt):
                return shape
        return None

    # Clears the background, then redraws it. If the DC is passed, then
    # we only do so in the area so designated. Otherwise, it's the whole thing.
    def OnEraseBackground(self, evt):
        dc = evt.GetDC()
        if not dc:
            dc = wx.ClientDC(self)
            rect = self.GetUpdateRegion().GetBox()
            dc.SetClippingRect(rect)
        self.TileBackground(dc)

    # tile the background bitmap
    def TileBackground(self, dc):
        sz = self.GetClientSize()
        w = self.bg_bmp.GetWidth()
        h = self.bg_bmp.GetHeight()

        x = 0

        while x < sz.width:
            y = 0

            while y < sz.height:
                dc.DrawBitmap(self.bg_bmp, x, y)
                y = y + h

            x = x + w

    # We're not doing anything here, but you might have reason to.
    # for example, if you were dragging something, you might elect to
    # 'drop it' when the cursor left the window.
    def OnLeaveWindow(self, evt):
        pass

class MechanismPanel(scrolled.ScrolledPanel):
    def __init__(self, parent):
        scrolled.ScrolledPanel.__init__(self, parent, -1, size = (400, 140))
        self.SetBackgroundColour((211, 211, 211))

        mechPnlSzr = wx.BoxSizer(wx.HORIZONTAL)

        os.chdir("./figures")
        position = 50
        for file in glob.glob("icon*.png"):
            print file
            imgIcon = wx.Image(file, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
            staticBitmap = wx.StaticBitmap(self, -1, imgIcon, (position, 50), (50, 50))
            shape = DragShape(staticBitmap.GetBitmap())
            shape.pos = (position, 50)
            position = position + 100
            shape.fullscreen = True
            parent.shapes.append(shape)
            mechPnlSzr.Add(staticBitmap, 0, wx.FIXED, border = 20)

        self.SetSizer(mechPnlSzr)

        self.SetAutoLayout(1)
        self.SetupScrolling()#scroll_y = False)

app = wx.App(False)
frame = MainWindow(None, "Trading Client")
app.MainLoop()
4

0 に答える 0