Tkinter Text widget getting too slow

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jane Austine

    Tkinter Text widget getting too slow

    As you add more items, say text lines, in Text widget, it gets too
    slow and almost impractical to use on. Take idle for example. If the
    text gets bigger(e.g. print
    urllib.urlopen( 'http://www.amazon.com' ).read() ), it becomes too
    sluggish to use as an "interactiv e" shell.

    I have tried wxPython and it seems to have the same problem (from my
    experience using PyCrust).

    Is there any way to speed up Text widget, or should I look for another
    GUI library?

    Jane
  • Peter Otten

    #2
    Re: Tkinter Text widget getting too slow

    Jane Austine wrote:
    [color=blue]
    > As you add more items, say text lines, in Text widget, it gets too
    > slow and almost impractical to use on. Take idle for example. If the
    > text gets bigger(e.g. print
    > urllib.urlopen( 'http://www.amazon.com' ).read() ), it becomes too
    > sluggish to use as an "interactiv e" shell.
    >
    > I have tried wxPython and it seems to have the same problem (from my
    > experience using PyCrust).
    >
    > Is there any way to speed up Text widget, or should I look for another
    > GUI library?
    >
    > Jane[/color]

    Does the same problem appear if you read a file of the same size from your
    harddisk or is it just the web site that does not respond fast enough?

    In this case you could put urlopen() into a separate thread.

    Peter

    Comment

    • Michael Peuser

      #3
      Re: Tkinter Text widget getting too slow


      "Jane Austine" <janeaustine50@ hotmail.com> schrieb im Newsbeitrag
      news:ba1e306f.0 309030713.ef2ec 4a@posting.goog le.com...[color=blue]
      > As you add more items, say text lines, in Text widget, it gets too
      > slow and almost impractical to use on. Take idle for example. If the
      > text gets bigger(e.g. print
      > urllib.urlopen( 'http://www.amazon.com' ).read() ), it becomes too
      > sluggish to use as an "interactiv e" shell.
      >
      > I have tried wxPython and it seems to have the same problem (from my
      > experience using PyCrust).
      >
      > Is there any way to speed up Text widget, or should I look for another
      > GUI library?[/color]

      This seems to be a problem with most naivly written wigdets which store
      their data in some internal format. What I have done several times is
      writing my own widgets. This is possible for Tkinter by using Fredrik
      Lundh's WCK (Widget Construction Kit)

      He has some tutorials and the whole thing is well integrated in Tkinter. He
      especially has a tutorial on using HUGE datasets.

      Of course you have to undergo some programming for all the features you
      would want to use in your text widget. (Highliting, linebreaks,..et c)

      I implemented a binary editor some time ago, which is extremely fast with
      even a 100 MB file. (For I/O it used memory mapped files, but this is not
      the reason it is fast; it just simplified the programmin :-))

      Kindly
      Michael P



      Comment

      • Changjune Kim

        #4
        Re: Tkinter Text widget getting too slow


        "Jane Austine" <janeaustine50@ hotmail.com> wrote in message
        news:ba1e306f.0 309030713.ef2ec 4a@posting.goog le.com...[color=blue]
        > As you add more items, say text lines, in Text widget, it gets too
        > slow and almost impractical to use on. Take idle for example. If the
        > text gets bigger(e.g. print
        > urllib.urlopen( 'http://www.amazon.com' ).read() ), it becomes too
        > sluggish to use as an "interactiv e" shell.
        >
        > I have tried wxPython and it seems to have the same problem (from my
        > experience using PyCrust).
        >
        > Is there any way to speed up Text widget, or should I look for another
        > GUI library?
        >
        > Jane[/color]

        Yes, it gets real slow. It happens quite often when a long single line is
        shown on the window currently, like in your amazon html example.

        Try this instead,

        pprint(urllib.u rlopen('http://www.amazon.com' ).readlines())

        It won't get slow even when it's still on the screen; it inserts multiple
        (short) lines. If you have to insert a lot of long lines, maybe you have to
        look into WCK and customize it as Michael said in his posting to the
        thread. (I'm interested to see his "extremely fast" text widget, too)

        Best regards,

        June Kim





        Comment

        • John J. Lee

          #5
          Re: Tkinter Text widget getting too slow

          janeaustine50@h otmail.com (Jane Austine) writes:
          [color=blue]
          > As you add more items, say text lines, in Text widget, it gets too
          > slow and almost impractical to use on. Take idle for example. If the
          > text gets bigger(e.g. print[/color]
          [...]
          [color=blue]
          > Is there any way to speed up Text widget, or should I look for another
          > GUI library?[/color]

          I'm surprised that you're having trouble with it, actually, but:

          How about something like Scintilla? I'm not sure about wx and Tk, but
          Scintilla is available for GTk and Qt, IIRC (the latter is a port,
          called QScintilla). There might well be something similar for wx or
          Tk. Or maybe the standard Qt or GTk text widgets are themselves more
          scalable than their wx or Tk counterparts -- no idea.

          If you specifically want a Python shell, I think eric3 uses
          QScintilla, so there should be code in there you can use.


          John

          Comment

          • Neil Hodgson

            #6
            Re: Tkinter Text widget getting too slow

            John J. Lee:
            [color=blue]
            > How about something like Scintilla?[/color]

            The original poster had tried PyCrust which uses the wxWindows port of
            Scintilla wxStyledTextCtr l. The design centre for Scintilla is editing
            source code files and its assumptions are incorrect for very large documents
            or very wide documents. The performance of Scintilla is dependent on how it
            is used as much as its design and it can be sped up greatly by turning off
            styling and word wrap.

            Neil


            Comment

            • Michael Peuser

              #7
              Re: Tkinter Text widget getting too slow


              "Christos TZOTZIOY Georgiou" <tzot@sil-tec.gr> schrieb im Newsbeitrag
              news:eoselvguf3 hvie3s95kjndhtu no0jiu09s@4ax.c om...[color=blue]
              > On Thu, 4 Sep 2003 03:15:16 +0900, rumours say that "Changjune Kim"
              > <juneaftn@REMOV ETHIShanmail.ne t> might have written:
              >[color=green]
              > >(I'm interested to see his "extremely fast" text widget, too)[/color]
              >
              > Notice that Michael Peuser described an "extremely fast" "binary
              > editor"; I assume a dual view (hex / chars) one. This is not a text
              > widget --you don't have to account for line feeds and variable width
              > characters :)[/color]

              Exactly! Most of the time of general text edit or table widgets stays in
              .font.measure()
              You will get an immediate speed up if you use fixed size fonts and just use
              the string length for computations. I am looking for a postable short
              version of my editor (I remember I started with something less 100 lines. It
              grew of course ;-) Maybe I even should install a nice homepage - if I had
              the time...

              Kindly
              Michael P



              Comment

              • Michael Peuser

                #8
                Re: Tkinter Text widget getting too slow


                "Christos TZOTZIOY Georgiou" <tzot@sil-tec.gr> schrieb im Newsbeitrag
                news:eoselvguf3 hvie3s95kjndhtu no0jiu09s@4ax.c om...[color=blue]
                > On Thu, 4 Sep 2003 03:15:16 +0900, rumours say that "Changjune Kim"
                > <juneaftn@REMOV ETHIShanmail.ne t> might have written:
                >[color=green]
                > >(I'm interested to see his "extremely fast" text widget, too)[/color]
                >
                > Notice that Michael Peuser described an "extremely fast" "binary
                > editor"; I assume a dual view (hex / chars) one. This is not a text
                > widget --you don't have to account for line feeds and variable width
                > characters :)[/color]

                Well I have somthing a little bit over 100 lines; I removed the editor part
                but that is straight forward.
                No scaling to size up to 1 GB.
                -----------------------------------
                # wckhwex by Michael Peuser May-2003
                # Using some ideas from F. Lundh (WCK)
                # This is Open Source. I will be happy if it could help somebody.

                versionString=" wckhex 0.3 by mpeuser.de"
                from __future__ import division

                from Tkinter import *
                from WCK import Widget, EventMixin
                from tkFileDialog import askopenfile
                import mmap

                class HexView(EventMi xin, Widget):
                """Displays HUGE binary file using memory mapped files
                """

                aCols=10 # address field
                bCols=2.5*16+1 # binary field
                cCols=16+1 # ascii field

                ui_takefocus=1
                ui_doublebuffer =0

                def __init__(self,r oot, buffer=None):
                self.buffer=buf fer
                self.defLines=( len(buffer)+15)//16
                self.firstLine= 0 # numer of first line in window
                self.oldFirst=-1 # .. compared to last time
                self.visLines=1 # visible lines in window
                self.pix=None # pixmap will be created on resize

                self.ui_init(ro ot)
                self.vscroll=Sc rolls(self,orie nt=VERTICAL)
                self.vscroll.pa ck(side=RIGHT,f ill=Y)

                self.pack(side= TOP,fill=BOTH,e xpand=1)
                self.font=self. ui_font(0,"Cour ier 10")
                (self.cWidth, self.lHeight) = self.font.measu re("X")

                def ui_handle_resiz e(self, width, height):

                self.height=hei ght
                self.width= max(width,
                (self.aCols+1+s elf.bCols+1+sel f.cCols)*self.c Width) #
                pixel
                self.visLines=s elf.height//self.lHeight
                self.pix=self.u i_pixmap(self.w idth, self.height)
                self.vscroll.do Scroll() # compute new thumb
                self.drawPix()

                def ui_handle_clear (*whatever):
                pass # no need for clear as is pixmap long enough

                def ui_handle_repai r(self, draw, x0, y0, x1, y1):
                #if self.pix:
                draw.paste(self .pix)

                def onclick(self, ev):
                self.focus_set( )
                if ev.num==1:
                pass #XXX implement editor here
                if ev.num==3:
                pop=Menu(self,t earoff=0);
                pop.add_command (label=versionS tring,state=DIS ABLED)
                pop.post(ev.x+s elf.winfo_rootx (),ev.y+self.wi nfo_rooty())

                def onkey(self, event):
                todo ={'Down': ("scroll",1,"li nes"), 'Up': ('scroll',-1,'lines'),
                'Next': ("scroll",1,"pa ges"), 'Prior':('scrol l',-1,'pages')}
                x=todo.get(even t.keysym)
                print x
                if x: self.vscroll.do Scroll(*x)

                def bgText(self,x,y ,w,h,text,theBr ush):
                "Displays centered text with background color"
                self.pix.rectan gle((x+1,y+1,x+ w-2,y+h-2),theBrush)
                (tw,th)=self.pi x.textsize(text ,self.font)
                self.pix.text(( x+(w-tw)/2,y+(h-th)/2),text,self.fo nt)

                def drawPix(self,un changedSize=0):
                "Central dawing routine"
                c=self.pix
                repair=None
                whiteBrush=self .ui_brush(0xfff fff)
                yellowBrush=sel f.ui_brush(0xff ff99)
                grayPen=self.ui _pen(0x999999,2 )
                ww,wh = self.ui_size()
                h=self.lHeight
                posX = 0

                # speed up scrolling by image blitting, but unclean parametrisation of paste
                if unchangedSize: ## check if blitting
                useful
                linesTBS = self.oldFirst-self.firstLine ## TBS = to be scrolled
                if 0 < linesTBS < self.visLines/2: ## down, repair top
                c.paste(c,(0, h*linesTBS))
                theRange=range( 1,linesTBS+1)
                c.rectangle((0, h,ww,(linesTBS+ 1)*h),whiteBrus h)
                c.rectangle((0, h,self.aCols*se lf.cWidth,(line sTBS+1)*h),
                yellowBrush)
                elif 0 < -linesTBS < self.visLines/2: ## up, repair bottom
                c.paste(c,(0, h*linesTBS))
                delta=self.visL ines+linesTBS
                theRange=range( delta-1,self.visLines )
                c.rectangle((0, delta*h, ww, wh),whiteBrush)
                c.rectangle((0, delta*h, self.aCols*self .cWidth, wh),
                yellowBrush)
                else:
                unchangedSize=0 # blitting would not make much
                improvement...
                self.oldFirst=s elf.firstLine # remember first line for
                next time
                # end of blitting optimization

                if not unchangedSize: # all new
                c.rectangle((0, 0,ww,wh),whiteB rush)
                theRange=range( 1, self.visLines)
                c.rectangle((0, h,self.aCols*se lf.cWidth,wh), yellowBrush)

                for w, text in \

                ((self.aCols,"a ddress"),(self. bCols,"hex"),(s elf.cCols,"asci i")):
                w *= self.cWidth
                if repair!='T':
                self.bgText(pos X, 0, w, h, text, yellowBrush)
                c.line((posX - 1, 0, posX - 1, wh -1), grayPen)
                posX+=w

                # addresses and data
                posY = self.lHeight
                for y in theRange:
                posX = 0
                heightY = self.lHeight
                address=(y-1+self.firstLin e)*16
                vals = self.buffer[address:address +16]
                c.text((posX,y* self.lHeight),
                "%3x.%05x " % divmod(address, 1024*1024), self.font)
                posX += self.aCols*self .cWidth

                for vala in range(address,a ddress+16):
                if vala %8==0: posX+=self.cWid th//2 # some in between
                space
                if vala<len(buffer ):
                c.text((posX,
                y*heightY),"%02 x"%ord(buffe r[vala]),self.font)
                posX += 2.5*self.cWidth

                c.text((posX+10 ,y*heightY),buf fer[address:address +16],self.font)
                self.ui_damage( )
                self.focus_set( )

                class Scrolls(Scrollb ar):
                "wrapper around Tk scrolbars"
                def __init__(self,f rame,orient=Non e,**kw):
                Scrollbar.__ini t__(self,frame, orient=orient,c ommand=self.doS croll)
                self.visible=1 # start packed
                self.theMaster= frame

                def doScroll(self,a =None,b=None,c= None):
                m=self.theMaste r
                oldfirst=m.firs tLine
                if a=="scroll":
                if c=='pages': b=int(b)*m.visL ines-1
                m.firstLine = oldfirst+int(b)
                elif a=="moveto":
                m.firstLine=int (float(b)*(m.de fLines+1))
                if m.firstLine+m.v isLines>m.defLi nes: # the end
                m.firstLine=m.d efLines-m.visLines+1
                if m.firstLine<0:
                m.firstLine=0
                size = m.visLines/m.defLines # 0...1
                start= m.firstLine/m.defLines # 0...1
                if self.visible: self.set(start, start+size)
                if oldfirst != m.firstLine: m.drawPix(uncha ngedSize=1)

                if __name__ == "__main__":
                root=Tk()
                root.iconify()
                fbb=askopenfile ("r+"); assert fbb, "No file"
                buffer=mmap.mma p(fbb.fileno(), 0)

                s=HexView(root, buffer=buffer)

                root.title("%s (%6.3f MB)" %(fbb.name, len(buffer)/1024/1024))
                root.geometry(" 720x550+10+10")
                root.deiconify( )
                root.mainloop()
                fbb.close()
                # the End




                Comment

                Working...