text input widget

Where should I look if I want to implement a text input widget, maybe for a chat interface for example. Or even a python console. Is there anything like that already built in?

If not, how hard would it be for me to implement one in panda3d?


There is one already built-in, the DirectEntry. Unfortunately, it is not yet documented in the manual, but it is very similar to the other DirectGUI widgets.

Interesting keywords you can set on DirectEntry include width (maximum width in screen units), numLines (default 1), command (func called when enter pressed), and cursorKeys (boolean flag whether cursor keys are enabled, default 0). See direct/src/DirectEntry.py for more.


Great. So the gui menu that appears on one of the toon town screenshots is custom made? Is there GUI support for more sophiscated widgets like that? What are all the widget types that are built in? I looked at direct/src, and didn’t find a directmenu, so thought to ask.

The Toontown chat menu is built up out of the lower-level DirectGui primitives with custom code (it stacks up a bunch of DirectButtons inside a DirectFrame).

But you might be interested in DirectOptionMenu, which provides a quick popup menu. There’s also a DirectScrolledList which can be a long list of buttons with a scroll bar.

If you don’t need either of those fancy things but you just want a long list of buttons like the Toontown menu, it doesn’t take much code to do it.


Hi, I’m not the OP but I’m trying to use a DirectEntry and it simply doesn’t seem to work. No matter what parameters I give it, it doesn’t display any text I type, and the command function is never called when I press enter. Is there something complicated I need to do to give it focus, or what?
Also, the manual doesn’t actually say how to get access to the text, and from what I can tell the API doesn’t either. Is it passed to the command function?


Looks like there’s a little bug in the current implementation of DirectEntry when you do not supply a background image. You will need to explicitly specify frameSize = (0, width, 0, 1) to get the frame to set itself up correctly (we’ll get this bug straightened out in a future release of Panda). Here’s an example:

from direct.directbase.DirectStart import *
from pandac.PandaModules import *
from direct.gui.DirectGui import *

def handleCommand(value):
    print "value = %s" % (value)

entry = DirectEntry(width = 15,
                    numLines = 1,
                    scale = 0.07,
                    relief = SUNKEN,
                    cursorKeys = 1,
                    frameSize = (0, 15, 0, 1),
                    command = handleCommand)

The text that is typed into the entry will be passed to the command function; you can also retrieve it via entry.get().

You can set focus into the entry by clicking on it (this will work once you have the width set properly, above) or programatically by calling entry.setFocus().


Hi, I wrote the previous message about DirectEntry. I did get it to work from what you said, but the code seems somewhat buggy…when I tried to scale the text, I got things like this:

where the cursor is still relative to the size of the field, not the text (so the text can continue out of the field since the cursor hasn’t reached the end of the line yet). Is there any way around this?

The text_scale parameter is not supported for DirectEntry. Instead, just change the scale parameter to make the whole entry larger.


OK, thanks.

Also, is there anything in the API that describes which parameters an object can take and/or needs to function correctly? I’m trying to make a DirectOptionMenu but have no idea what to give it. When I try to do the bare minimum, I get an error when I try to click on it that says "DirectOptionMenu instance has no attribute ‘minZ’, but minZ itself is an unknown option. Setting the frameSize didn’t help. I assume the lists are similar to the way DirectDialog works, but I don’t know what they’re actually called.

Never mind, just found the options() method.

We do have some more work to do to document the whole DirectGUI system better. :slight_smile:


David - meet Ryan Myers (ram), one of my employees this summer. He is working on the DirectGui manual pages right now. :slight_smile:

Yeah, I should have mentioned that, sorry.

New question: I’m trying to use a slider, and it appears and seems to work properly, although some of the options don’t appear to do anything…but I get an error when I try to get the slider’s value. When I try to use getPercent(), I get:

File “C:\Panda3D-1.0.4\direct\src\gui\DirectSliderBar.py”, line 118, in getPercent
return self.guiItem.getPercent()
AttributeError: PGSliderBar instance has no attribute ‘getPercent’

although I didn’t see anything in the API that indicates that this would be a problem. It also appears that DirectSliderBar has no getValue() method, even though it has the corresponding set method.

Welcome ram.

You can check the sound tutorial for how I figured out how to use DirectSliders. I remember that it wasn’t as easy as it should be. As long as you are writing manual pages for the direct widgets, it would probably be a good idea to thouroghly test all of them and record bugs and interfaces that could be improved, as there probably are many. And if you have time this summer, fix them. It would be great to get the gui system fixed up and polished.

Hi Ryan, glad to meet you!

Yep, looks like a bug in the DirectSliderBar.py code. Probably getPercent() is intended to be called getValue(). My guess is that the person who wrote DirectSliderBar originally called these functions percent, then changed his mind to call them value, and missed a case.


Why does frameSize take 4 parameters? length, width, height, …?

Also, I’ve been looking through the options and found a fair number of keywords that don’t appear to do anything or don’t give any indication of their use:
enableEdit: I can still slide sliders and enter text in DirectEntries when this is 0
borderWidth: As far as I can tell it only affects the loading bar in DirectWaitBar, making barBorderWidth do nothing instead.
pgFunc: I just assume this is something that shouldn’t ever be changed, but I want to include it in the manual for completeness if it might be relevant
suppressKeys and Mouse: keys seems to be always on 0 and mouse on 1, but the mouse or keys don’t seem to be suppressed no matter which value it has
invertedFrames, sortOrder, guiID: no idea what these are supposed to signify
frameTexture: same as geom?

Speaking of which, what does the geom option mean exactly…what kinds of NodePaths specify geometry?


The four parameters of frame size are left, right, bottom, top–the position of each edge of the frame relative to the gui item’s origin. It should more accurately be called frame extents, I suppose.

enableEdit is used in conjunction with direct-gui-edit. When direct-gui-edit is set to true in your Config.prc, you can use the middle mouse button to move and, when the control key is held down, resize these widgets on the fly. Set enableEdit to 0 on any particular widget to disallow this feature.

borderWidth controls the thickness of the bevel when relief is RAISED, SUNKEN, GROOVE, or RIDGE. It has no effect when relief is FLAT or None.

pgFunc defines the constructor method to create the appropriate underlying Panda object for the gui item. Normally you should not change it, but there may be cases when you have a custom Panda object that you want to create for a widget. You have to know what you’re doing.

suppressKeys and suppressMouse refer to the button events that are generated outside of the DirectGUI system. If you have suppressKeys enabled, then a key pressed while the mouse is over the dialog will not generate the corresponding global Panda event. Similarly for suppressMouse and the mouse buttons and mouse events.

When invertedFrames is true, it reverses the meaning of RAISED vs. SUNKEN.

sortOrder controls the rarely-specified second parameter to all NodePath reparenting operations; this is an advanced NodePath feature to control order among siblings. It is useful for DirectGUI objects because sibling order determines render order, so it may be necessary to specify this if you have overlapping elements.

guiId overrides the unique internal identifier automatically generated for each gui element; this identifier is used to generate internal event names, etc. Normally you would not want to override the default behavior unless you are doing something really advanced and fancy–again, you should know what you are doing.

frameTexture is the texture that is applied to the frame geometry generated when relief is not None. It is unrelated to geom, which is an arbitrary model that is placed behind the widget, although usually the purpose of geom is to replace the frame (so you typically set relief to None when you specify a geom). Any NodePath can serve as a geom; presumably its source is from a model that an artist created and you loaded through the normal channels. Another common geom source is an egg file created via egg-texture-cards from a particular texture image.


Thanks! That’ll be really useful.

Hopefully just a few more questions before I start on the tutorial…

numStates and state? Most of them start off ‘disabled’ (or ‘normal’)…I know Panda has FSMs but is it ever actually relevant? Label has activeState which can be used to hide it, but isn’t that what hide() is for?

textMayChange-I know how this works for OptionMenus but it doesn’t seem to do anything for DirectEntries and I don’t know when else it would be relevant, but it shows up as an option for everything…

I’m also a little confused about the ScrolledList…when I try to make it with more items than numItemsVisible, I don’t see any way to actually scroll other than the scroll…() methods in the API, but that undermines the need for the scrollSpeed option. Also, any info on itemMakeExtraArgs and itemMakeFunction would be great.

Few more questions…
I’m guessing that the itemMakeFunction is called when a new item is added to the list? I can’t test this, though, because when I try to call addItem(item, refresh) as it says in the API, (I assume ‘refresh’ is a boolean but it doesn’t say), I get:
Traceback (most recent call last):
File “helloworld.py”, line 147, in ?
scroll.addItem(button5, 0)
File “C:\Panda3D-1.0.4\direct\src\gui\DirectScrolledList.py”, line 318, in add
AttributeError: ‘tuple’ object has no attribute ‘append’

So I don’t know how that’s supposed to work.

Also, only DirectGuiWidgets can be added to the list, right? When I tried something else I got AttributeError: NodePath instance has no attribute ‘getHeight’, so I assume that only something with that method can be added.
Furthermore, what is ‘command’ supposed to do? When I add buttons to the list they just do their own command, and when I add labels they don’t do anything when I click on them…when is the list’s command called?
Finally (for now), what does the ScrolledList method makeAllItems(self) do, and when the API says item or itemID, is the former the index and the latter a string, or what?

Thanks for your patience.

The state of a DirectGUI item is a fairly advanced feature, and gets a little complicated.

Every DirectGUI item has multiple “states”. In the case of a button, for instance, there are four states: ready, press, rollover, disabled. The button might have a different appearance in each state; for instance, in the “press” state its bevel is reversed, to simulate the button being depressed, and in the “rollover” state it is drawn a little brighter. In the case of a button, the state transitions are implicit and happen automatically as the mouse rolls over the object.

You can also set a DirectGUI object to a particular state programmatically, which is particularly useful for setting the state to DISABLED. (Use DISABLED instead of ‘disabled’; use NORMAL instead of ‘normal’.)

When you create a DirectGUI object, you can explicitly specify the appearance for each state by passing an n-tuple for the corresponding appearance parameter, for instance text = (‘alpha’, ‘beta’, ‘gamma’, ‘delta’) sets a different text label for each state of the button, while the normal interface of text = ‘alpha’ just implicitly replicates the label four times.

You can also define additional states for your own purpose; you would do this by specifying numStates and then calling setState() from time to time to change the state.

A DirectLabel by default has only one state. If you wanted to, you could create additional states for it. If you did this, you might want to change which state is considered the “active” or normal state; you would do this by specifying activeState. By default, activeState is 0, the first state. If you set this to, for instance, 1, and did not change the value of numStates, then you have specified that the default state for the label is an undefined state, which is why the label appears to disappear. But that’s not the intended purpose for this feature.

The answers to your other questions are forthcoming.