Unfortunately, this may format poorly. Here’s an example that builds upon
the DirectFrame base.
Usage is:
myConsole=DirectConsole()
myConsole[“lineLimit”]=6
myConsole[“lineLength”]=40
myConsole.addLine(“Hi There”)
myConsole.addLine(“I’m a console!”)
import direct.directbase.DirectStart
from direct.gui.DirectGui import *
class DirectConsole(DirectFrame):
def __init__(self,parent = None, **kw):
#The beginning portion of a DirectGui element
#adds any extra options into the list that it needs
#
#We'll keep these in the options set to avoid
#adding too many functions
#
#lineLength- determines how wide the console is
#lineLimit- determines how tall the console is
optiondefs = (
# Define type of DirectGuiWidget
('lineLength', 20, self.changeText),
('lineLimit', 14, self.changeText),
)
# Merge keyword options with default options
self.defineoptions(kw, optiondefs)
DirectFrame.__init__(self,parent, **kw)
#I'd really like to use DirectLabel here,
#but I need to futz with its internals
#because by default text is centered
#
#Also, even though there is a wordwrap
#option, it messes up the notion of a
#scroll bar limiting lines
self.window=OnscreenText(
parent=self,
align=TextNode.ALeft)
self.scroll=DirectScrollBar(parent=self,
orientation=VERTICAL,
command=
self.updateText,
#setting frame relative
#to scale
scale=.05,
frameSize=
(-.5,.5,-10,10),
#keep setup simple
resizeThumb=False,
manageButtons=True,
#make each button
#a basic square
thumb_relief=1,
decButton_relief=1,
incButton_relief=1,
)
self.window.setScale(.05)
self.window.setZ(.45)
self.internalText=[]
self.cachedText=[]
self.changeText()
#anytime we throw a new line in,
#jump the scroll bar to the bottom.
#This has the added benefit of updating the text
def addLine(self,text):
self.internalText.append(text)
self.scroll["value"]=1
self.changeText()
def changeText(self):
#We do all of the things we don't want to do
#while scrolling
lineLimit=self["lineLimit"]
lineLength=self["lineLength"]
#Make sure the scroll bar is positioned nicely
#relative to the window. The 1-lineLimit/14.0
#is basically hardcoded to keep the window
#upper-left oriented
self.scroll["frameSize"]=(-.5,.5,
((1-(lineLimit/14.0))-.5)*20,10)
self.scroll.setX(lineLength/50.0+.05)
finalText=""
textList=[]
#format long lines into bad wordwrapped lines
#I'm not being smart, but this is still
#pretty primitive
for line in self.internalText:
while(len(line)>lineLength):
textList.append(line[0:lineLength])
#strip the leftover line, so they don't
#look wierd
line=line[lineLength:].lstrip()
#put the last piece of the line into the list
textList.append(line)
#dump the text into our "cache"
self.cachedText=list(textList)
self.updateText()
def updateText(self):
lineLimit=self["lineLimit"]
finalText=""
numLines=len(self.cachedText)
#If we have more text than we can show
#select the set that fits with the
#current point on the slider bar
if(numLines > lineLimit):
lineToStartAt=int(self.scroll["value"]*
(numLines-lineLimit))
linesLeft=min(lineLimit,numLines-lineToStartAt)
textChunk=self.cachedText[
lineToStartAt:lineToStartAt+linesLeft]
#otherwise, use the whole list, and throw a few
#dummy lines in to keep it lower justified
else:
textChunk=list(self.cachedText)
spotsToAdd=lineLimit-len(textChunk)
finalText="\n"*spotsToAdd
for i in textChunk:
finalText=finalText+i+"\n"
self.window.setText(finalText)