如何并行绘制到 PaintDC 和 MemoryDC 中?
how to draw into a PaintDC and MemoryDC in parallel?
我正在寻找一段代码,如何并行使用 wx.PaintDC() 和 wx.MemoryDC。
我的 wxPython 是 2.8.12 版,我无法将 wx.PaintDC() 绘制到 wx.Window,而
还有一个线程 运行,将 wx.MemoryDC 绘制到位图中。
像这样:
def onPaint(self, evt):
self.dc=wx.PaintDC(self)
imgbuf, (sx, sy), self.refresh_needed=self.osm.getBitmap()
self.dc.DrawBitmap(imgbuf, sx, sy)
as_thread()
w, h=self.__getBitmapSize()
self.bmpbuf=wx.EmptyBitmapRGBA(w, h, 204, 204, 204, 1)
self.mdc=wx.MemoryDC()
self.mdc.SelectObject(self.bmpbuf)
[.....]
y=0
for yi in imgs:
x=0
for tn, (status, xi) in yi:
if status!=self.status["GOOD"]:
xi=wx.EmptyBitmapRGBA(256, 256, red=255, alpha=1)
if status!=self.status["INVALID"]:
needs_refresh=True
self.mdc.DrawBitmap(xi, x, y)
x+=self.ts
y+=self.ts
imgbuf和self.bmpbuf不是同一个对象。
self.bmpbuf 复制为:
w, h=self.__getBitmapSize()
buf=numpy.empty((w, h, 3), dtype=numpy.uint8)
self.bmpbuf.CopyToBuffer(buf)
self.v[handle].bmpbuf=wx.BitmapFromBuffer(w, h, buf)
但总是出现如下错误:
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: xcb_io.c:165: dequeue_pending_request: Zusicherung »!xcb_xlib_unknown_req_in_deq« nicht erfüllt.
编辑:
这是一个完整的工作演示脚本,显示了问题:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import wx
import random
import time
import threading
class TestWin(wx.Window):
def __init__(self, parent, title, size):
wx.Window.__init__(self, parent)
self.Bind(wx.EVT_PAINT, self.onPaint)
self.Bind(wx.EVT_TIMER, self.onTimer)
t=threading.Thread(target=self.asThread, name="draw")
t.setDaemon(True)
t.start()
self.timer=wx.Timer(self)
self.timer.Start(100)
def onPaint(self, evt):
dc=wx.PaintDC(self)
dc.SetPen(wx.Pen("BLACK"))
dc.SetBrush(wx.Brush("BLUE"))
w, h=self.GetSize()
dc.DrawCirclePoint((random.randint(0, w), random.randint(0, h)), 5)
def onTimer(self, evt):
self.Refresh()
def asThread(self):
w, h=self.GetSize()
bmpbuf=wx.EmptyBitmapRGBA(w, h, 204, 204, 204, 1)
mdc=wx.MemoryDC()
mdc.SelectObject(bmpbuf)
time.sleep(1)
mdc.SetPen(wx.Pen("BLACK"))
mdc.SetBrush(wx.Brush("RED"))
print "now writing to MemoryDC"
while True:
#time.sleep(0.0001)
mdc.DrawCirclePoint((random.randint(0, w), random.randint(0, h)), 5)
wx.Yield()
class TestFrame(wx.Frame):
def __init__(self, parent, title, size):
wx.Frame.__init__(self, None, wx.ID_ANY, title)
win=TestWin(self, title, size)
if __name__=="__main__":
app=wx.App(False)
frame=TestFrame(None, "Test", size=(200, 200))
frame.Show()
app.MainLoop()
EDIT2: 为什么我要在线程中构建位图:
我有一个 class 为给定的 window 大小、缩放级别和 lat/lon-coordinate 提供位图(显示 OpenStreetMap-tiles)。
class 还将 GPS 轨迹和点列表绘制到 map/bitmap 上。
因为位图的尺寸高于 window 尺寸,所以我可以将位图移动到 window 下,而无需构建新的位图。
为了移动位图,调用 dc.DrawBitmap(imgbuf, sx, sy) 并稍微改变 (sx, sy) 的值。每个新剪辑需要 0.1 毫秒。构建新位图最多需要 150 毫秒。
当从一个位置滚动到另一个位置时,滚动非常平滑,直到需要新的位图。
如果可以准备新的位图,在 old 位图上滚动时,应该可以在长距离上连续平滑滚动。
你不应该(在大多数情况下,不能)从主 UI 线程以外的任何地方操作 UI 对象。这包括 DC 和位图。你到底想完成什么?可能还有其他方法可以做到这一点。
我正在寻找一段代码,如何并行使用 wx.PaintDC() 和 wx.MemoryDC。 我的 wxPython 是 2.8.12 版,我无法将 wx.PaintDC() 绘制到 wx.Window,而 还有一个线程 运行,将 wx.MemoryDC 绘制到位图中。
像这样:
def onPaint(self, evt):
self.dc=wx.PaintDC(self)
imgbuf, (sx, sy), self.refresh_needed=self.osm.getBitmap()
self.dc.DrawBitmap(imgbuf, sx, sy)
as_thread()
w, h=self.__getBitmapSize()
self.bmpbuf=wx.EmptyBitmapRGBA(w, h, 204, 204, 204, 1)
self.mdc=wx.MemoryDC()
self.mdc.SelectObject(self.bmpbuf)
[.....]
y=0
for yi in imgs:
x=0
for tn, (status, xi) in yi:
if status!=self.status["GOOD"]:
xi=wx.EmptyBitmapRGBA(256, 256, red=255, alpha=1)
if status!=self.status["INVALID"]:
needs_refresh=True
self.mdc.DrawBitmap(xi, x, y)
x+=self.ts
y+=self.ts
imgbuf和self.bmpbuf不是同一个对象。
self.bmpbuf 复制为:
w, h=self.__getBitmapSize()
buf=numpy.empty((w, h, 3), dtype=numpy.uint8)
self.bmpbuf.CopyToBuffer(buf)
self.v[handle].bmpbuf=wx.BitmapFromBuffer(w, h, buf)
但总是出现如下错误:
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: xcb_io.c:165: dequeue_pending_request: Zusicherung »!xcb_xlib_unknown_req_in_deq« nicht erfüllt.
编辑:
这是一个完整的工作演示脚本,显示了问题:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import wx
import random
import time
import threading
class TestWin(wx.Window):
def __init__(self, parent, title, size):
wx.Window.__init__(self, parent)
self.Bind(wx.EVT_PAINT, self.onPaint)
self.Bind(wx.EVT_TIMER, self.onTimer)
t=threading.Thread(target=self.asThread, name="draw")
t.setDaemon(True)
t.start()
self.timer=wx.Timer(self)
self.timer.Start(100)
def onPaint(self, evt):
dc=wx.PaintDC(self)
dc.SetPen(wx.Pen("BLACK"))
dc.SetBrush(wx.Brush("BLUE"))
w, h=self.GetSize()
dc.DrawCirclePoint((random.randint(0, w), random.randint(0, h)), 5)
def onTimer(self, evt):
self.Refresh()
def asThread(self):
w, h=self.GetSize()
bmpbuf=wx.EmptyBitmapRGBA(w, h, 204, 204, 204, 1)
mdc=wx.MemoryDC()
mdc.SelectObject(bmpbuf)
time.sleep(1)
mdc.SetPen(wx.Pen("BLACK"))
mdc.SetBrush(wx.Brush("RED"))
print "now writing to MemoryDC"
while True:
#time.sleep(0.0001)
mdc.DrawCirclePoint((random.randint(0, w), random.randint(0, h)), 5)
wx.Yield()
class TestFrame(wx.Frame):
def __init__(self, parent, title, size):
wx.Frame.__init__(self, None, wx.ID_ANY, title)
win=TestWin(self, title, size)
if __name__=="__main__":
app=wx.App(False)
frame=TestFrame(None, "Test", size=(200, 200))
frame.Show()
app.MainLoop()
EDIT2: 为什么我要在线程中构建位图:
我有一个 class 为给定的 window 大小、缩放级别和 lat/lon-coordinate 提供位图(显示 OpenStreetMap-tiles)。
class 还将 GPS 轨迹和点列表绘制到 map/bitmap 上。
因为位图的尺寸高于 window 尺寸,所以我可以将位图移动到 window 下,而无需构建新的位图。
为了移动位图,调用 dc.DrawBitmap(imgbuf, sx, sy) 并稍微改变 (sx, sy) 的值。每个新剪辑需要 0.1 毫秒。构建新位图最多需要 150 毫秒。
当从一个位置滚动到另一个位置时,滚动非常平滑,直到需要新的位图。
如果可以准备新的位图,在 old 位图上滚动时,应该可以在长距离上连续平滑滚动。
你不应该(在大多数情况下,不能)从主 UI 线程以外的任何地方操作 UI 对象。这包括 DC 和位图。你到底想完成什么?可能还有其他方法可以做到这一点。