Canvas drawing problems

I have tried to draw into wx.lib.plot canvas and I got now some problems to
solve :slight_smile:

In my example left mouse button will draw rectangle, the rectangle will be
drawn onto plot.canvas using wx.ClientDC(), the problem here is that now
when I resize the application, plot will be drawn again over the rectangle.
I should maybe use wx.PaintDC with EVT_PAINT but I did not get it to work,
so in my example I include code with wx.ClientDC without EVT_PAINT.

Mouse motion will draw two lines onto wx.Screen just above cursor (that's
actually tracing crosshair in my app, but didn't want to include too much
code in my example so I did make it much simplier). Ofcourse when the
crosshair is drawn again, previous crosshair must be erased, but now when
erasing the previous crosshair using self.RefreshRect(rect_area), the
refreshing will also erase the rectangle which was drawn
(http://tinypic.com/view.php?pic=vn03k1&s=4), the refreshrect seem to behave
like evt_paint only in smaller area, so moving the rectangle into
plot.canvas EVT_PAINT could also solve this problem? Or would it be possible
to take "screenshot" of the area and then using that area somehow with the
refreshrect...

I would need two layers for drawing which would be put on plot.canvas, also
drawing directly to plot.canvas (like I'm already drawing the rectangle)
could be another solution.

To make it simple: I have two problems which I would like to solve
1. drawing the rectangle so that it won't be erased when resizing windows
(using evt_paint maybe?)
2. crosshair (no, not the cursor) erases drawed rectangle when it refresh
the screen using refreshrect, see http://tinypic.com/view.php?pic=vn03k1&s=4

my code: http://pastebin.com/m29371fc
and also below:

import wx
import wx.lib.plot as plot

class MyFrame(wx.Frame):
聽聽聽def __init__(self):
聽聽聽聽聽聽wx.Frame.__init__(self, None, id=-1, title="Graph display",
size=(480,300))
聽聽聽聽聽聽main_panel = wx.Panel(self, -1)

聽聽聽聽聽聽#data for the plot
聽聽聽聽聽聽data = [[1,2],[2,0],[3,1],[4,3],[5,2]]
聽聽聽聽聽聽line = plot.PolyLine(data, colour='red', width=1)

聽聽聽聽聽聽#plot window & bindings
聽聽聽聽聽聽self.plot_window = plot.PlotCanvas(main_panel, -1)
聽聽聽聽聽聽gc = plot.PlotGraphics([line], 'y-axis', 'x-axis', 'Title')
聽聽聽聽聽聽self.plot_window.Draw(gc)
聽聽聽聽聽聽self.plot_window.canvas.Bind(wx.EVT_LEFT_DOWN, self.mouseleftdown)
聽聽聽聽聽聽self.plot_window.canvas.Bind(wx.EVT_MOTION, self.mousemotion)

聽聽聽聽聽聽#sizer & layouts
聽聽聽聽聽聽vbox_sizer = wx.BoxSizer(wx.VERTICAL)
聽聽聽聽聽聽vbox_sizer.Add(self.plot_window, 1, wx.EXPAND|wx.ALIGN_LEFT)
聽聽聽聽聽聽main_panel.SetAutoLayout(True)
聽聽聽聽聽聽main_panel.SetSizer(vbox_sizer)
聽聽聽聽聽聽main_panel.Layout()

聽聽聽def mouseleftdown(self, event):
聽聽聽聽聽聽x, y = event.GetPosition()
聽聽聽聽聽聽print "Left Mouse Down at Point:", x, y

聽聽聽聽聽聽pdc = wx.ClientDC( self.plot_window.canvas )
聽聽聽聽聽聽try: dc = wx.GCDC(pdc)
聽聽聽聽聽聽except: dc = pdc

聽聽聽聽聽聽#rectangle
聽聽聽聽聽聽rect = wx.Rect(x,y, 150, 150)

聽聽聽聽聽聽#pencil & brush - rectangle color
聽聽聽聽聽聽r, g, b = (34, 34, 178)
聽聽聽聽聽聽penclr = wx.Colour(r, g, b, wx.ALPHA_OPAQUE)
聽聽聽聽聽聽brushclr = wx.Colour(r, g, b, 128)
聽聽聽聽聽聽dc.SetPen(wx.Pen(penclr))
聽聽聽聽聽聽dc.SetBrush(wx.Brush(brushclr))
聽聽聽聽聽聽
聽聽聽聽聽聽#drawing the rectangel
聽聽聽聽聽聽dc.DrawRectangleRect(rect)

聽聽聽def mousemotion(self, event):
聽聽聽聽聽聽point_x, point_y = event.GetPosition()
聽聽聽聽聽聽print "Right Mouse Down at Point:", point_x, point_y

聽聽聽聽聽聽#converts to screen coordinates because we're drawing to screendc
聽聽聽聽聽聽point_x, point_y = self.ClientToScreenXY(point_x, point_y)

聽聽聽聽聽聽#showing the drawn object above cursor so this example doesn't look
too confusing
聽聽聽聽聽聽point_y -= 100

聽聽聽聽聽聽#clearing the screen where the crosshair was previously located
聽聽聽聽聽聽try:
聽聽聽聽聽聽聽聽聽self.RefreshRect(self.last_drawn_crosshair)
聽聽聽聽聽聽聽聽聽self.Update()
聽聽聽聽聽聽except:
聽聽聽聽聽聽聽聽聽pass

聽聽聽聽聽聽dc = wx.ScreenDC()
聽聽聽聽聽聽pen = wx.Pen('#000000', 1, wx.SOLID)
聽聽聽聽聽聽pen.SetCap(wx.CAP_BUTT)
聽聽聽聽聽聽dc.SetPen(pen)

聽聽聽聽聽聽#drawing two lines, " a crosshair"
聽聽聽聽聽聽size = 10
聽聽聽聽聽聽dc.DrawLine(point_x-size, point_y, point_x+size, point_y)
聽聽聽聽聽聽dc.DrawLine(point_x, point_y-size, point_x, point_y+size)

聽聽聽聽聽聽#remember the area where the lines was drawn, so we can clear the area
next time
聽聽聽聽聽聽#converting coordinates back to client coords, because the refreshing
needs client coords.
聽聽聽聽聽聽point_x, point_y = self.plot_window.ScreenToClientXY(point_x, point_y)
聽聽聽聽聽聽self.last_drawn_crosshair = wx.Rect(point_x-size,point_y-size, size*2,
size*2)

app = wx.PySimpleApp()
MyFrame().Show()
app.MainLoop()

路路路

--
View this message in context: http://www.nabble.com/Canvas-drawing-problems-tp20262194p20262194.html
Sent from the wxPython-users mailing list archive at Nabble.com.

so...I added EVT_PAINT to my plot and now the crosshair drawing is also
erasing the plot picture :o
you can add these 3lines to code to see its effect:

self.plot_window.canvas.Bind(wx.EVT_PAINT, self.onpaint)

def onpaint(self, event):
聽聽聽dc = wx.PaintDC(event.GetEventObject())

路路路

--
View this message in context: http://www.nabble.com/Canvas-drawing-problems-tp20262194p20262634.html
Sent from the wxPython-users mailing list archive at Nabble.com.

Have you read these wiki pages:

http://wiki.wxpython.org/RecipesImagesAndGraphics

They may help you out.

But the broader question is: What are you trying to do? building it on wx.lib.plot may not be the best choice.

wx.lib.floatcanvas may be a better option, or even just doing it all yourself with DCs or GCs

-Chris

路路路

--
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

kewlar wrote:

I have tried to draw into wx.lib.plot canvas and I got now some problems to
solve :slight_smile:

In my example left mouse button will draw rectangle, the rectangle will be
drawn onto plot.canvas using wx.ClientDC(), the problem here is that now
when I resize the application, plot will be drawn again over the rectangle.
I should maybe use wx.PaintDC with EVT_PAINT but I did not get it to work,
so in my example I include code with wx.ClientDC without EVT_PAINT.

Mouse motion will draw two lines onto wx.Screen just above cursor (that's
actually tracing crosshair in my app, but didn't want to include too much
code in my example so I did make it much simplier). Ofcourse when the
crosshair is drawn again, previous crosshair must be erased, but now when
erasing the previous crosshair using self.RefreshRect(rect_area), the
refreshing will also erase the rectangle which was drawn
(http://tinypic.com/view.php?pic=vn03k1&s=4), the refreshrect seem to behave
like evt_paint only in smaller area,

Correct. It actually results in a EVT_PAINT event with the given rectangle (and any others since the last EVT_PAINT) used for the update region, which means that drawing in that paint event will be clipped to that region.

so moving the rectangle into
plot.canvas EVT_PAINT could also solve this problem? Or would it be possible
to take "screenshot" of the area and then using that area somehow with the
refreshrect...

Looking at PlotCanvas.OnPaint I see that it is using a buffered Dc, so all you should need to do is to draw your stuff on to the self._Buffer bitmap and then do a RefreshRect to get PlotCanvas to paint it. If needed you can force PllotCanvas to reinitialize its buffer by calling SendSizeEvent.

路路路

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

Looking at PlotCanvas.OnPaint I see that it is using a buffered Dc, so
all you should need to do is to draw your stuff on to the self._Buffer
bitmap and then do a RefreshRect to get PlotCanvas to paint it. If
needed you can force PllotCanvas to reinitialize its buffer by calling
SendSizeEvent.

thx, drawing to self._Buffer with dc.MemoryDC solved my problem :slight_smile:

路路路

--
View this message in context: http://www.nabble.com/Canvas-drawing-problems-tp20262194p20298460.html
Sent from the wxPython-users mailing list archive at Nabble.com.