How do you draw on client (wx.ClientDC) using wx.GCDC for alpha channel

Windows Vista box

Python 2.7.2

wxPython 2.8.12.0

Looking at the wxPython demo for Alpha Drawing I thought I could adapt my code to include a to use the wx.GCDC so I could use the alpha channel for blending my drawing with the background and other elements.

In the demo the wx.GCDC is built in the OnPaint method which is bound to the EVT_PAINT event. When I do this I get funky artifacts and the program breaks.

If I just use the wx.ClientDC everything works great (except there is no alpha element which would be nice.)

When I do it, nothing “breaks” perse’… Just nothing draws on the client so I was under the impression GCDC only works with wx.PaintDC or I’m just not doing something right.

Could someone show me a way (if possible) to use the wx.ClientDC and wx.GCDC together?

Hi Steve,

Windows Vista box

Python 2.7.2

wxPython 2.8.12.0

Looking at the wxPython demo for Alpha Drawing I thought I could adapt my code to include a to use the wx.GCDC so I could use the alpha channel for blending my drawing with the background and other elements.

In the demo the wx.GCDC is built in the OnPaint method which is bound to the EVT_PAINT event. When I do this I get funky artifacts and the program breaks.

If I just use the wx.ClientDC everything works great (except there is no alpha element which would be nice.)

You don’t explain how things break. My guess is that at least part of the issue is that you want to use wx.AutoBufferedPaintDC instead of wx.PaintDC, though.

When I do it, nothing “breaks” perse’… Just nothing draws on the client so I was under the impression GCDC only works with wx.PaintDC or I’m just not doing something right.

Could someone show me a way (if possible) to use the wx.ClientDC and wx.GCDC together?

It’s doubtful that wx.GCDC has been well-tested with wx.ClientDC, wx.ClientDC is made for a few special cases where you want to draw something over your UI temporarily (like a selection rect), and is not for drawing your program’s primary UI.

Regards,

Kevin

···

On Mar 11, 2012, at 10:36 PM, Steve Freedenburg wrote:

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

Did you remove the EVT_PAINT handler? If so then it is probably repainting the default window content (the background) over whatever you drew with the client DC.

Please make a small runnable sample that shows what you are trying to do so we can see what is going wrong. MakingSampleApps - wxPyWiki

···

On 3/11/12 10:36 PM, Steve Freedenburg wrote:

Windows Vista box
Python 2.7.2
wxPython 2.8.12.0

Looking at the wxPython demo for Alpha Drawing I thought I could adapt
my code to include a to use the wx.GCDC so I could use the alpha channel
for blending my drawing with the background and other elements.

In the demo the wx.GCDC is built in the OnPaint method which is bound to
the EVT_PAINT event. When I do this I get funky artifacts and the
program breaks.
If I just use the wx.ClientDC everything works great (except there is no
alpha element which would be nice.)

When I do it, nothing "breaks" perse'... Just nothing draws on the
client so I was under the impression GCDC only works with wx.PaintDC or
I'm just not doing something right.

Could someone show me a way (if possible) to use the wx.ClientDC and
wx.GCDC together?

--
Robin Dunn
Software Craftsman

Working on making the sample app now… should have it posted shortly. Trying to add worth while comments as well.

BTW, Thanks so much for being polite and gracious hosts. I know it can be hard to tolerate the novice.

I Read Andrea’s reply about using a thread for GUI manipulation. If I can do what I want to do in the main thread and not lock up the GUI in the mean time that would be great, but I’m shooting for some type of “animation” on a mouse over, and I’d like those animations to have an alpha channel.

I’ve come a long way from where I first started, but I am aware I have much farther to go before I can call myself anything other than a novice. Thanks in advance!

Code below.

import wx

import time

import thread

import wx.lib.inspection

print wx.version()

Thread that color changing boxes around the event object on the client.

This works.

class MouseOverThread:

def init(self, EventObj, DC):

self.EventObj = EventObj

self.DC = DC

def Start(self):

self.Working = self.running = True

thread.start_new_thread(self.Run, ())

def Stop(self):

self.Working = False

def IsRunning(self):

return self.running

def Run(self):

while self.Working:

self.ObjSize = self.EventObj.GetSize()

self.ObjPos = self.EventObj.GetPosition()

RGB = [(0, 255, 255), (0, 200, 255), (0, 150, 255), (0, 100, 255), (0, 50, 255), (0, 0, 255)]

for Color in RGB:

R, G, B = Color

self.DC.SetPen(wx.Pen(wx.Colour(R, G, B)))

LConstX = self.ObjPos[0] - 1

LStartY = self.ObjPos[1]

LEndY = self.ObjPos[1] + self.ObjSize[1]

self.DC.DrawLine(LConstX, LStartY, LConstX, LEndY)

RConstX = self.ObjPos[0] + self.ObjSize[0]

RStartY = self.ObjPos[1]

REndY = self.ObjPos[1] + self.ObjSize[1]

self.DC.DrawLine(RConstX, RStartY, RConstX, REndY)

TStartX = self.ObjPos[0] - 1

TEndX = self.ObjPos[0] + self.ObjSize[0] + 1

TConstY = self.ObjPos[1] - 1

self.DC.DrawLine(TStartX, TConstY, TEndX, TConstY)

BStartX = self.ObjPos[0] - 1

BEndX = self.ObjPos[0] + self.ObjSize[0] + 1

BConstY = self.ObjPos[1] + self.ObjSize[1]

self.DC.DrawLine(BStartX, BConstY, BEndX, BConstY)

time.sleep(0.05)

LConstX = self.ObjPos[0] - 2

LStartY = self.ObjPos[1] - 1

LEndY = self.ObjPos[1] + self.ObjSize[1] + 1

self.DC.DrawLine(LConstX, LStartY, LConstX, LEndY)

RConstX = self.ObjPos[0] + self.ObjSize[0] + 1

RStartY = self.ObjPos[1] - 1

REndY = self.ObjPos[1] + self.ObjSize[1] + 1

self.DC.DrawLine(RConstX, RStartY, RConstX, REndY)

TStartX = self.ObjPos[0] - 2

TEndX = self.ObjPos[0] + self.ObjSize[0] + 2

TConstY = self.ObjPos[1] - 2

self.DC.DrawLine(TStartX, TConstY, TEndX, TConstY)

BStartX = self.ObjPos[0] - 2

BEndX = self.ObjPos[0] + self.ObjSize[0] + 2

BConstY = self.ObjPos[1] + self.ObjSize[1] + 1

self.DC.DrawLine(BStartX, BConstY, BEndX, BConstY)

time.sleep(0.05)

LConstX = self.ObjPos[0] - 3

LStartY = self.ObjPos[1] - 2

LEndY = self.ObjPos[1] + self.ObjSize[1] + 2

self.DC.DrawLine(LConstX, LStartY, LConstX, LEndY)

RConstX = self.ObjPos[0] + self.ObjSize[0] + 2

RStartY = self.ObjPos[1] - 2

REndY = self.ObjPos[1] + self.ObjSize[1] + 2

self.DC.DrawLine(RConstX, RStartY, RConstX, REndY)

TStartX = self.ObjPos[0] - 3

TEndX = self.ObjPos[0] + self.ObjSize[0] + 3

TConstY = self.ObjPos[1] - 3

self.DC.DrawLine(TStartX, TConstY, TEndX, TConstY)

BStartX = self.ObjPos[0] - 3

BEndX = self.ObjPos[0] + self.ObjSize[0] + 3

BConstY = self.ObjPos[1] + self.ObjSize[1] + 2

self.DC.DrawLine(BStartX, BConstY, BEndX, BConstY)

time.sleep(0.05)

self.running = False

class BasePanel(wx.Panel):

def init(self, parent):

wx.Panel.init(self, parent, -1)

self.SetBackgroundColour(“yellow”)

self.GP = self.GetParent()

self.DC = wx.ClientDC(self)

wx.StaticText(self, -1, “Hover over a button to trigger the EVT_ENTER_WINDOW event.”, (10, 10))

wx.StaticText(self, -1, “The event starts a thread that paints colored boxes on the”,(10, 30))

wx.StaticText(self, -1, “client, but around the event object no matter it’s position”,(10, 50))

wx.StaticText(self, -1, “or size. Leave the window to trigger the EVT_LEAVE_WINDOW”, (10,70))

wx.StaticText(self, -1, “even. This stops the thread.”, (10, 90))

wx.StaticText(self, -1, “Help on making the exact same thing happen but with a GCDC”, (10, 130))

wx.StaticText(self, -1, “so the colored boxes can have an alpha channel would be great!”, (10, 150))

TestButton1 = wx.Button(self, -1, “Thanks”, (40,200))

TestButton2 = wx.Button(self, -1, “For The”, (130,200))

TestButton3 = wx.Button(self, -1, “Help!!!”, (220,200))

TestButton1.Bind(wx.EVT_ENTER_WINDOW, self.OnWindowEnter)

TestButton1.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)

TestButton2.Bind(wx.EVT_ENTER_WINDOW, self.OnWindowEnter)

TestButton2.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)

TestButton3.Bind(wx.EVT_ENTER_WINDOW, self.OnWindowEnter)

TestButton3.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)

def OnGUIThreadStop(self):

self.Refresh()

self.t.Stop()

running = 1

while running:

running = 0

running = running + self.t.IsRunning()

time.sleep(0.05)

def OnWindowEnter(self, event):

self.EventObj = event.GetEventObject()

self.t = MouseOverThread(self.EventObj, self.DC)

self.t.Start()

def OnWindowLeave(self, event):

self.OnGUIThreadStop()

def OnCloseWindowClick(self, event):

self.OnGUIThreadStop()

self.GP.Close()

def OnMinimizeWindowClick(self, event):

self.GP.Iconize(True)

class BaseFrame(wx.Frame):

def init(self):

wx.Frame.init(self, None, -1, “wx.ClientDC test.py”, size=(350,300), pos=(100,100))

self.BP = BasePanel(self)

wx.lib.inspection.InspectionTool().Show()

class SomaApp(wx.App):

def OnInit(self):

BF = BaseFrame()

BF.Show(True)

return True

App = SomaApp(False)

App.MainLoop()

For animation it is best to forget about using threads and simply use a timer. Each iteration of the animation is performed in a single timer event handler, and then you wait until the next timer event to do the next iteration of the animation "loop". That keeps all UI interactions in the main thread and still allows other events to be processed between the animation iterations.

A basic flow could be something like this:

1. Something happens in the UI that you want to trigger some animation
2. Do any setup code needed, like getting/saving any parameters needed for the animation.
3. Start() the timer
4. In the EVT_TIMER handler do one iteration of your animation loop
5. Setup for the next iteration of the animation loop if needed
6. If the animation is finished then Stop() the timer.
7. Return from the EVT_TIMER handler.

Depending on the platform and the nature of the animation it may be best to not do any drawing at all in the timer handler, but rather just change state as needed and then do a Refresh(rect=SomeRectangle) and then do the drawing in the EVT_PAINT handler.

···

On 3/12/12 5:22 PM, Steve Freedenburg wrote:

    I Read Andrea's reply about using a thread for GUI manipulation. If
    I can do what I want to do in the main thread and not lock up the
    GUI in the mean time that would be great, but I'm shooting for some
    type of "animation" on a mouse over, and I'd like those animations
    to have an alpha channel.

I've come a long way from where I first started, but I am aware I have
much farther to go before I can call myself anything other than a
novice. Thanks in advance!

--
Robin Dunn
Software Craftsman

A few extra notes:

In the demo the wx.GCDC is built in the OnPaint method which is bound to the
EVT_PAINT event. When I do this I get funky artifacts and the program
breaks.
If I just use the wx.ClientDC everything works great (except there is no
alpha element which would be nice.)

As Kevin mentioned, this isn't what wx.ClientDC is meant for. You may
find that it works well on Windows, but it could work really badly on
OS-X (and maybe GTK?) and perhaps even newer versions of Windows.

And I've been able to use wxGCDC just fine in Paint handlers, so there
is probably something else wrong.

Please make a small runnable sample that shows what you are trying to do
so we can see what is going wrong.
MakingSampleApps - wxPyWiki

you sent a sample, but;

- it wasn't nearly as small as it should be.
- it's better to enclose the code, rather than pasting into your email
-- email clinets can make a mess of Pyhton code.

the goal is to make it really, really easy for us to download, test
and debug your example -- in this case, I took one look, and decided
it was going to be too much effort to bother -- though I did notice
the use of threads, which as Robin pointed out is probably not worth
it (if it's even possible). But in any case, you seem to mixing issues
here:

- using GCDC to do your main drawing
- animation

I'd get the first one working first.

-Chris

···

On Sun, Mar 11, 2012 at 10:36 PM, Steve Freedenburg <stevefreedenburg@gmail.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov