كيفية التمرير النص في Python/لعنات subwindow؟
سؤال
في البرنامج النصي Python الذي يستخدم اللعنات ، لديّ Subwin تم تعيين بعض النص عليه. نظرًا لأن طول النص قد يكون أطول من حجم النافذة ، يجب تمرير النص.
لا يبدو أن هناك أي CSS- "فائض" مثل السمة لنوافذ اللعنات. مستندات Python/Curses هي أيضا خفية إلى حد ما على هذا الجانب.
هل لدى أي شخص هنا فكرة كيف يمكنني ترميز الريف الفرعي لعنات قابلة للتمرير باستخدام Python والتمرير من خلاله فعليًا؟
تحرير: سؤال أكثر دقة
المحلول
حسنًا مع Window.Scroll كان الأمر معقدًا للغاية لتحريك محتوى النافذة. بدلاً من ذلك ، فعلت Curses.newpad ذلك بالنسبة لي.
إنشاء لوحة:
mypad = curses.newpad(40,60)
mypad_pos = 0
mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)
ثم يمكنك التمرير عن طريق زيادة/تقليل mypad_pos اعتمادًا على المدخلات من window.getch () في 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)
نصائح أخرى
حسنًا ، كنت مرتبكًا بعض الشيء حول كيفية استخدام الفوط (من أجل التمرير النص) ، وما زلت لا أستطيع اكتشافه بعد قراءة هذا المنشور ؛ خاصة وأنني أردت استخدامه في سياق المحتوى كونه "مجموعة من الخطوط" الحالية. لذلك قمت بإعداد مثال صغير ، يظهر أوجه التشابه (والاختلافات) بين newpad
و 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)
عندما تقوم بتشغيل هذا ، ستحصل في البداية على شيء مثل (newpad
اليسار، subpad
حق):
┌────────────────────────┐ ┌────────────────────────┐
│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 │
└────────────────────────┘
بعض الملاحظات:
- كلاهما
newpad
وsubpad
يجب أن يكون لها عرض/ارتفاع بحجم المحتوى (خطوط NUM/عرض خط الحد الأقصى لمجموعة الخطوط) + مساحة الحدود النهائية - في كلتا الحالتين ، يمكنك السماح بخطوط إضافية مع
scrollok()
- ولكن ليس عرض إضافي - في كلتا الحالتين ، يمكنك "دفع" خطًا في أسفل اللوحة ؛ وثم
scroll()
حتى إفساح المجال لآخر - الخاص
refresh
طريقة ذلكnewpad
بعد ذلك ، يسمح فقط بإظهار منطقة من "المحتوى الكامل" على الشاشة ؛subpad
لا بد من إظهار أقل في الحجم الذي تم إنشاءه فيه - إذا رسمت حدود الفوط قبل إضافة سلاسل المحتوى - فإن الحدود سوف تنتقل أيضًا (هذا هو
───
قطعة مبينة في...Line 1 ───│
جزء).
روابط مفيدة:
اضبط window.scrollok (صواب).
كنت أرغب في استخدام لوحة التمرير لعرض محتوى بعض الملفات النصية الكبيرة ، لكن هذا لم ينجح بشكل جيد لأن النصوص يمكن أن تحتوي على فترات فواصل بين الأسطر وكان من الصعب جدًا معرفة عدد الأحرف التي يجب عرضها في وقت واحد لتناسب العدد الجيد من الأعمدة والصفوف.
لذلك قررت أولاً تقسيم ملفاتي النصية في خطوط أحرف الأعمدة بالضبط ، قم بالتحريض مع المساحات عندما كانت الخطوط قصيرة جدًا. ثم يصبح التمرير النص أكثر سهولة.
فيما يلي نموذج رمز لعرض أي ملف نصي:
#!/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)
الحيلة الرئيسية هي الخط:
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()]))
أولاً ، يتم تحويل الجداول في النص إلى مسافات ، ثم استخدمت طريقة splitlines () لتحويل نصي في مجموعة من الخطوط. ولكن قد تكون بعض الخطوط أطول من رقم الأعمدة لدينا ، لذلك قمت بتقسيم كل سطر في أحرف من أعمدة الأعمدة ثم استخدمت تقليلها لتحويل القائمة الناتجة في قائمة الخطوط. أخيرًا ، استخدمت MAP لتسخين كل سطر مع مساحات زائدة بحيث يكون طوله أحرف أعمدة بالضبط.
أتمنى أن يساعدك هذا.
هذا هو إجابة هذا السؤال:كيفية صنع قائمة التمرير في بيثون كورس
يتيح لك هذا الرمز إنشاء قائمة تمرير صغيرة في مربع من قائمة الأوتار.
يمكنك أيضًا استخدام هذا الرمز للحصول على قائمة السلاسل من استعلام SQLite أو من ملف CSV.
لتحرير عدد أقصى صفوف من القائمة التي عليك فقط تحريرها max_row
.
إذا قمت بالضغط على إدخال البرنامج ، فسيقوم بطباعة قيمة السلسلة المحددة وموضعها.
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()