Sketch window: Dragging ist nach dem Zoomen langsam

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
ennemoser
User
Beiträge: 7
Registriert: Freitag 31. August 2007, 18:48
Wohnort: Graz

Montag 1. Oktober 2007, 21:19

Servus,

ich habe von wxPython in Action das Sketch Beispiel übernommen und abgewandelt. Ich habe "dragging"(linke Maustaste) und "zoom"(Mausrad) implementiert. Außerdem verwende ich GraphicsContext, da ich Antialiasing und später Transparenz verwenden möchte.
Wenn ich nun zoome (größer), lässt sich das ganze kaum mehr "draggen". Wenn ich das Ganze wieder verkleinere, dann habe ich full speed.

Was mache ich falsch? Hängt das mit dem event.Skip() zusammen? :?

Python: 2.4, Enthought edition
wxPython Version: wx-2.8-msw-ansi

Andi

Code: Alles auswählen

#!c:/python24/python

import wx

class Canvas(wx.Window):
    def __init__(self, parent, ID):
        wx.Window.__init__(self, parent, ID)
        self.SetBackgroundColour("White")
        self.color = "Black"
        self.thickness = 2
        self.pen = wx.Pen(self.color, self.thickness, wx.SOLID)
        self.brush = wx.Brush(wx.Colour( 80, 80, 255, 255))
        self.lines = [(-20,-20), (20,-20), (20,20), (-20,20), (-20,-20)]
        self.zoom = 1.0

        self.Bind(wx.EVT_MOTION, self.OnMotion)
        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMotion)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_IDLE, self.OnIdle)
        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetSizeandOrigin()
        self.InitBuffer()

    def InitBuffer(self):

        self.buffer = wx.EmptyBitmap(self.width, self.height)
        dc = wx.BufferedDC(None, self.buffer)
        dc.SetMapMode(wx.MM_METRIC)

        # Drawing upside down (i.e. natural orientation)
        dc.SetAxisOrientation(True, True)

        # Original position is top left of window
        dc.SetDeviceOrigin(self.origin[0], self.origin[1])

        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()

        gc = wx.GraphicsContext.Create(dc)

        if self.lines: 
            self.DrawLines(gc)

        # Prevent redraw in OnIdle 
        self.reInitBuffer = False

    def OnPaint(self, event):
        # For double buffered drawing; content of self.buffer is blit here to the DC
        dc = wx.BufferedPaintDC(self, self.buffer)

    def DrawLines(self, gc):
        path = gc.CreatePath()
        path.MoveToPoint(self.lines[0])   # Move to start point of airfoil
        for index, coord in enumerate(self.lines):
            #if index == 0: pass
            path.AddLineToPoint(coord)
        gc.SetPen(self.pen)
        gc.SetBrush(self.brush)
        gc.Scale(self.zoom, self.zoom)
        gc.DrawPath(path)

    def OnMotion(self, event):
        # Drag
        if event.Dragging() and event.LeftIsDown() and not event.m_controlDown:
            actPos = event.GetPositionTuple()
            xact = actPos[0]
            yact = actPos[1]
            xold = self.pos[0]
            yold = self.pos[1]
            vx = xact - xold
            vy = yact - yold
            self.origin = (self.origin[0] + vx, self.origin[1] + vy)
            self.pos = actPos
            self.InitBuffer()
            self.Refresh(False)
        # Zoom
        elif event.GetWheelRotation():
            self.zoom = self.zoom - event.GetWheelRotation()/float(self.height)    # Change zoom factor
            self.InitBuffer()
            self.Refresh(False)
        else:
            self.pos = event.GetPositionTuple()   # Initialize for dragging

        event.Skip()   # ???

    def OnSize(self, event):
        self.width, self.height = self.GetClientSize()
        self.SetSizeandOrigin(0)
        self.reInitBuffer = True  # Redraw is automatically performed in OnIdle

    def OnIdle(self, event):
        if self.reInitBuffer:
            self.InitBuffer()
            self.Refresh(False)   #  generates EVT_PAINT; False means background not erased

    def SetSizeandOrigin(self, fit=0):
        self.width, self.height = self.GetClientSize()
        if fit == 0:
            or_x = 0.5*self.width    # to be changed for all
            or_y = 0.5*self.height   # to be changed for all
            self.zoom = 1.0

        self.origin = (or_x, or_y)

class SketchFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "Test",
                size=(800,600))
        self.sketch = Canvas(self, -1)

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = SketchFrame(None)
    frame.Show(True)
    app.MainLoop()

Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Dienstag 2. Oktober 2007, 09:03

ennemoser hat geschrieben:Wenn ich nun zoome (größer), lässt sich das ganze kaum mehr "draggen". Wenn ich das Ganze wieder verkleinere, dann habe ich full speed.
Hallo ennemoser!

Du zeichnest dein Objekt immer wieder neu. Ich habe im Code mal mitzählen lassen, wie oft das Bild neu gezeichnet wird, wenn ich das Objekt von links oben nach rechts unten bewege. Im Schnitt 50 mal.

Bei einem kleinen Bild ist das nicht so schlimm. Das sind insgesamt wenige Pixel die gezeichnet werden müssen. Aber je größer das Bild wird, desto mehr Pixel müssen neu gezeichnet werden. Und das bis zu xxx mal pro Sekunde.

Ich glaube, dass du einen Geschwindigkeitsvorteil heraus holen kannst, wenn du nach dem Zoomen das gezeichnete Bild in ein Bitmap (buffer) speicherst und das Bild beim Bewegen nicht ständig neu zeichnen lässt.

Es sollte genügen, wenn du das gepufferte Bitmap mit Blit() in den Hauptbuffer überträgst. Hinter Blit() steckt nicht so viel Computerarbeit als hinter den Zeichenbefehlen. Blit() überträgt einfach nur den angegebenen Speicherbereich. Ich gehe davon aus, dass damit dein Programm viel schneller wird.

Probier es mal aus. Vielleicht hilft es.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten