Curses Problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

Hallo!

Ich habe mal wieder ein Problem bei einem Projekt.

Ich brauche ein Curses-Interface, und habe mir folgendes gebastelt:

Das ist meine Klasse fuer die Verwaltung des In- und Outputs, momentan erstmal der Output:

Code: Alles auswählen

import curses

class Screen(object):
  curses.setupterm()
  TERM_COLS = curses.tigetnum("cols")
  TERM_LINES = curses.tigetnum("lines")
  OUTWIN_COLS = TERM_COLS
  OUTWIN_LINES = TERM_LINES - 5
  OUTWIN_COLS_MAX = OUTWIN_COLS - 2
  OUTWIN_LINES_MAX = OUTWIN_LINES - 2
  OUTWIN_START_POS = [1, 2]
  INWIN_COLS = TERM_COLS
  INWIN_LINES = 5
  INWIN_COLS_MAX = TERM_COLS - 2
  INWIN_LINES_MAX = INWIN_LINES - 2

  def __init__(self):
    self.stdscr = curses.initscr()
    self.outwin = self.stdscr.subwin(self.OUTWIN_LINES,
                                     self.OUTWIN_COLS, 0, 0)
    self.outwin.box()
    self.outwin.refresh()
    self.inwin = self.stdscr.subwin(self.INWIN_LINES,
                                    self.INWIN_COLS,
                                    self.OUTWIN_LINES, 0)
    self.inwin.box()
    self.inwin.refresh()

    self._outwin_pos = self.OUTWIN_START_POS[:]
    self._outwin_scroll = 0
    self._outwin_content = ""

  def __del__(self):
    curses.endwin()

  def write_output(self, data, attr=0):
    data = data.replace("\r", "")
    for char in data:
      if char == "\n" or self._outwin_pos[1] == self.OUTWIN_COLS_MAX:
        if self._outwin_pos[0] == self.OUTWIN_LINES_MAX:
          self.scroll_outwin(1)
        self._outwin_pos[0] += 1
        self._outwin_content += "\n"
        self._outwin_pos[1] = self.OUTWIN_START_POS[1]
        if char == "\n":
          continue
      self.outwin.addstr(self._outwin_pos[0],
                         self._outwin_pos[1],
                         char, attr)
      self._outwin_content += char
      self._outwin_pos[1] += 1
    self.outwin.refresh()
    return True

  def scroll_outwin(self, lines):
    if lines != 0:
      data = self._outwin_content.split("\n")
      from_line = self._outwin_scroll + lines
      till_line = self._outwin_scroll + lines + self.OUTWIN_LINES_MAX
      data = data[from_line:till_line]
#      data += ["" for dummy in xrange(self.OUTWIN_LINES_MAX - len(data))]
      data = "\n".join(data)
      print "\a"
      self._outwin_pos[0] = self.OUTWIN_START_POS[0]
      self._outwin_pos[1] = self.OUTWIN_START_POS[1]
      self.outwin.clear()
      self.outwin.box()
      self.write_output(data)
      self._outwin_scroll = from_line
      self._outwin_pos[0] -= 1
      print >>file("data", "w"), from_line, till_line, self._outwin_pos[0], data
      return True
    else:
      return True
Nun will ich z.B. hiermit Text ausgeben:

Code: Alles auswählen

#!/usr/bin/env python

import random, sys, time

def main():
  scr = Screen()
  while True:
    scr.write_output(random.choice(["x\n", "xx\n", "xxx\n"]))
    time.sleep(0.5)

if __name__ == "__main__":
  try:
    main()
  except KeyboardInterrupt:
    sys.exit(1)
Das Problem ist, dass in manchen Zeilen auch mehr als 3 X-Zeichen ausgegeben werden, wieso das?

Ich waere euch sehr dankbar fuer Hilfe!

Liebe Grueße,
roschi
Zuletzt geändert von roschi am Dienstag 6. Oktober 2009, 14:07, insgesamt 1-mal geändert.
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Kennst du urwid? Ist etwas komfortabler als direkt curses zu verwenden.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Warum geben deine Methoden am Ende `True` zurück?
BlackJack

@roschi: Irgenwo hakts bei Deiner Scrollmethode. Das erste mal wird die ausgelöst, wenn in der vorletzten Zeile ein '\n' ausgegeben wird. Danach scheint der Text aber auch bis zur letzten Zeile zu gehen!?

Was sollen diese überflüssigen ``return True``\s?
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

Rebecca hat geschrieben:Kennst du urwid? Ist etwas komfortabler als direkt curses zu verwenden.
Ja, kenne ich. Aber mir schien das hier einfacher. Vielleicht auch nur, weil ich kein gutes Tutorial gefunden habe :). Aber ich dachte, dass es so jetzt schneller geht.
BlackJack hat geschrieben:@roschi: Irgenwo hakts bei Deiner Scrollmethode. Das erste mal wird die ausgelöst, wenn in der vorletzten Zeile ein '\n' ausgegeben wird. Danach scheint der Text aber auch bis zur letzten Zeile zu gehen!?
Genau das ist das Problem. Das Scheint ja alles zusammenzuhaengen.
BlackJack hat geschrieben:Was sollen diese überflüssigen ``return True``\s?
Die werden spaeter notwendig sein, weil die Methoden noch was unterscheiden sollen, aber das ist hierbei irelevant.

Liebe Grueße,
roschi
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

So, ich habe jetzt noch einiges ausprobiert, aber nie habe ich es gescahfft, zu verhindern, dass mehrere Strings, die mit \n enden, in einer Zeile ausgegeben werden.

Ich schildere mal mein Vorhaben, vielleicht kennt jemand ja eine andere, eventuell bessere Loesung.

Ich moechte ein Programm schreiben, das das Terminal in zwei Teile teilt. Im oberen, großen Teil soll durch den Aufruf einer schreib-Funktion Text ausgegeben werden. Das kann am Ende sehr viel Text werden, mit unter bis zu 5000 Zeilen. Dieser Bereich soll nach unten scrollen, wenn Text laenger als das Terminal wird. Ich moechte aber trotzdem den alten Text speichern, damit ich spaeter manuell wieder hochscrollen kann.
Im unteren Teil soll Texteingabe moeglich sein, und die eingegebenen Kommandos sollen dann verarbeitet werden.

Vielleicht hilft das ja beim Finden einer Problemloesung.

Vielen Dank schonmal!

roschi
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Schau dir mal das cmd Modul aus der stdlib an. Ein gutes Beispiel für die Nutzung ist die sqlalchemy_console.
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

Mit dem cmd-Modul kann man zwar eine Art Shell bauen, aber ich brauche einen geteilten Bildschirm, bei dem ich beide Teile separat schreiben und lesen kann.

Gibt es da keine Moeglichkeiten?
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
BlackJack

@roschi: Also für mich klingt es nach einem Fall für `urwid`.
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

BlackJack hat geschrieben:@roschi: Also für mich klingt es nach einem Fall für `urwid`.
Koenntest du mir dann ein kleines Beispiel fuer sowas geben? oder ein gutes Tutorial, was diese Schwerpunkte behandelt? Das waere sehr nett.
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
BlackJack

@roschi: Bei den Beispielen, die von anderen Benutzern beigesteuert wurden, gibt es einen IRC-Clienten, mit der typischen Aufteilung "letzte Zeile == Eingabe, darüber scrollende Ausgabe". Schau Dir da mal die `Screen`-Klasse an: inyyssonen_twisted_irc.Screen.
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

BlackJack hat geschrieben:@roschi: Bei den Beispielen, die von anderen Benutzern beigesteuert wurden, gibt es einen IRC-Clienten, mit der typischen Aufteilung "letzte Zeile == Eingabe, darüber scrollende Ausgabe". Schau Dir da mal die `Screen`-Klasse an: inyyssonen_twisted_irc.Screen.
Vielen dank! Das sieht sehr gut aus.
Kannst du mir nun noch sagen, was fuer ein Wrapper am Ende des Scripts aufgerufen wird? wie muss ich das handhaben?

Ich habe mir jetzt die ``Screen``-Klasse etwas angepasst, und selber das ``tui`` instanzieren lassen.

Das ganze sieht jetzt so aus:

Code: Alles auswählen

import urwid.curses_display
import urwid

class Screen(object):
  def __init__(self):
    self.tui = urwid.curses_display.Screen()
    self.size = self.tui.get_cols_rows()
    self.lines = [urwid.Text('Hello')]
    self.listbox = urwid.ListBox(self.lines)
    self.input = urwid.Edit()
    self.frame = urwid.Frame(self.listbox, footer = self.input)
    self.frame.set_focus('footer')
    self.redisplay()

  def addLine(self, text):
    self.lines.append(urwid.Text(text))
    self.listbox.set_focus(len(self.lines) - 1)
    self.redisplay()

  def redisplay(self):
    canvas = self.frame.render(self.size, focus = True)
    self.tui.draw_screen(self.size, canvas)

  def doRead(self):
    keys = self.tui.get_input()
    for key in keys:
      if key == 'window resize':
        self.size = self.tui.get_cols_rows()
      elif key == 'enter':
        text = self.input.get_edit_text()
        self.input.set_edit_text('')
        self.addLine(text)
        #self.irc.sendLine(text)
      elif key in ('up', 'down', 'page up', 'page down'):
        self.listbox.keypress(self.size, key)
      else:
        self.frame.keypress(self.size, key)
    self.redisplay()
Wie muss ich das nun mit dieser ``run_wrapper``-Methode machen? Wie und wo muss ich die aufrufen?

Vielen dank und liebe Grueße,
roschi
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

Alles klar, ich habe es geschafft!

Kann mir nun noch jemand sagen, wie ich mit urwid in einem ListBox-Item mehrere Textattribute setze? Ich moechte zum Beispiel erst ein Wort in gruen, dann eins ohne Faerbung, dann eines in rot.

Ich muesste alsp praktisch Text-Widgets zusammenfassen koennen.

Es waere genial, wenn mir dabei noch jemand helfen koennte.

Vielen herzlichen Dank!

roschi
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
Antworten