Hi, it's me again and i have new question:


This is my code:

# -*- coding: cp1250 -*-

import  string as _string
import  time as _time
import  wx
from math import*


class Canvas:
    def __init__(self,parent):
        self.okno=parent
        self.okno.SetBackgroundColour("#FCFCFE")
        self.radic = wx.FlexGridSizer(2,2,0,0)
        self.canvas = wx.ScrolledWindow(self.okno, -1)
       
        self.canvas.EnableScrolling(True, True)
        
        
        self.P_WIDTH = 1000
        self.P_HEIGHT = 1000
        self.canvas.SetScrollbars(20, 20, self.P_WIDTH/20, self.P_HEIGHT/20)

        self.radic.Add(self.canvas, 1, wx.EXPAND)
        self.radic.Add((0,0))
        sizer=wx.BoxSizer(wx.VERTICAL)
        self.radic.Add(sizer, 1, wx.EXPAND)
        self.radic.Add((0,0))
        self.radic.AddGrowableRow(0, 1)
        self.radic.AddGrowableCol(0, 1)
        sizer2=wx.BoxSizer(wx.HORIZONTAL)
        sizer2.Add(wx.StaticText(self.okno,label="  f(y)=   "),0,wx.ALIGN_CENTER)
        self.vstup=wx.TextCtrl(self.okno)
        sizer2.Add(self.vstup,1,0,wx.ALL)
        sizer.Add(sizer2,0,wx.EXPAND)
        sizer3=wx.BoxSizer(wx.HORIZONTAL)
        button1=wx.Button(self.okno,label="Show")
        sizer3.Add(button1,0,wx.ALIGN_RIGHT)
        sizer.Add(sizer3,0,wx.EXPAND)
        ##
        self.canvas.SetCursor(wx.CROSS_CURSOR)
        self.canvas.Bind(wx.EVT_PAINT, self.OnPaint)
        self.okno.SetSizer(self.radic)
        button1.Bind(wx.EVT_BUTTON,lambda e:self.vykresli())
        self.body=[(0,0,0,0)]
        self.pocet=0
        self.dc=False
    def vykresli(self):
        l=[]
        for prvek in self.vstup.GetValue().split(','):
            l.append(int(prvek))
        self.body=l
        self.dc.BeginDrawing()
        self.dc.DrawLineList([l])
        self.dc.EndDrawing()
    def OnPaint(self, evt):
        self.dc=wx.PaintDC(self.canvas)
        self.dc.BeginDrawing()
        self.dc.DrawLineList(self.body)
        self.dc.EndDrawing()
if __name__ == "__main__":
    okno = wx.App(0)
    parent=wx.MDIParentFrame(None,size=wx.Size(500,500))
    child=wx.MDIChildFrame(parent,title="Graf",id=-1)
    Canvas(child)
    child.Maximize()
    parent.Show()
    okno.MainLoop()

if i write in entry for example 4,5,4,40 than will becreated line at this coordinates. But if i press button Show, the line is showed, but i get some error. Do you can tell me please what i am doing bad?

Well, try to write in entry coordinates "4,4,40,40" and press Show. There will create onle line, but i will get error:

TypeError: Expected a sequence of (x1,y1, x1,y2) sequences.
Traceback (most recent call last):
  File "C:\Documents and Settings\Blu\Plocha\MaRoWx\graf_zkouska.py", line 140,
in OnPaint
    self.dc.DrawLineList(self.body)
  File "C:\Python24\lib\site-packages\wx-2.6-msw-unicode\wx\_gdi.py", line 4100,
 in DrawLineList
    return self._DrawLineList(lines, pens, [])
  File "C:\Python24\lib\site-packages\wx-2.6-msw-unicode\wx\_gdi.py", line 4042,
 in _DrawLineList
    return _gdi_.DC__DrawLineList(*args, **kwargs)

OK, buddy, you owe me one :) Just kidding; I'm learning wxPython, and it was helpful to work through the code.

Comments about your code:

(1) The reason it crashed and printed multiple error messages, I *think*, was that you were passing non-tuples to DrawLines.

And, if you are using IDLE and get an error while working with wxPython -- you may not get your system back. The error messages just kept scrolling down the screen, and I had to restart twice.:-O

(2) In general, the code had a lot of unneeded stuff. BeginDrawing() and EndDrawing() are listed in the docs as doing nothing and are deprecated. The two separate paint methods (vykresli, OnPaint) were muddling the picture. I wasn't able to find a use for the Add((0,0)) calls.

(3) I recommend having all of your widgets be members of the parent class. That way, you can refer to them as needed in the code. See below for examples.

(4) jste cech?

Anyways, here's a working version:

import wx

class MyFrame(wx.Frame):

    PENS = ['blue','red','green','black','purple']
    
    def __init__(self,parent=None,id=wx.ID_ANY,title="Line Drawer"):
        wx.Frame.__init__(self, parent, id, title)

        
        self.sizer = wx.FlexGridSizer(2,2,0,0)

        # Add canvas
        self.canvas = wx.ScrolledWindow(self, id=wx.ID_ANY)
        self.canvas.EnableScrolling(True, True)
        self.P_WIDTH = 1000
        self.P_HEIGHT = 1000
        self.canvas.SetScrollbars(20, 20, self.P_WIDTH/20, self.P_HEIGHT/20)
        self.sizer.Add(self.canvas, 1, wx.EXPAND)

        # Pad spacing to sizer
        self.pad_sizer=wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.pad_sizer, 1, wx.EXPAND)

        self.sizer.AddGrowableRow(0, 1)
        self.sizer.AddGrowableCol(0, 1)

        # Add text entry
        self.text_sizer=wx.BoxSizer(wx.HORIZONTAL)
        self.text_sizer.Add(wx.StaticText(self,label="  f(y)=   "),0,wx.ALIGN_CENTER)
        self.entry=wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER)
        self.text_sizer.Add(self.entry,1,0,wx.ALL)
        self.sizer.Add(self.text_sizer,0,wx.EXPAND)

        # Add button
        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.button1=wx.Button(self,label="Show")
        self.button_sizer.Add(self.button1,0,wx.ALIGN_RIGHT)
        self.sizer.Add(self.button_sizer,0,wx.EXPAND)

        self.SetSizer(self.sizer)

        # housekeeping
        self.lines = []
        self.button1.Bind(wx.EVT_BUTTON,self.OnClick,self.button1)
        #self.entry.Bind(wx.EVT_COMMAND_ENTER,self.OnClick,self.entry) # <--- This doesn't work correctly.  TO-DO: make TextCtrl respond to <Enter>.
        self.canvas.Bind(wx.EVT_PAINT, self.OnPaint)
       
        
        
    def OnPaint(self, event):
        dc = wx.PaintDC(self.canvas)

        # This does different colors.
        for line_no in range(len(self.lines)):
            
            dc.SetPen(wx.Pen(self.PENS[line_no % len(self.PENS)],1))
            dc.DrawLine(*self.lines[line_no])

        # If you want all one color, use this instead:
        # dc.SetPen('black',1)
        # for line in self.lines:
        #    dc.DrawLine(*line)
        
    def OnClick(self, event=None):
        text = self.entry.GetValue()
        coords = text.split(',')
        try:
            x0,y0,x1,y1 = [int(x) for x in coords]
        except:
            return
        else:
            self.lines.append((x0,y0,x1,y1))
        self.canvas.Refresh()  # <-- The key to getting the drawing to work.
        
if __name__ == "__main__":

    app = wx.PySimpleApp()  # <-- much easier than MDIParentFrame...
    app.frame = MyFrame()
    app.frame.Show()
    app.MainLoop()

Hope it helps,
Jeff

well, thanks a lot. it works fine now and i can finish my program...
I was using MDIParentFrame, because this is part of bigger application;)


btw, jsem čech;)
A tak ještě jednou díky moc!

and i have another question. i tryed to find on web some manual on canas, but i failed. If you know any, please post here. I am trying to find answer on some thing, like "is possible to zoom canvas with some function, or i must write my own function?"

thanks a lot...

omg, i found another problem. If i sroll canvas, is called functin OnPaint and all objects are redraw. If you have there 2 lines, its no problem, but if you have there around milion lines, each redraw takes several seconds......
For exapmle, same program in Tkinter is faster. I thought, that wx is waster then Tkinter, so i think there is some way to draw lines a scroll it without redrawing. Do you know how to solve it?


Thanks a lot...

I know generally how to solve it, but not specifically in wxPython (yet).

Basically, the OnPaint needs to distinguish between dirty and not-dirty: if you've drawn new lines since the last OnPaint, the canvas is dirty and has to be redrawn. If not, then you just need to blit the right area of the canvas onto the display screen.

That's the basic idea, but I'm not sure how to implement it specifically in wxPython. Let us know when you find out!

Jeff

This question has already been answered. Start a new discussion instead.