我正在使用wxPyhon編寫簡單的GUI並面臨一些問題。
我的應用程序做了簡單的事情:它在窗體上繪製三角形,並在用戶單擊箭頭按鈕或在窗體上拖動鼠標光標時旋轉它。
我現在看到的問題如下:
1.然後,我快速拖動鼠標sursor,三角形旋轉,同時保持舊圖像短時間可見。當保持快速移動光標一段時間時,窗體上的圖形看起來像2或3個三角形。
2.如果我將窗體展開爲整個屏幕的大小,三角形將不太順暢地移動,從舊的外觀跳到一個新的外觀。我在旋轉過程中查看了鼠標光標的座標,並注意到它們被間隙跟蹤。我的朋友說我是因爲每當我揮動三角形時,我都會重新繪製應用程序的整個窗口。這就是爲什麼它運行緩慢並且減慢了鼠標光標的跟蹤速度。如何平滑重繪窗體上的對象(wxPython)
刷新視圖我正在使用wx.Panel.Refresh()方法。作爲繪圖上下文,我正在使用wx.BufferedDC()
請告訴我如何在wxPython表單上正確繪製動態更改的圖片/繪圖,特別是我在該應用程序中製作的方式。
我可以把我的代碼放在這裏,但它太長了。所以如果我必須告訴我更多關於我的情況 - 請問我,我會回答。
謝謝!
class SimpleGraphics(wx.Panel):
def __init__(self, parent, size=(50, 50)):
super(SimpleGraphics, self).__init__(parent,
size=size,
style=wx.NO_BORDER)
self.color = "Black"
self.thickness = 2
self.pen = wx.Pen(self.color, self.thickness, wx.SOLID)
self.MARGIN = 1 #px
self.points = [[0.0, 0.5], [0.5, 0.0], [-0.5, -0.5]]
self.pos = (0, 0)
self.cur_vector = Vector2D(1, 1)
self.InitBuffer()
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_IDLE, self.OnIdle)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyArrow)
# MOUSE TRACKING
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def InitBuffer(self):
self.client_size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(self.client_size.width, self.client_size.height)
dc = wx.BufferedDC(None, self.buffer)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
self.DrawImage(dc)
self.reInitBuffer = False
def OnSize(self, event):
self.reInitBuffer = True
def repaint_the_view(self):
self.InitBuffer()
self.Refresh()
def OnIdle(self, event):
if self.reInitBuffer:
self.repaint_the_view()
def OnKeyArrow(self, event):
key_code = event.GetKeyCode()
if key_code == wx.WXK_LEFT:
self.rotate_points(degrees_to_rad(5))
elif key_code == wx.WXK_RIGHT:
self.rotate_points(degrees_to_rad(-5))
self.repaint_the_view()
event.Skip()
def OnLeftDown(self, event):
# get the mouse position and capture the mouse
self.pos = event.GetPositionTuple()
self.cur_vector = create_vector2d(self.pos[0], self.pos[1],
self.client_size.width/2,
self.client_size.height/2)
self.CaptureMouse()
def OnLeftUp(self, event):
#release the mouse
if self.HasCapture():
self.ReleaseMouse()
def OnMotion(self, event):
if event.Dragging() and event.LeftIsDown():
newPos = event.GetPositionTuple()
new_vector = create_vector2d(newPos[0], newPos[1],
self.client_size.width/2,
self.client_size.height/2)
if new_vector.lenth() > 0.00001:
c = cos_a(self.cur_vector, new_vector)
s = sin_a(self.cur_vector, new_vector)
rot_matr = rotation_matrix(s, c)
self.rotate_points(rot_matr=rot_matr)
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) # this line I've added after posting the question
self.repaint_the_view()
self.cur_vector = new_vector
event.Skip()
def OnPaint(self, event):
wx.BufferedPaintDC(self, self.buffer)
def DrawImage(self, dc):
dc.SetPen(self.pen)
new_points = self.convetr_points_to_virtual()
dc.DrawPolygon([wx.Point(x, y) for (x, y) in new_points])
def to_x(self, X_Log):
X_Window = self.MARGIN + (1.0/2) * (X_Log + 1) * (self.client_size.width - 2 * self.MARGIN)
return int(X_Window)
def to_y(self, Y_Log):
Y_Window = self.MARGIN + (-1.0/2) * (Y_Log - 1) * (self.client_size.height - 2 * self.MARGIN)
return int(Y_Window)
def convetr_points_to_virtual(self):
return [(self.to_x(x), self.to_y(y)) for (x, y) in self.points]
def rotate_points(self, angle_in_degrees=None, rot_matr=None):
if angle_in_degrees is None:
self.points = [rotate_point(x, y , rotator_matrix=rot_matr) for (x, y) in self.points]
else:
self.points = [rotate_point(x, y , angle_in_degrees) for (x, y) in self.points]
class SimpleGraphicsFrame(wx.Frame):
def __init__(self, parent, *args, **kwargs):
wx.Frame.__init__(self, parent, *args, **kwargs)
# Attributes
self.panel = SimpleGraphics(self)
# Layout
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel, 1, wx.EXPAND)
self.SetSizer(sizer)
class SimpleGraphApp(wx.App):
def OnInit(self):
self.frame = SimpleGraphicsFrame(None,
title="Drawing Shapes",
size=(300, 400))
self.frame.Show()
return True
if __name__ == '__main__':
app = SimpleGraphApp(False)
app.MainLoop()
嘗試在EVT_IDLE中刷新面板,而不是在鼠標事件中。也使用雙緩衝。如果您可以提供演示問題的小型可運行代碼示例,將會有所幫助。 – Fenikso 2012-03-30 14:04:06
我已添加我的代碼。一些功能不包括在內,但我認爲,給定的部分足以實現這個想法。 P.S. 我在OnMotion方法中添加了一行。它使應用程序更好(解決項目2),但我認爲這個應用程序不夠好。所以你的建議將受到歡迎。 – 2012-03-30 17:46:28