⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calc.py

📁 Urwid is a Python library for making text console applications. It has many features including fluid
💻 PY
📖 第 1 页 / 共 2 页
字号:
#!/usr/bin/python## Urwid advanced example column calculator application#    Copyright (C) 2004-2007  Ian Ward##    This library is free software; you can redistribute it and/or#    modify it under the terms of the GNU Lesser General Public#    License as published by the Free Software Foundation; either#    version 2.1 of the License, or (at your option) any later version.##    This library is distributed in the hope that it will be useful,#    but WITHOUT ANY WARRANTY; without even the implied warranty of#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU#    Lesser General Public License for more details.##    You should have received a copy of the GNU Lesser General Public#    License along with this library; if not, write to the Free Software#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA## Urwid web site: http://excess.org/urwid/"""Urwid advanced example column calculator applicationFeatures:- multiple separate list boxes within columns- custom edit widget for editing calculator cells- custom parent widget for links to other columns- custom list walker to show and hide cell results as required- custom wrap and align modes for editing right-1 aligned numbers- outputs commands that may be used to recreate expression on exit"""import urwidimport urwid.raw_displayimport urwid.web_display# use appropriate Screen classif urwid.web_display.is_web_request():	Screen = urwid.web_display.Screenelse:	Screen = urwid.raw_display.Screendef div_or_none(a,b):	"""Divide a by b.  Return result or None on divide by zero."""	if b == 0: 		return None	return a/b# operators supported and the functions used to calculate a resultOPERATORS = {	'+': (lambda a, b: a+b),	'-': (lambda a, b: a-b),	'*': (lambda a, b: a*b),	'/': div_or_none,	}# the uppercase versions of keys used to switch columnsCOLUMN_KEYS = list( "?ABCDEF" )# these lists are used to determine when to display errorsEDIT_KEYS = OPERATORS.keys() + COLUMN_KEYS + ['backspace','delete']MOVEMENT_KEYS = ['up','down','left','right','page up','page down']# Event textE_no_such_column = "Column %s does not exist."E_no_more_columns = "Maxumum number of columns reached."E_new_col_cell_not_empty = "Column must be started from an empty cell."E_invalid_key = "Invalid key '%s'."E_no_parent_column = "There is no parent column to return to."E_cant_combine = "Cannot combine cells with sub-expressions."E_invalid_in_parent_cell = "Cannot enter numbers into parent cell."E_invalid_in_help_col = [	"Help Column is in focus.  Press ", 	('key',COLUMN_KEYS[1]),"-",('key',COLUMN_KEYS[-1]), 	" to select another column."]# Shared layout objectCALC_LAYOUT = Noneclass CalcEvent:	"""Events triggered by user input."""		attr = 'event'		def __init__(self, message):		self.message = message		def widget(self):		"""Return a widget containing event information"""		text = urwid.Text( self.message, 'center' )		return urwid.AttrWrap( text, self.attr )class ColumnDeleteEvent(CalcEvent):	"""Sent when user wants to delete a column"""	attr = 'confirm'	def __init__(self, letter, from_parent=0):		self.message = ["Press ", ('key',"BACKSPACE"),			" again to confirm column removal."]		self.letter = letterclass UpdateParentEvent:	"""Sent when parent columns may need to be updated."""	passclass Cell:	def __init__(self, op ):		self.op = op		self.is_top = op is None		self.child = None		self.setup_edit()		self.result = urwid.Text("", layout=CALC_LAYOUT)		def show_result(self, next_cell):		"""Return whether this widget should display its result.		next_cell -- the cell following self or None"""				if self.is_top: 			return False		if next_cell is None:			return True		if self.op == "+" and next_cell.op == "+":			return False		return True				def setup_edit(self):		"""Create the standard edit widget for this cell."""				self.edit = urwid.IntEdit()		if not self.is_top:			self.edit.set_caption( self.op + " " )		self.edit.set_layout( None, None, CALC_LAYOUT )	def get_value(self):		"""Return the numeric value of the cell."""				if self.child is not None:			return self.child.get_result()		else:			return long("0"+self.edit.edit_text)		def get_result(self):		"""Return the numeric result of this cell's operation."""				if self.is_top:			return self.get_value()		if self.result.text == "": 			return None		return long(self.result.text)	def set_result(self, result):		"""Set the numeric result for this cell."""				if result == None:			self.result.set_text("")		else:			self.result.set_text( "%d" %result )		def become_parent(self, column, letter):		"""Change the edit widget to a parent cell widget."""				self.child = column		self.edit = ParentEdit( self.op, letter )		def remove_child(self):		"""Change the edit widget back to a standard edit widget."""				self.child = None		self.setup_edit()	def is_empty( self ):		"""Return True if the cell is "empty"."""		return self.child is None and self.edit.edit_text == ""class ParentEdit(urwid.Edit):	"""Edit widget modified to link to a child column"""		def __init__(self, op, letter):		"""Use the operator and letter of the child column as caption				op -- operator or None		letter -- letter of child column		remove_fn -- function to call when user wants to remove child		             function takes no parameters		"""				urwid.Edit.__init__(self, layout=CALC_LAYOUT)		self.op = op		self.set_letter( letter )		def set_letter(self, letter):		"""Set the letter of the child column for display."""				self.letter = letter		caption = "("+letter+")"		if self.op is not None:			caption = self.op+" "+caption		self.set_caption(caption)			def keypress(self, size, key):		"""Disable usual editing, allow only removing of child""" 				if key == "backspace":			raise ColumnDeleteEvent(self.letter, from_parent=True)		elif key in list("0123456789"):			raise CalcEvent, E_invalid_in_parent_cell		else:			return key		class CellWalker(urwid.ListWalker):	def __init__(self, content):		self.content = urwid.MonitoredList(content)		self.content.modified = self._modified		self.focus = (0,0)		# everyone can share the same divider widget		self.div = urwid.Divider("-")	def get_cell(self, i):		if i < 0 or i >= len(self.content):			return None		else:			return self.content[i]	def _get_at_pos(self, pos):		i, sub = pos		assert sub in (0,1,2)		if i < 0 or i >= len(self.content):			return None, None		if sub == 0:			edit = self.content[i].edit			return urwid.AttrWrap(edit, 'edit', 'editfocus'), pos		elif sub == 1:			return self.div, pos		else:			return self.content[i].result, pos		def get_focus(self):		return self._get_at_pos(self.focus)		def set_focus(self, focus):		self.focus = focus		def get_next(self, start_from):		i, sub = start_from		assert sub in (0,1,2)		if sub == 0:			show_result = self.content[i].show_result(				self.get_cell(i+1))			if show_result:				return self._get_at_pos( (i, 1) )			else:				return self._get_at_pos( (i+1, 0) )		elif sub == 1:			return self._get_at_pos( (i, 2) )		else:			return self._get_at_pos( (i+1, 0) )		def get_prev(self, start_from):		i, sub = start_from		assert sub in (0,1,2)		if sub == 0:			if i == 0: return None, None			show_result = self.content[i-1].show_result(				self.content[i])			if show_result:				return self._get_at_pos( (i-1, 2) )			else:				return self._get_at_pos( (i-1, 0) )		elif sub == 1:			return self._get_at_pos( (i, 0) )		else:			return self._get_at_pos( (i, 1) )				class CellColumn( urwid.WidgetWrap ):	def __init__(self, letter):		self.walker = CellWalker([Cell(None)])		self.content = self.walker.content		self.listbox = urwid.ListBox( self.walker )		self.set_letter( letter )		urwid.WidgetWrap.__init__(self, self.frame)		def set_letter(self, letter):		"""Set the column header with letter."""				self.letter = letter		header = urwid.AttrWrap(			urwid.Text( ["Column ",('key',letter)],			layout = CALC_LAYOUT), 'colhead' )		self.frame = urwid.Frame( self.listbox, header )				def keypress(self, size, key):		key = self.frame.keypress( size, key)		if key is None: 			changed = self.update_results()			if changed:				raise UpdateParentEvent()			return				f, (i, sub) = self.walker.get_focus()		if sub != 0: 			# f is not an edit widget			return key		if OPERATORS.has_key(key):			# move trailing text to new cell below			edit = self.walker.get_cell(i).edit			cursor_pos = edit.edit_pos			tail = edit.edit_text[cursor_pos:]			edit.set_edit_text( edit.edit_text[:cursor_pos] )						new_cell = Cell( key )			new_cell.edit.set_edit_text( tail )			self.content[i+1:i+1] = [new_cell]						changed = self.update_results()			self.move_focus_next( size )			self.content[i+1].edit.set_edit_pos(0)			if changed:				raise UpdateParentEvent()			return					elif key == 'backspace':			# unhandled backspace, we're at beginning of number			# append current number to cell above, removing operator			above = self.walker.get_cell(i-1)			if above is None:				# we're the first cell				raise ColumnDeleteEvent( self.letter, 					from_parent=False )						edit = self.walker.get_cell(i).edit			# check that we can combine			if above.child is not None:				# cell above is parent				if edit.edit_text:					# ..and current not empty, no good					raise CalcEvent, E_cant_combine				above_pos = 0			else:					# above is normal number cell				above_pos = len(above.edit.edit_text)				above.edit.set_edit_text( above.edit.edit_text +					edit.edit_text )			self.move_focus_prev( size )			self.content[i-1].edit.set_edit_pos(above_pos)			del self.content[i]			changed = self.update_results()			if changed:				raise UpdateParentEvent()			return				elif key == 'delete':			# pull text from next cell into current			cell = self.walker.get_cell(i)			below = self.walker.get_cell(i+1)			if cell.child is not None:				# this cell is a parent				raise CalcEvent, E_cant_combine			if below is None:				# nothing below				return key			if below.child is not None:				# cell below is a parent				raise CalcEvent, E_cant_combine						edit = self.walker.get_cell(i).edit			edit.set_edit_text( edit.edit_text +				below.edit.edit_text )			del self.content[i+1]			changed = self.update_results()			if changed:				raise UpdateParentEvent()			return		return key		def move_focus_next(self, size):		f, (i, sub) = self.walker.get_focus()		assert i<len(self.content)-1				ni = i		while ni == i:			self.frame.keypress(size, 'down')			nf, (ni, nsub) = self.walker.get_focus()		def move_focus_prev(self, size):		f, (i, sub) = self.walker.get_focus()		assert i>0				ni = i		while ni == i:			self.frame.keypress(size, 'up')			nf, (ni, nsub) = self.walker.get_focus()							def update_results( self, start_from=None ):		"""Update column.  Return True if final result changed.				start_from -- Cell to start updating from or None to start from		              the current focus (default None)		"""				if start_from is None:			f, (i, sub) = self.walker.get_focus()		else:			i = self.content.index(start_from)			if i == None: return False				focus_cell = self.walker.get_cell(i)				if focus_cell.is_top:			x = focus_cell.get_value()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -