Search code examples
pythonncursescurses

How to make text fit inside a python curses textbox?


I've tried many things attempting to make the text stay inside its borders but I can't find a way. Below is what I've already tried.

#!/usr/bin/env python

import curses
import textwrap

screen = curses.initscr()
screen.immedok(True)

try:
    screen.border(0)

    box1 = curses.newwin(20, 40, 6, 50)
    box1.immedok(True)
    text = "I want all of this text to stay inside its box. Why does it keep going outside its borders?"
    box1.box()
    box1.addstr(1, 0, textwrap.fill(text, 39))

    #box1.addstr("Hello World of Curses!")

    screen.getch()

finally:
    curses.endwin()

Solution

  • Your first problem is that calling box1.box() takes up space in your box. It uses up the top row, the bottom row, the first column, and the last column. When you use box1.addstr() to put a string in a box, it starts at col 0, row 0, and so overwrites the box characters. After creating your borders, your box only has 38 available characters per line.

    I'm not a curses expert, but one way of resolving this is to create a new box inside box1 that is inset by one character all the way around. That is:

    box2 = curses.newwin(18,38,7,51)
    

    Then you can write your text into that box without overwriting the box drawing characters in box1. It's also not necessary to call textwrap.fill; it appears that writing a string to a window with addstr automatically wraps the text. In fact, calling textwrap.fill can interact badly with the window: if text wrap breaks a line at exactly the window width, you may end up with an erroneous blank line in your output.

    Given the following code:

    try:
        screen.border(0)
    
        box1 = curses.newwin(20, 40, 6, 50)
        box2 = curses.newwin(18,38,7,51)
        box1.immedok(True)
        box2.immedok(True)
        text = "I want all of this text to stay inside its box. Why does it keep going outside its borders?"
        text = "The quick brown fox jumped over the lazy dog."
        text = "A long time ago, in a galaxy far, far away, there lived a young man named Luke Skywalker."
        box1.box()
        box2.addstr(1, 0, textwrap.fill(text, 38))
    
        #box1.addstr("Hello World of Curses!")
    
        screen.getch()
    
    finally:
        curses.endwin()
    

    My output looks like this:

    enter image description here