Frage

I've got a curses application that uses subwindows, but I can't seem to be able to delete them.

For example, this code doesn't work:

import curses
def fill(window, ch):
    y, x = window.getmaxyx()
    s = ch * (x - 1)
    for line in range(y):
        window.addstr(line, 0, s)

def main(stdscr):
    fill(stdscr, 'M')
    stdscr.refresh()
    stdscr.getch()

    subwin = stdscr.subwin(1, 28, 20, 13)
    fill(subwin, 'J')
    subwin.refresh()
    subwin.getch()

    del subwin
    stdscr.touchwin()
    stdscr.refresh()
    stdscr.getch()

curses.wrapper(main)

When you run this code, the screen fills with 'M', then when you hit a key, a subwindow is created and filled with 'J'. Finally, when you press a key again, the code deletes the subwindow and completely redraws the screen. However, those Js are still there.

After some experimentation, I've found that calling the clear() method of stdscr will make the subwindow go, but I would like to restore the background as it was, without blanking it and rewriting. Does anyone know a way in which this could be done?

War es hilfreich?

Lösung

Is there a good reason why you're using a subwindow? If you create a new top-level window then the code works correctly - simply change stdscr.subwin to curses.newwin and it works as you'd expect.

I'm not a curses expert, but I believe a subwindow shares the character buffer with its parent such that changes to either one will also affect the other. So, if you're looking to sub-divide a window into logical areas (perhaps a menu bar, main area and status bar) then subwindows are useful. If, however, you're looking for something more like a dialog box or pop-up menu then a whole new window (with its own separate buffer) is what you're after.

I can't find any definitive reference for ncurses which agrees or disagrees with me, but man page for AIX seems to corroborate it:

Recall that the subwindow shares its parent's window buffer. Changes made to the shared window buffer in the area covered by a subwindow, through either the parent window or any of its subwindows, affects all windows sharing the window buffer.

Of course, this isn't definitive for ncurses, but I can't find anything to the contrary and it certainly seems to explain the behaviour observed. I also did a crude experiment where, immediately after the subwin.getch() line in your example, I added this line:

raise Exception(stdscr.instr(20, 15, 3))

In your example, I get JJJ as the content of the actual main window. If I change to use curses.newwin() to create the window instead of stdscr.subwin() I get the expected MMM.

I don't know how many specific Python curses resources there are, but most of the standard tutorials and documents about ncurses are quite useful for this sort of level. Back when I had to do some work in it, this document was quite useful. If you scroll down to the "An Example" section, you'll see that the menu pop-ups are not subwindows - he alludes to this with the following slightly vague explanation:

We don't want this new window to overwrite previously written characters on the background. They should stay there after the menu closes. This is why the menu window can't be created as a subwindow of stdscr.

Also, I remember that using both stdscr and your own windows can cause issues - the "official" ncurses introduction has some warnings about this sort of thing. It also suggests avoiding overlapping windows entirely, as they're apparently error-prone, but I don't recall having any issues with them for short-term transient modal dialogs (which is the only use to which I put them). Of course, just because my simple use-case didn't expose any issues doesn't mean there aren't any. In something as complicated as ncurses, however, I can see the wisdom in keeping things as simple as you can.

I hope that's some help. As I said, I'm by no means a curses expert, but hopefully this gets you a few steps further along.

Andere Tipps

There are two problems with this code.

First, as the previous poster noted, subwindows share a buffer with the parent window, so you should use curses.newwin() if you want a completely independent window.

Second, using del to remove a window is problematic because it relies on reference counting/garbage collection to work properly. (For one thing, you have to delete all references to the window for it to work.) I recommend using the curses.panel module to explicitly show/hide the window.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top