2015-05-27 3 views
0

У меня есть следующий простой код (щелкните по розовому боксу, и вы можете перемещать его с помощью мыши, удерживая левую кнопку мыши).wxPython Paint Damaged, Обрезанная область

import wx 


class AppPanel(wx.Panel): 

    def __init__(self, parent, id): 
     wx.Panel.__init__(self, parent, id) 
     p = MovablePanel(self, -1) 
     self.i = 0 
     self.Bind(wx.EVT_PAINT, self.OnPaint, self) 

    def OnPaint(self, event): 
     dc = wx.PaintDC(self) 
     self.i = self.i+10 
     c = self.i % 255 
     c = (0, 0, c) 
     dc.SetPen(wx.Pen(c)) 
     dc.SetBrush(wx.Brush(c)) 
     dc.DrawRectangle(0, 0, 10000,10000) 





class MovablePanel(wx.Panel): 

    def __init__(self, parent, id): 
     wx.Panel.__init__(self, parent, id) 
     self.SetMinSize((500,500)) 
     self.SetSize((500,500)) 
     self.SetBackgroundColour("PINK") 
     self.LEFT_DOWN = False 
     self.Bind(wx.EVT_MOTION, self.OnMove, self) 

     self.Bind(wx.EVT_LEFT_DOWN, 
         self.OnClickDown, 
         self) 


     self.Bind(wx.EVT_LEFT_UP, 
         self.OnClickUp, 
         self) 

    def OnClickUp(self, event): 
     self.LEFT_DOWN = False 
     self.Refresh() 

    def OnClickDown(self, event):  
     self.LEFT_DOWN = True 
     self.Refresh() 

    def OnMove(self, event): 
     if self.LEFT_DOWN: 
      p = self.GetTopLevelParent().ScreenToClient(wx.GetMousePosition()) 
      self.SetPosition(p) 


if __name__ == "__main__": 
    app = wx.App(False) 
    f = wx.Frame(None, -1, size = (700, 700)) 
    p = AppPanel(f, -1) 
    f.Show() 
    f.Maximize() 
    app.MainLoop() 

и предполагают, чтобы выглядеть следующим образом (просто изменить размер кадра)

Normal background

Однако после перемещения розового прямоугольника вокруг вы увидите, что на самом деле выглядит следующим образом

Bad Background with ghosting

Я пробовал следующие

dc.Clear() 

dc.DestroyClippingRegion() 

wx.FULL_REPAINT_ON_RESIZE 

wx.EVT_ERASE_BACKGROUND 

Я уверен, что это связано с тем, что это панель, и поэтому PaintEvent лишь частично ее повреждает. Эта часть окрашена по-разному, что делает «ореолом» или «размазыванием» очевидным. Возможно, я использую неправильные слова, потому что мне не удалось найти решение (и мне кажется, что это непростая проблема, связанная с «поврежденным» регионом).

ответ

0

Хорошо, я нашел проблему, но я постараюсь опубликовать более подробную информацию позже.

В основном цель этого кода - перемещать панель вокруг и затем обновлять родительскую панель. Вызовы SetPosition Перемещение, проходящее через код wxWidget, вызывает DoMoveWindow, все это приводит к изменению позиции и перерисовке (не уверен, что вызывает перерисовку). Отлично. Однако перерисовка отмечает только определенную «область», поскольку она пытается быть эффективной. Вот почему некоторые проблемы можно решить, если панель перейдет в область «призрак». Что вам нужно сделать, это после SetPosition, вызвать GetParent(). Refresh(), который отправит «полную» краску без какой-либо исключенной области.

Еще одна вещь, которую следует отметить, - это два условия для этой «поврежденной» или «обрезанной» области. Один из них - «ущерб», однако есть и другой, «грязный». Повреждение используется в WX PaintDC информации

Использование wx.PaintDC обработчиков EVT_PAINT важна, поскольку она автоматически устанавливает область отсечения в области окна повреждения. Попытки выйти за пределы этой области не появляются.

Доверяя документацию, вы будете в основном потеряны. Однако в одном из wxPython DoubleBuffer, как изменяется лингво (но это то же самое, что и «урон»)

Теперь метод OnPaint(). Он называется всякий раз, когда это событие боли , отправленное системой: т. Е. Когда часть окна получает грязный.

Зная это, если вы Google WX окна грязные, вы получите следующее

Марк указанный прямоугольник (или все окно) «грязный» так будет перекрашен. Вызывает событие EVT_PAINT, которое должно быть сгенерировано и отправлено в окно.

Возьмите следующие три цикла печати, где EVT_PAINT был уволен после SetPosition вызова (это БЕЗ GetParent(). Refresh() вызов)

# first EVT_PAINT 
Drawing 
Panel Size (1440, 851) 
Clipping Rect (0, 0, 1440, 851) 
Client Update Rect (x=0, y=6, w=500, h=501) # the only place getting update is 
              # directly below the panel 
              # (that is (500, 500)) 

# second 
Drawing 
Panel Size (1440, 851) 
Clipping Rect (0, 0, 1440, 851) 
Client Update Rect (x=0, y=6, w=910, h=845) # however this time the update area is                                
              # bigger, this is also right before 
              # the move 
              # i believe what it is doing is 
              # drawing from (0,6) to (910, 851) 
              # why? because the panel is moving to 
              # (410, 390) and the bottom right 
              # corner of the panel (after moved) 
              # is (410+500, 390+461) = (910, 851) 
              # or about where the edge of the panel 
              # will be 

# third 
Drawing 
Panel Size (1440, 851) 
Clipping Rect (0, 0, 1440, 851) 
Client Update Rect (x=410, y=390, w=500, h=461) 

Вот код обновления поиграем, надеюсь, это поможет другим.

import wx 

instructions = """ 
How to use. 
1) Hover your mouse over the pink panel. 
2) Click down (left click) 
3) While holding down drag mouse around 
4) Release mouse button to stop. 

""" 

class AppPanel(wx.Panel): 

    def __init__(self, parent, id): 
     wx.Panel.__init__(self, parent, id) 
     self.sizer = wx.BoxSizer(wx.VERTICAL) 
     self.settings_sizer = wx.BoxSizer(wx.HORIZONTAL) 
     p = MovablePanel(self, -1) 

     self.c = wx.CheckBox(self, -1, label = "Ghosting On?") 
     self.p = p 
     self.i = 0 

     self.settings_sizer.Add(self.c) 

     self.sizer.Add(self.settings_sizer) 
     self.sizer.Add(self.p) 
     self.SetSizer(self.sizer) 
     self.Layout() 

     self.Bind(wx.EVT_CHECKBOX, self.OnCheck, self.c) 
     self.Bind(wx.EVT_PAINT, self.OnPaint, self) 
     self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase, self) 


    def OnCheck(self, event): 
     print "CHECK\n\n\n\n\n" 
     v = self.c.GetValue() 
     self.p.r = v 
     print v 


    def OnErase(self, event): 
     pass 

    def OnPaint(self, event): 
     print "Drawing" 
     dc = wx.PaintDC(self) 
     print "Panel Rect, ", self.p.GetPosition(), 
     print self.p.GetSize() 
     print "Clipping Rect", dc.GetClippingBox() 
     print "Client Update Rect", self.GetUpdateClientRect() 
     print "----------------------------" 
     self.i = self.i+10 
     c = self.i % 255 
     c = (0, 0, c) 
     dc.SetPen(wx.Pen(c)) 
     dc.SetBrush(wx.Brush(c)) 

     dc.DrawRectangle(0, 0, 10000,10000) 
     self.SetBackgroundColour(c) 

     dc.SetPen(wx.Pen("WHITE")) 
     dc.SetBrush(wx.Brush("WHITE")) 


     dc.DrawRectangle(0, 0, self.GetSize()[0], self.c.GetSize()[1]) 





class MovablePanel(wx.Panel): 

    def __init__(self, parent, id): 
     wx.Panel.__init__(self, parent, id) 
     self.SetMinSize((300,300)) 
     self.SetSize((300,300)) 

     txt = wx.StaticText(self, -1, label = "CLICK AND DRAG ME!") 
     inst = wx.StaticText(self, -1, label = instructions) 

     font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD) 
     txt.SetFont(font) 
     inst.SetFont(font) 

     sizer = wx.BoxSizer(wx.VERTICAL) 
     sizer.Add(txt, flag = wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_CENTRE_HORIZONTAL) 
     sizer.Add(inst, flag = wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_CENTRE_HORIZONTAL) 
     self.SetSizer(sizer) 

     self.SetBackgroundColour("PINK") 
     self.LEFT_DOWN = False 
     self.r = False 
     self.Bind(wx.EVT_MOTION, self.OnMove, self) 

     self.Bind(wx.EVT_LEFT_DOWN, 
         self.OnClickDown, 
         self) 


     self.Bind(wx.EVT_LEFT_UP, 
         self.OnClickUp, 
         self) 

    def OnClickUp(self, event): 
     self.LEFT_DOWN = False 
     self.Refresh() 

    def OnClickDown(self, event):  
     self.LEFT_DOWN = True 
     self.Refresh() 

    def OnMove(self, event): 
     if self.LEFT_DOWN: 
      p = self.GetTopLevelParent().ScreenToClient(wx.GetMousePosition()) 
      self.SetPosition(p) 
      if not self.r: 
       self.GetParent().Refresh() 


if __name__ == "__main__": 
    app = wx.App(False) 
    f = wx.Frame(None, -1, size = (700, 700)) 
    p = AppPanel(f, -1) 
    f.Show() 
    app.MainLoop()