0

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.

Community
  • 1
  • 1
Basj
  • 41,386
  • 99
  • 383
  • 673
  • I think curses is the recommended way to do this (not that that answers your specific question) – Joran Beasley Dec 20 '15 at 21:52
  • I can't make `curses` working on Windows. I tried many examples found here and there, but none of them were working on Win7. If you have a worked example, I'm interested! – Basj Dec 20 '15 at 21:57
  • Did you see the [hint in the docs](https://docs.python.org/3/howto/curses.html#what-is-curses): `The Windows version of Python doesn’t include the curses module. A ported version called UniCurses is available. You could also try the Console module written by Fredrik Lundh, which doesn’t use the same API as curses but provides cursor-addressable text output and full support for mouse and keyboard input.` – albert Dec 20 '15 at 21:59
  • Do you need to have a multi-platform support? What do you want to do as your long-term objective. If multi-platform support is a must I would take some considerations about writing something like the desired terminal using tkinter... – albert Dec 20 '15 at 22:01
  • @albert if we do it with ANSI commands `\x1b` etc. it should work on all terminals supporting ANSI – Basj Dec 20 '15 at 22:39

2 Answers2

1

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)
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Basj
  • 41,386
  • 99
  • 383
  • 673
0

From the given picture: ansicon appears to be allocating a console buffer to do its work; that has a limited size (due to the Windows console, which limits the buffer size to 64 kilobytes). Once your script reaches the end of the buffer and tries to move the cursor past the end, ansicon forces the whole buffer to scroll up. That makes the style of update change.

If your calls to movePos were bounded within ansicon's workspace, you would get more consistent results.

Regarding the "multiple lines" for "Bonjour", this chunk

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

is printing the date on one line, and then moving forward 4 lines, printing "Bonjour" on the same column. It seems that there's enough space (10 columns) on the same line to do this:

movePos(i+1,60)
print time.strftime('%H:%M:%S', time.gmtime())
movePos(i+1,70)
print 'Bonjour'

which would at least make the text on the right look consistent. The scrolling from movePos will cause some double-spacing at times though.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • Thanks. More generally, do you have an idea for writing the lines (Blah 11, Blah 12, etc.) like a normal `print` + fixed position text at certain places? – Basj Dec 21 '15 at 10:18