Wie Text in Python / Curses Subwindow blättern?
Frage
In meinem Python-Skript, das Flüche verwendet, habe ich eine subwin zu denen einige Text zugeordnet ist. Da die Textlänge länger sein kann als die Fenstergröße sollte der Text scrollbaren sein.
Es scheint nicht, dass es irgendein CSS- „Überlauf“ wie Attribut für Flüche Fenster. Die Python / Curses docs sind auch eher kryptisch auf diesen Aspekt.
Hat jemand hier eine Idee, wie ich eine scrollbare Flüche Python-Code kann Subwindow mit und tatsächlich blättern durch das?
\ edit: präzisere Frage
Lösung
OK mit window.scroll es war zu kompliziert, den Inhalt des Fensters zu bewegen. Stattdessen curses.newpad es für mich getan hat.
Erstellen Sie eine Unterlage:
mypad = curses.newpad(40,60)
mypad_pos = 0
mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)
Dann können Sie blättern durch Erhöhen / Vermindern mypad_pos in Abhängigkeit von der Eingabe von window.getch () in cmd:
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)
Andere Tipps
Richtig, ich war ein wenig verwirrt, wie Pads zu verwenden (um Scroll-Text), und konnte es immer noch nicht herausfinden, nach dem Lesen dieser Nachricht; zumal ich wollte es in einem Kontext des Inhalts verwenden, um eine bestehende „Anordnung von Linien“ zu sein. Also habe ich ein kleines Beispiel vorbereitet, das zeigt Ähnlichkeiten (und Unterschiede) zwischen newpad
und 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)
Wenn Sie dies ausführen, zunächst werden Sie so etwas wie erhalten (newpad
links, subpad
rechts):
┌────────────────────────┐ ┌────────────────────────┐
│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 │
└────────────────────────┘
Einige Anmerkungen:
- Sowohl
newpad
undsubpad
sollten ihre Breite / Höhe auf den Inhalt so bemessen (num Linien / max Linienbreite der Anordnung von Linien) + schließlichen Grenzraum - In beiden Fällen können Sie zusätzliche Linien mit
scrollok()
erlauben - aber nicht zusätzliche Breite - In beiden Fällen Sie im Grunde „Push“ eine Linie am unteren Rand des Kissens; und dann
scroll()
bis zu machen Platz für die nächste - Die spezielle
refresh
Methode, dassnewpad
hat, kann dann nur für eine Region dieses „ganzen Inhalts“ auf dem Bildschirm angezeigt werden;subpad
mehr weniger hat in der Größe gezeigt wird, wurde in instanziiert - Wenn Sie die Grenzen der Pads ziehen, bevor Inhalt Strings Zugabe - dann werden die Grenzen scrollen (die das
───
Stück am...Line 1 ───│
Teil gezeigt ist).
Nützliche Links:
Stellen Sie die window.scrollok (True).
Ich wollte ein Scrolling-Pad-Display Inhalt einiger großer Textdateien verwenden, aber dies auch nicht funktionieren, weil Texte Zeilenumbrüche haben können und es war ziemlich hart, wie viele Zeichen-Display, um herauszufinden, zu einer Zeit, die passen gute Anzahl von Spalten und Zeilen.
beschlossen Also ich zum ersten Split meiner Textdateien in Zeilen genau SPALTEN Zeichen mit Leerzeichen Klotzen, wenn Linien zu kurz waren. Dann Scrollen der Text werden einfacher.
Hier ist ein Beispielcode eine beliebige Textdatei angezeigt werden:
#!/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)
Der wichtigste Trick ist die Zeile:
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()]))
Als erstes Tabellierungen im Text in Leerzeichen umgewandelt wird, dann habe ich Teilungslinien () -Methode meinen Text in Array von Zeilen zu konvertieren. Aber einige Zeilen können länger als unsere SäULEN Nummer, so dass ich jede Zeile in Batzen SPALTEN Zeichen aufgeteilt und verwenden dann reduzieren Sie die resultierende Liste in einer Liste von Linien zu verwandeln. Schließlich habe ich verwendet, um jede Zeile Karte Pad mit Leerzeichen Hinter so dass seine Länge genau SPALTEN Zeichen.
Hope, das hilft.
Dies ist die Antwort auf diese Frage: Wie ein Scroll-Menü in machen Python-Flüche
Mit diesem Code können Sie ein wenig Scrollen Menü in einem Kasten aus einer Liste von Zeichenketten erstellen.
Sie können auch diesen Code verwenden, um die Liste von Zeichenketten aus einer SQLite-Abfrage oder aus einer CSV-Datei zu bekommen.
Um die maximale Anzahl der Zeilen des Menüs bearbeiten Sie gerade bearbeiten max_row
haben.
Wenn Sie das Programm Eingabetaste drücken den ausgewählten Zeichenfolge-Wert und seine Position drucken.
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()