2017-11-12 18 views
0

curses를 사용하여 간단한 GUI를 작성하려고하지만 크기 조정 및 화면 다시 그릴 때 약간의 문제가 있습니다. 다음은 내 코드입니다 :Python curses - 텍스트 입력 중에 터미널 크기 조정

import curses 
import curses.textpad as textpad 

class editor (object): 
    def __init__(self, stdscreen): 
     self.screen = stdscreen 
     self.height,self.width = self.screen.getmaxyx() 
     self.draw_screen() 
     while True: 
      # Check if the screen has been resized 
      resize = curses.is_term_resized(self.height, self.width) 
      if resize: 
       self.height,self.width = self.screen.getmaxyx() 
       self.draw_screen() 
      curses.noecho() 
      text = textpad.Textbox(self.text).edit(validate=self.validate) 
      self.body.addstr(0,0, str(text), curses.A_NORMAL) 
      self.body.refresh() 
      self.text.erase() 
    def draw_screen (self): 
     self.screen.clear() 
     self.header=self.screen.subwin(1,self.width,0,0) 
     self.body=self.screen.subwin(self.height-3,self.width,1,0) 
     self.text=self.screen.subwin(1,self.width,self.height-2,0) 
     self.footer=self.screen.subwin(self.height-1,0) 
     header_text = "{0:<{n}}".format("Header", n=self.width-1) 
     self.header.addstr(0,0, header_text, curses.A_REVERSE) 
     self.footer.addstr(0,0, "^W", curses.A_REVERSE) 
     self.footer.addstr(0,2, " Quit", curses.A_NORMAL) 
     self.header.noutrefresh() 
     self.body.noutrefresh() 
     self.footer.noutrefresh() 
     self.text.noutrefresh() 
     curses.doupdate() 
    def validate (self, ch): 
     # If resize event redraw screen 
     if ch==curses.KEY_RESIZE: 
      self.height,self.width = self.screen.getmaxyx() 
      self.draw_screen() 
     if ch==23: # ^w quit 
      exit() 
     else: 
      return ch 

if __name__=="__main__": 
    curses.wrapper(editor) 
터미널이이 같은 예상 작품 크기가 조정되지되어

,하지만, 터미널 창을 확대 할 때 각각 상단과 하단 행 머리글과 바닥 글 이동, 커서 남아있는 동안 Enter 키를 눌러 문자열을 받아 들일 때까지 이전 위치에 놓습니다. 축소 할 때와 동일합니다. 단,이 경우 커서가 바닥 글에 들어가고 바닥 글의 내용이 반환됩니다. 문제를 디버깅하려고했는데 하위 창이 제대로 움직이는 것처럼 보였지만 커서가 움직이지 않는 것으로 나타났습니다. 나도 시도했다

self.text.move(0,0) 

커서를 오른쪽 위치로 다시 이동했지만 작동하지 않았다.

보너스 : 크기 조정 작업 전에 삽입 한 텍스트를 보존하고 크기가 조정 된 표시된 화면에 추가하려면 어떻게합니까?

편집 : 더 많은 디버깅을 한 후에 나는 "종류"의 작동 (그러나 추악하고 해킹) 인 의사 솔루션을 생각해 냈습니다. 내가를 무슨 짓을했는지

import curses 
import curses.textpad as textpad 

class my_textbox(textpad.Textbox): 

    def edit(self, validate=None): 
     while 1: 
      ch = self.win.getch() 
      # Return a list instead of a string if the last key was a resize 
      if ch==curses.KEY_RESIZE: 
       return[self.gather(),True] 
      if validate: 
       ch = validate(ch) 
      if not ch: 
       continue 
      if not self.do_command(ch): 
       break 
      self.win.refresh() 
     return self.gather() 

class editor (object): 
    def __init__(self, stdscreen): 
     self.screen = stdscreen 
     self.height,self.width = self.screen.getmaxyx() 
     # Initialize a variable to store the previous text 
     self.ptext=None 
     curses.noecho() 
     self.draw_screen() 
     while True: 
      # Check if the screen has been resized 
      resize = curses.is_term_resized(self.height, self.width) 
      if resize: 
       self.height,self.width = self.screen.getmaxyx() 
       self.draw_screen() 
      text = my_textbox(self.text).edit(validate=self.validate) 
      # If the window has been resized (aka textbox returned a list) 
      if isinstance (text, list): 
       text=text[0] 
       # Store the previous text 
       self.ptext=text.strip() 
       continue 
      self.body.addstr(0,0, str(text), curses.A_NORMAL) 
      self.body.refresh() 
      self.text.erase() 
    def draw_screen (self): 
     self.screen.clear() 
     self.header=self.screen.subwin(1,self.width,0,0) 
     self.body=self.screen.subwin(self.height-3,self.width,1,0) 
     self.text=self.screen.subwin(1,self.width,self.height-2,0) 
     self.footer=self.screen.subwin(self.height-1,0) 
     header_text = "{0:<{n}}".format("Header", n=self.width-1) 
     self.header.addstr(0,0, header_text, curses.A_REVERSE) 
     # If there was text previous to resize 
     if self.ptext: 
      # To prevent _curses.error: addwstr() returned ERR 
      # when shrinking window cut out the last character 
      # (!) Raises ERR anyway when shrinking with double click from 
      # titlebar, also, when resizing is too fast, ptext become a series of ^? 
      if len(self.ptext)<self.width-1: 
       self.text.addstr(0,0,self.ptext.strip()) 
      else: 
       self.ptext=self.ptext[:self.width-1] 
       self.text.addstr(0,0,self.ptext.strip()) 
     self.footer.addstr(0,0, "^W", curses.A_REVERSE) 
     self.footer.addstr(0,2, " Quit", curses.A_NORMAL) 
     self.header.noutrefresh() 
     self.body.noutrefresh() 
     self.footer.noutrefresh() 
     self.text.noutrefresh() 
     curses.doupdate() 

    def validate (self, ch): 
     if ch==23: # ^w quit 
      exit() 
     else: 
      return ch 

if __name__=="__main__": 
    curses.wrapper(editor) 

는 : 창문의 크기를 조정할 때 문자열 대신 목록을 반환하도록

나는, 텍스트 상자 클래스의 편집 방법을 재정의.

입력 루프에서 창의 크기가 조정되면 이전주기가 저장되고 새주기가 시작됩니다.

이전 텍스트가있는 경우 그리기 기능이이를 하위 창에 추가합니다.

노트 :

에 의해 크기 조정 제목 표시 줄을 두 번 클릭 던져에서 오류가 발생하고 크기 조정은 "너무 빨리"인 경우 문자열이 쓰레기로 대체한다 (실제로는 2^64 "? ^"이다 -1).

(n) curses의 기능 대부분이 크기 조정이 불가능한 터미널을 염두에두고 작성 되었기 때문에 구현은 이해가되지만 적어도 필자와 같은 비교적 새로운 Python에서는 직관적이지 않습니다. 모든.

답변

1

설명이 올바르다 : 응용 프로그램이 텍스트를 다시 레이아웃하고 화면의 내용을 다시 그려야합니다.

이렇게하려면 정보를 기록해야합니다.그 중 일부는이 라인

header_text = "{0:<{n}}".format("Header", n=self.width-1) 

"Header" 같은 미리 정의되어 그러나 화면이 이루어진 경우 서브 윈도우의 내용이 손실 될 수 있습니다 (ncurses의에서 resizeterm 그 창 자릅니다 때문에) 작은 :

self.header=self.screen.subwin(1,self.width,0,0) 

뿐만 아니라 임의의 창, 예 : newwin으로 생성됩니다. 파이썬의 textpad 클래스가 그렇게합니다.

curses (특히 Python에서 사용되는 ncurses)는 "pad"이라는 준 창이 지원되며, 경우에 따라 사용할 수 있습니다. 그러나 텍스트 패드 클래스 (패드을 새로 고치는 기본 호출은 윈도우의 경우와 다르기 때문에 쉽게 사용할 수 없습니다).

그러나 당신 당신이 관리하고자하는 화면로 큰 인 패드를 만들 수 있습니다 (이 진짜 설치 작업을 걸릴 것이다), 그리고 TextPad를 그 아이를 만들어, resizeterm에 관계없이 자신 만의 레이아웃을 다시 작성하십시오. (ncurses의 manual에서 복사) 관련 resize_term 메모 파이썬 문서 :

백엔드 기능은 대부분의 작업을 수행 resizeterm()에 의해 사용; 창 크기를 조정할 때 resize_term()은 확장 된 영역을 공백으로 채 웁니다. 호출 응용 프로그램은이 영역을 적절한 데이터로 채워야합니다. resize_term() 함수는 모든 창 크기를 조정하려고 시도합니다. 그러나 패드의 호출 규칙 때문에 응용 프로그램과의 추가 상호 작용 없이도 크기를 조정할 수 없습니다.

+0

의견을 보내 주셔서 감사합니다. 더 많은 실험을 수행했으며 문제가 잘린 창인지 확신 할 수 없습니다. 나는 내가 발견 한 것으로 질문을 업데이트했다. 나는 패드로 몇 가지 테스트를 할 수 있다고 생각하지만 실제로 많은 작업이있는 것으로 보인다. –