Search code examples
pythonuser-interfaceterminalcursespython-curses

Terminal with each line after another + some fixed text as well


I'd like to have both:

  • Lines displayed each one after another (Blah 12, Blah 13, Blah 14, etc.) like in a normal terminal

  • Fixed position information (on right) : Date + fixed text "Bonjour"

It nearly works, until ~ Blah 250, when the look is destroyed! Why?


(source: gget.it)

from sys import stdout
import time

ESC = "\x1b"
CSI = ESC+"["

def movePos(row, col):
    stdout.write("%s%d;%dH" % (CSI, row, col))
  
stdout.write("%s2J" % CSI)      # CLEAR SCREEN

for i in range(1,1000):
    movePos(i+1,60)
    print time.strftime('%H:%M:%S', time.gmtime())
    movePos(i+5,60)
    print 'Bonjour'

    movePos(24+i,0)
    print "Blah %i" % i
    time.sleep(0.01)

With an ANSI terminal, how to have both normal terminal behaviour (one new line for each print) + fixed position display?

Note: On Windows, I use ansicon.exe to have ANSI support in Windows cmd.exe.


Solution

  • Here is a solution:


    (source: gget.it)

    The code is (check here for latest version):

    """
    zeroterm is a light weight terminal allowing both:
    * lines written one after another (normal terminal/console behaviour)
    * fixed position text
    
    Note: Requires an ANSI terminal. For Windows 7, please download https://github.com/downloads/adoxa/ansicon/ansi160.zip and run ansicon.exe -i to install it.
    """
    
    from sys import stdout
    import time
    
    class zeroterm:
        def __init__(self, nrow=24, ncol=50):      # nrow, ncol determines the size of the scrolling (=normal terminal behaviour) part of the screen
            stdout.write("\x1b[2J")                # clear screen
            self.nrow = nrow
            self.ncol = ncol
            self.buf = []
    
        def write(self, s, x=None, y=None):        # if no x,y specified, normal console behaviour
            if x is not None and y is not None:    # if x,y specified, fixed text position
                self.movepos(x,y)
                print s
            else:
                if len(self.buf) < self.nrow:
                    self.buf.append(s)
                else:
                    self.buf[:-1] = self.buf[1:]
                    self.buf[-1] = s
    
                for i, r in enumerate(self.buf):
                    self.movepos(i+1,0)
                    print r[:self.ncol].ljust(self.ncol)
    
        def movepos(self, row, col):
            stdout.write("\x1b[%d;%dH" % (row, col))
    
    
    if __name__ == '__main__':
        # An exemple
        t = zeroterm()
        t.write('zeroterm', 1, 60)
    
        for i in range(1000):
            t.write(time.strftime("%H:%M:%S"), 3, 60)
            t.write("Hello %i" % i)
            time.sleep(0.1)