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