dc.DrawLine and transparent background

22 views
Skip to first unread message

Twiggy Sticks

unread,
Apr 28, 2012, 9:15:17 AM4/28/12
to wxPython-dev
Hi,
Im trying to make a program where the user can draw on a transparent
frame and dc, which creates the effect of drawing on the desktop.
However the dc's DrawLine method seems to also draw a filled
rectangle around the line which is an image of the desktop showing
behind the line, so when the frame is moved, so does the line and
image.
At the moment, I am using a custom line drawing algorithm which draws
many squares in the line, this method is very inefficient.
Is there any way of making the backgrounds of things drawn on a dc
transparent like the rest of the dc?
Here is an example of what i mean:

import wx
import math

class OverlayFrame(wx.Frame):
"""This is the transparent frame that overlays the application and
recieves mouse input when painting (application feature) is enabled
and sends it to the DC for display."""
def __init__(self, parent):
self.last_pos = wx.Point(0, 0)

wx.Frame.__init__(self, parent, title = "", size = (1000,
1000), style = wx.CLIP_CHILDREN | wx.CLIP_CHILDREN | wx.NO_BORDER |
wx.FULL_REPAINT_ON_RESIZE)

self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown )
self.Bind(wx.EVT_MOTION, self.OnMotion )
self.Bind(wx.EVT_PAINT, self.OnPaint )

self.Show(True)
def OnEraseBackground(self, event):
pass
def OnLeftDown(self, event):
self.DrawLine(event.GetPosition().x, event.GetPosition().y,
event.GetPosition().x + 1, event.GetPosition().y + 1, self.dc)

self.last_pos.x = event.GetPosition().x
self.last_pos.y = event.GetPosition().y
event.Skip()
def OnMotion(self, event):
if event.Dragging():
self.DrawLine(self.last_pos.x, self.last_pos.y,
event.GetPosition().x, event.GetPosition().y, self.dc)
self.last_pos.x = event.GetPosition().x
self.last_pos.y = event.GetPosition().y
event.Skip()
def OnPaint(self, event):
self.dc_initial = wx.PaintDC(self)
self.dc = wx.GCDC(self.dc_initial)

self.dc.SetBrush(wx.Brush(wx.Colour(0, 255, 1)))
self.dc.SetPen(wx.Pen(wx.Colour(0, 255, 0), 1))

self.dc.DrawLine(0, 0, 250, 250)


self.SetPosition((500, 500))

def DrawLine(self, x1, y1, x2, y2, dc):
"""For every x value, the y value is mx."""
thickness = 2

run = x2 - x1
rise = y2 - y1

if run != 0:
gradient = float(rise) / float(run)
for i in range(0, run):
dc.GetGraphicsContext().DrawRectangle(i + x1,
int(round(i * gradient)) + y1, thickness, thickness)
else: #Gradient is infinite (vertical line)
if y1 < y2: #Line is moving down
for i in range(y1 , y2):
dc.GetGraphicsContext().DrawRectangle(x1, i,
thickness, thickness)
elif y2 < y1: #Line is moving up
for i in range(y1, y2, -1):
dc.GetGraphicsContext().DrawRectangle(x1, i,
thickness, thickness)

class MyApp(wx.App):
def OnInit(self):
self.frame = OverlayFrame(None)
return True

if __name__ == "__main__":
app = MyApp()
app.MainLoop()

Robin Dunn

unread,
Apr 29, 2012, 12:15:09 PM4/29/12
to wxpyth...@googlegroups.com
On 4/28/12 6:15 AM, Twiggy Sticks wrote:
> Hi,
> Im trying to make a program where the user can draw on a transparent
> frame and dc, which creates the effect of drawing on the desktop.
> However the dc's DrawLine method seems to also draw a filled
> rectangle around the line which is an image of the desktop showing
> behind the line, so when the frame is moved, so does the line and
> image.
> At the moment, I am using a custom line drawing algorithm which draws
> many squares in the line, this method is very inefficient.
> Is there any way of making the backgrounds of things drawn on a dc
> transparent like the rest of the dc?

A transparent window is more than simply not drawing the background. In
your example the background still exists, it is simply not initialized
to anything and so it takes on what was already on the screen at that
position. And when you move the frame its background moves with it like
usual, and when you draw with anti-aliasing then it is blended with what
it thinks is in the background for that location.

To get a truly transparent frame you can either set the translucency of
the frame, or you can set the shape of the frame. Unfortunately the
first option means that your lines will have the same translucency, and
the second option means that you will not get mouse events for the
transparent areas.

There probably is a way to get what you want, but unfortunately it is
not coming to mind at the moment.

--
Robin Dunn
Software Craftsman
http://wxPython.org

Reply all
Reply to author
Forward
0 new messages