Pregunta

En mi script en Python que utiliza Curses, tengo una subwin al que se asigna un texto. Debido a la longitud del texto puede ser más largo que el tamaño de la ventana, el texto debe ser desplazable.

No parece que haya ninguna CSS- "desbordamiento" como atributo para ventanas maldiciones. Los docs Python / Maldiciones son también bastante críptico en este aspecto.

¿Alguien aquí tiene una idea de cómo puedo codificar un Maldiciones desplazables subventana usando Python y en realidad de desplazamiento a través de él?

\ edición: pregunta más precisa

¿Fue útil?

Solución

Aceptar con window.scroll era demasiado complicado para mover el contenido de la ventana. En su lugar, curses.newpad lo hizo por mí.

Crea una almohadilla:

mypad = curses.newpad(40,60)
mypad_pos = 0
mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)

A continuación, puede desplazarse por el aumento / disminución mypad_pos en función del aporte de window.getch (cmd) en:

if  cmd == curses.KEY_DOWN:
    mypad_pos += 1
    mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)
elif cmd == curses.KEY_UP:
    mypad_pos -= 1
    mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)

Otros consejos

Derecho, yo estaba un poco confundido sobre cómo utilizar almohadillas (para el texto de desplazamiento), y aún así no pudo averiguarlo después de leer este post; sobre todo porque quería usarlo en un contexto del contenido de ser un "conjunto de líneas" existente. Así preparé un pequeño ejemplo, que muestra similitudes (y diferencias) entre newpad y subpad:

#!/usr/bin/env python2.7
import curses

# content - array of lines (list)
mylines = ["Line {0} ".format(id)*3 for id in range(1,11)]

import pprint
pprint.pprint(mylines)

def main(stdscr):
  hlines = begin_y = begin_x = 5 ; wcols = 10
  # calculate total content size
  padhlines = len(mylines)
  padwcols = 0
  for line in mylines:
    if len(line) > padwcols: padwcols = len(line)
  padhlines += 2 ; padwcols += 2 # allow border
  stdscr.addstr("padhlines "+str(padhlines)+" padwcols "+str(padwcols)+"; ")
  # both newpad and subpad are <class '_curses.curses window'>:
  mypadn = curses.newpad(padhlines, padwcols)
  mypads = stdscr.subpad(padhlines, padwcols, begin_y, begin_x+padwcols+4)
  stdscr.addstr(str(type(mypadn))+" "+str(type(mypads)) + "\n")
  mypadn.scrollok(1)
  mypadn.idlok(1)
  mypads.scrollok(1)
  mypads.idlok(1)
  mypadn.border(0) # first ...
  mypads.border(0) # ... border
  for line in mylines:
    mypadn.addstr(padhlines-1,1, line)
    mypadn.scroll(1)
    mypads.addstr(padhlines-1,1, line)
    mypads.scroll(1)
  mypadn.border(0) # second ...
  mypads.border(0) # ... border
  # refresh parent first, to render the texts on top
  #~ stdscr.refresh()
  # refresh the pads next
  mypadn.refresh(0,0, begin_y,begin_x, begin_y+hlines, begin_x+padwcols)
  mypads.refresh()
  mypads.touchwin()
  mypadn.touchwin()
  stdscr.touchwin() # no real effect here
  #stdscr.refresh() # not here! overwrites newpad!
  mypadn.getch()
  # even THIS command erases newpad!
  # (unless stdscr.refresh() previously):
  stdscr.getch()

curses.wrapper(main)

Al ejecutar esto, en un primer momento obtendrá algo así como (newpad izquierda, subpad derecha):

 ┌────────────────────────┐    ┌────────────────────────┐
 │Line 1 Line 1 Line 1 ───│    │Line 1 Line 1 Line 1 ───│
 │Line 2 Line 2 Line 2    │    │Line 2 Line 2 Line 2    │
 │Line 3 Line 3 Line 3    │    │Line 3 Line 3 Line 3    │
 │Line 4 Line 4 Line 4    │    │Line 4 Line 4 Line 4    │
 │Line 5 Line 5 Line 5    │    │Line 5 Line 5 Line 5    │
                               │Line 6 Line 6 Line 6    │
                               │Line 7 Line 7 Line 7    │
                               │Line 8 Line 8 Line 8    │
                               │Line 9 Line 9 Line 9    │
                               │Line 10 Line 10 Line 10 │
                               └────────────────────────┘

Algunas notas:

  • Tanto newpad y subpad deben tener su anchura / altura dimensionada para el contenido (líneas num / ancho de línea max de la matriz de líneas) + espacio frontera eventual
  • En ambos casos, se podría permitir líneas adicionales con scrollok() - pero no extra de anchura
  • En ambos casos, que, básicamente, "empujar" una línea en la parte inferior de la almohadilla; y luego scroll() hasta hacer espacio para la siguiente
  • El método refresh especial que tiene newpad, a continuación, permite sólo una región de este "todo contenido" que se muestra en la pantalla; subpad más-menos tiene que ser mostrado en el tamaño que se crea una instancia en
  • Si dibuja los bordes de las almohadillas antes de añadir cadenas de contenido - a continuación, las fronteras se desplazará hacia arriba también (que es la pieza ─── se muestra en la parte ...Line 1 ───│).

Enlaces útiles:

Configurar el window.scrollok (Verdadero).

Documentación

quería usar una almohadilla de desplazamiento para mostrar el contenido de algunos archivos de texto grandes, pero esto no funcionaba bien porque los textos pueden tener saltos de línea y era bastante difícil de averiguar el número de caracteres a la pantalla a la vez para adaptarse a la buen número de columnas y filas.

Así que decidí primera división mis archivos de texto en líneas de caracteres exactamente columnas, relleno con espacios cuando las líneas eran demasiado cortos. A continuación, desplazándose el texto sea más fácil.

Aquí hay un código de ejemplo para mostrar cualquier archivo de texto:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import curses
import locale
import sys

def main(filename, filecontent, encoding="utf-8"):
    try:
        stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        stdscr.keypad(1)
        rows, columns = stdscr.getmaxyx()
        stdscr.border()
        bottom_menu = u"(↓) Next line | (↑) Previous line | (→) Next page | (←) Previous page | (q) Quit".encode(encoding).center(columns - 4)
        stdscr.addstr(rows - 1, 2, bottom_menu, curses.A_REVERSE)
        out = stdscr.subwin(rows - 2, columns - 2, 1, 1)
        out_rows, out_columns = out.getmaxyx()
        out_rows -= 1
        lines = map(lambda x: x + " " * (out_columns - len(x)), reduce(lambda x, y: x + y, [[x[i:i+out_columns] for i in xrange(0, len(x), out_columns)] for x in filecontent.expandtabs(4).splitlines()]))
        stdscr.refresh()
        line = 0
        while 1:
            top_menu = (u"Lines %d to %d of %d of %s" % (line + 1, min(len(lines), line + out_rows), len(lines), filename)).encode(encoding).center(columns - 4)
            stdscr.addstr(0, 2, top_menu, curses.A_REVERSE)
            out.addstr(0, 0, "".join(lines[line:line+out_rows]))
            stdscr.refresh()
            out.refresh()
            c = stdscr.getch()
            if c == ord("q"):
                break
            elif c == curses.KEY_DOWN:
                if len(lines) - line > out_rows:
                    line += 1
            elif c == curses.KEY_UP:
                if line > 0:
                    line -= 1
            elif c == curses.KEY_RIGHT:
                if len(lines) - line >= 2 * out_rows:
                    line += out_rows
            elif c == curses.KEY_LEFT:
                if line >= out_rows:
                    line -= out_rows
    finally:
        curses.nocbreak(); stdscr.keypad(0); curses.echo(); curses.curs_set(1)
        curses.endwin()

if __name__ == '__main__':
    locale.setlocale(locale.LC_ALL, '')
    encoding = locale.getpreferredencoding()
    try:
        filename = sys.argv[1]
    except:
        print "Usage: python %s FILENAME" % __file__
    else:
        try:
            with open(filename) as f:
                filecontent = f.read()
        except:
            print "Unable to open file %s" % filename
        else:
            main(filename, filecontent, encoding)

El truco principal es la línea:

lines = map(lambda x: x + " " * (out_columns - len(x)), reduce(lambda x, y: x + y, [[x[i:i+out_columns] for i in xrange(0, len(x), out_columns)] for x in filecontent.expandtabs(4).splitlines()]))

En primer lugar, tabulaciones en el texto se convierten en espacios, entonces utiliza splitlines () para convertir mi texto en disposición de líneas. Sin embargo, algunas líneas pueden ser más largo que nuestro número COLUMNAS, así que todo dividido cada línea en el conjunto de caracteres de columnas y luego se usa para transformar reducir la lista resultante en una lista de líneas. Por último, he utilizado un mapa para rellenar cada línea con espacios finales para que su longitud es exactamente caracteres columnas.

Espero que esto ayude.

Esta es la respuesta de esta pregunta: Como hacer un menú desplegable en python-maldiciones

Este código le permite crear un pequeño menú de desplazamiento en un cuadro de una lista de cadenas.
También puede utilizar este código conseguir la lista de cadenas de una consulta sqlite o desde un archivo csv.
Para editar el número máximo de filas de menú sólo hay que editar max_row.
Si pulsa entrar en el programa imprimirá el valor de cadena seleccionado y su posición.

from __future__ import division  #You don't need this in Python3
import curses
from math import *



screen = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad( 1 )
curses.init_pair(1,curses.COLOR_BLACK, curses.COLOR_CYAN)
highlightText = curses.color_pair( 1 )
normalText = curses.A_NORMAL
screen.border( 0 )
curses.curs_set( 0 )
max_row = 10 #max number of rows
box = curses.newwin( max_row + 2, 64, 1, 1 )
box.box()


strings = [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "l", "m", "n" ] #list of strings
row_num = len( strings )

pages = int( ceil( row_num / max_row ) )
position = 1
page = 1
for i in range( 1, max_row + 1 ):
    if row_num == 0:
        box.addstr( 1, 1, "There aren't strings", highlightText )
    else:
        if (i == position):
            box.addstr( i, 2, str( i ) + " - " + strings[ i - 1 ], highlightText )
        else:
            box.addstr( i, 2, str( i ) + " - " + strings[ i - 1 ], normalText )
        if i == row_num:
            break

screen.refresh()
box.refresh()

x = screen.getch()
while x != 27:
    if x == curses.KEY_DOWN:
        if page == 1:
            if position < i:
                position = position + 1
            else:
                if pages > 1:
                    page = page + 1
                    position = 1 + ( max_row * ( page - 1 ) )
        elif page == pages:
            if position < row_num:
                position = position + 1
        else:
            if position < max_row + ( max_row * ( page - 1 ) ):
                position = position + 1
            else:
                page = page + 1
                position = 1 + ( max_row * ( page - 1 ) )
    if x == curses.KEY_UP:
        if page == 1:
            if position > 1:
                position = position - 1
        else:
            if position > ( 1 + ( max_row * ( page - 1 ) ) ):
                position = position - 1
            else:
                page = page - 1
                position = max_row + ( max_row * ( page - 1 ) )
    if x == curses.KEY_LEFT:
        if page > 1:
            page = page - 1
            position = 1 + ( max_row * ( page - 1 ) )

    if x == curses.KEY_RIGHT:
        if page < pages:
            page = page + 1
            position = ( 1 + ( max_row * ( page - 1 ) ) )
    if x == ord( "\n" ) and row_num != 0:
        screen.erase()
        screen.border( 0 )
        screen.addstr( 14, 3, "YOU HAVE PRESSED '" + strings[ position - 1 ] + "' ON POSITION " + str( position ) )

    box.erase()
    screen.border( 0 )
    box.border( 0 )

    for i in range( 1 + ( max_row * ( page - 1 ) ), max_row + 1 + ( max_row * ( page - 1 ) ) ):
        if row_num == 0:
            box.addstr( 1, 1, "There aren't strings",  highlightText )
        else:
            if ( i + ( max_row * ( page - 1 ) ) == position + ( max_row * ( page - 1 ) ) ):
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + strings[ i - 1 ], highlightText )
            else:
                box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + strings[ i - 1 ], normalText )
            if i == row_num:
                break



    screen.refresh()
    box.refresh()
    x = screen.getch()

curses.endwin()
exit()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top