如何在 curses 的文本框中添加滚动?

How to add scrolling in a textbox in curses?

目前,当我们到达文本框区域的末尾时,我们只是移动到框外的下一行。我如何实现滚动,以便当我们到达末尾并尝试移动到下一行时,顶行消失并且整个文本正文向上移动?

例如:

+-------+
|hello1 |
|hello2 |
|hello3 |
|hello4 |
|hello5 |
+-------+

按回车后:-

+-------+
|hello2 |
|hello3 |
|hello4 |
|hello5 |
|       |
+-------+

这是代码,我知道 curses 的文本板,但它不是我需要的。

import curses
from curses import textpad
import time

class notepad:
    def __init__(self, stdscr, topleft, bottomright, starttext = ""):
        self.topleft = topleft
        self.bottomright = bottomright
        self.stdscr = stdscr
        self.text = starttext
        self.curspos = 0

    def box(self):
        curses.textpad.rectangle(self.stdscr, self.topleft[0], self.topleft[1], self.bottomright[0], self.bottomright[1])

    def get_input(self, key):

        if not key == -1:

            if key == curses.KEY_LEFT:
                self.curspos -= 1

            elif key == curses.KEY_RIGHT:
                if self.curspos < len(self.text):
                    self.curspos += 1

            elif key == curses.KEY_UP:
                self.curspos -= self.width

            elif key == curses.KEY_DOWN:
                if self.curspos//self.width < len(self.text)//self.width:
                    self.curspos += self.width - (self.curspos%self.width - len(self.text)%self.width)

            elif key == curses.KEY_BACKSPACE:
                self.text = self.text[:self.curspos][:-1] + self.text[self.curspos:]
                self.curspos -= 1

            elif key == curses.KEY_ENTER or key == 10 or key == 13:
                self.text = self.text[:self.curspos] + " "*(self.width - (len(self.text[:self.curspos])%self.width)) + self.text[self.curspos:]
                self.curspos += 1
                self.curspos += self.width - (self.curspos%self.width - len(self.text)%self.width)

            else:
                self.text = self.text[:self.curspos] + chr(key) + self.text[self.curspos:]
                self.curspos += 1

    def display(self):
        self.width = (self.bottomright[1]-1) - (self.topleft[1]+1)

        if self.curspos < 0:
            self.curspos = 0


        #disply text
        for i in range(len(self.text)):
            self.stdscr.addstr( self.topleft[0]+1 + (i//self.width) , 
                                self.topleft[1]+1 +i%self.width  , 
                                self.text[i]
                                )
            
        #display fake cursor
        if self.curspos < len(self.text):
            self.stdscr.addstr(self.topleft[0]+1 + (self.curspos//self.width) , self.topleft[1]+1 + self.curspos%self.width, self.text[self.curspos], curses.A_REVERSE)
        else:
            self.stdscr.addstr(self.topleft[0]+1 + (self.curspos//self.width) , self.topleft[1]+1 + self.curspos%self.width, " ", curses.A_REVERSE)
        
def main():
    run = True
    stdscr = curses.initscr()
    stdscr.nodelay(True)
    stdscr.keypad(True)
    curses.curs_set(False)
    curses.start_color()
    curses.noecho()
    curses.cbreak()

    notepad1 = notepad(stdscr, [0,0], [20, 30])

    try:
        while run:
            start = time.time()

            stdscr.erase()

            key = stdscr.getch()

            notepad1.box()
            notepad1.get_input(key)
            notepad1.display()

            stdscr.refresh()


            time.sleep(max(0.05 - (time.time() - start), 0))
    finally:
        curses.echo()
        curses.nocbreak()
        curses.curs_set(True)
        stdscr.keypad(False)
        stdscr.nodelay(False)
        curses.endwin()

main()

既然你评论说你想保留文本但将其滚动到屏幕之外,你需要在你的初始化中这样的东西:

self.scroll_lines = 0

然后当你想向下滚动一行时,只需使用:

 self.scroll_lines += 1

你的显示函数看起来像这样:

 #disply text
 text_offset = self.scroll_lines*self.width
 for i in range(text_offset, len(self.text)):
        self.stdscr.addstr( self.topleft[0]+1 + (i//self.width-self.scroll_lines) , 
                            self.topleft[1]+1 +i%self.width  , 
                            self.text[i]
                            )

我将把它留作练习,供您正确放置光标。