Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何并行绘制PaintDC和MemoryDC?_Multithreading_Wxpython_Gdi - Fatal编程技术网

Multithreading 如何并行绘制PaintDC和MemoryDC?

Multithreading 如何并行绘制PaintDC和MemoryDC?,multithreading,wxpython,gdi,Multithreading,Wxpython,Gdi,我正在寻找一段代码,如何并行使用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.d

我正在寻找一段代码,如何并行使用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:为什么要在线程中构建位图:
我有一个类为给定的窗口大小、缩放级别和lat/lon坐标提供位图(显示OpenStreetMap分幅)。 该类还将在地图/位图上绘制GPS轨迹和点列表。 因为位图的尺寸高于窗口尺寸,所以我可以在窗口下移动位图,而无需构建新位图。 要移动位图,将调用dc.DrawBitmap(imgbuf,sx,sy),并稍微更改(sx,sy)的值。每个新剪辑需要0.1ms。创建新位图最多需要150毫秒。
从一个位置滚动到另一个位置时,它会非常平滑地滚动,直到需要新的位图为止。

如果可以在滚动旧位图的同时准备新位图,则可以在长距离上连续平滑滚动。

您不应该(在大多数情况下,不能)从主UI线程以外的任何位置操作UI对象。这包括DC和位图。你到底想完成什么?可能还有其他方法可以做到这一点。

似乎正在使用wxpython 4.0.0a参见我的编辑2……非常欢迎使用“其他方法”来平滑滚动动态创建的位图序列。如果您使用numpy数组获取和构建图像数据,则可以在工作线程上完成这一部分。转换为位图显示需要在GUI线程上进行。我尝试的一种方法是使用一些较小的位图,而不是一个较大的位图,并使用缓存在内存中保留一些N个最近使用的位图。然后,当滚动到一个边缘时,你可以使用线程获取数据,然后在EVT_空闲事件或类似事件中转换为位图,然后将它们添加到缓存中,以便它们在需要时等待EVT_绘制。好主意……我也有这个想法……使用numpy和枕头而不是wx运行我的类。也可以通过这种方式绘制地图和点列表。但是对于轨迹,我需要在位图上画线。在Python中每像素的绘制速度太慢了(我猜)。我现在已经重写了我的类,用枕头来绘制所有的图形。只需要调用一个wx函数:wx.BitmapFromBuffer(w,h,self.v[handle].bmpbuf.tostring())。