1

I am currently playing with some cmd/prompt animations/graphics:

import os
import time

def printFrame(timeout, count):
    os.system('cls')
    l=0
    while True:
        for k in range(0,9):
            for i in range(0,9):
                for j in range(0,9):
                    if j == k and i != 4:
                        print("|", end="", flush=True)
                    elif j !=k and i == 4:
                        print("-", end="", flush=True)
                    elif j ==k and i == 4:
                        print("+", end="", flush=True)
                    else:
                        print("O", end="", flush=True)
                print("")
            time.sleep(timeout)
            os.system('cls')
        l += 1
        if l > count:
            break

if __name__ == "__main__":
    printFrame(0.08, 2)

and i want to get rid of frame blinking - especialy visible in first line, my idea was to use second printing thread:

def printFrame(timeout, count):
#print from example1

def printFrameTwo(timeout, count):
#print from example1 without os.system('cls')

if __name__ == "__main__":
    p1 = threading.Thread(target = printFrame, args = (0.08, 2))
    p2 = threading.Thread(target = printFrameTwo, args = (0.08, 2))
    p1.start()
    p2.start()

but the effect was rather disappointing - problems with synchronization and first line still very blinky, second idea was to use 'predefined frames' - but its not very educating - the bonus here is that I can print whole line at once, but still effect is not as expected, third (most promising) idea is to only change necessary 'pixels'/chars in frame - but here I need to move in frame between lines! and curses is not working on windows (at least not in standard). Do you maybe have some ideas how to bite it? (windows, standard libraries) maybe how to speed up 'os.system('cls')'?

hegelsturm
  • 71
  • 1
  • 6

1 Answers1

-1

I figured it out... You can use ANSI codes to move the cursor then clear the lines without any BLINK!

print('\033[4A\033[2K', end='')

\033[4A Moves the cursor 4 lines up (\033[{lines}A you can replace lines with however many you need) \033[2K Clears all those lines without the screen blinking. You can use it in a simple typewrite function that needs a constant message or a box around it like this:

from time import sleep   

def typewrite(text: str):
    lines = text.split('\n')
    for line in lines:
        display = ''
        for char in line:
            display += char
            print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
            print(f'│ {display:74} │') # :74 is the same as ' ' * 74
            print(f'╰────────────────────────────────────────────────────────────────────────────╯')
            
            sleep(0.05)
            
            print('\033[3A\033[2K', end='')

The only problem with this is that the top line is blinking. To fix this all we need to do is to add a empty line that is blinking so the user cant see it. We also move the cursor up from 3 to 4 lines.

def typewrite(text: str):
    lines = text.split('\n')
    for line in lines:
        display = ''
        for char in line:
            display += char
            print('')
            print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
            print(f'│ {display:74} │') # :74 is the same as ' ' * 74
            print(f'╰────────────────────────────────────────────────────────────────────────────╯')
            
            sleep(0.05)
            
            print('\033[4A\033[2K', end='')

To make this into your code just print your text and add a print('') at the start. Then use this print('\033[4A\033[2K', end='') but change the 4 to however many lines that you printed including the print(''). Then it should work without blinking. You can put print('\033[4B', end='') at the end which just moves the cursor back up.

If you want to hide the cursor you can use this gibberish or make the cursor the same color as the background:

import ctypes

if os.name == 'nt':
    class _CursorInfo(ctypes.Structure):
        _fields_ = [("size", ctypes.c_int),
                    ("visible", ctypes.c_byte)]
def hide_cursor() -> None:
    if os.name == 'nt':
        ci = _CursorInfo()
        handle = ctypes.windll.kernel32.GetStdHandle(-11)
        ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
        ci.visible = False
        ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
def show_cursor() -> None:
    if os.name == 'nt':
        ci = _CursorInfo()
        handle = ctypes.windll.kernel32.GetStdHandle(-11)
        ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
        ci.visible = True
        ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))

Note: All of this is still new to me so I am still testing this out to fully understand it.

  • 1
    Welcome to Stack Overflow. [Please don't post](https://meta.stackexchange.com/q/104227/248627) the [same](https://stackoverflow.com/a/73396379/354577) [answer](https://stackoverflow.com/a/73396206/354577) [multiple](https://stackoverflow.com/a/73396032/354577) times. – ChrisGPT was on strike Aug 21 '22 at 18:50