More useful widgets¶
Now that we’ve seen how all the basic widget customizations work, we can introduce some of the widgets that really rely on those customizations.
Frame — pretty outlines¶
The purpose of the Frame
widget is to put a nice border around another
widget. It achieves this effect by delegating to two inner classes:
Decoration
and Box
.
Decoration
is responsible for drawing the border. There’s no actual widget
called “Decoration”, that’s just the name of the inner class you have to
provide. Any widget can be the decoration, but Background
and Image
are
the most common choices.
Box
is responsible for containing the widget (or widgets) that will go in
the frame. This usually means setting a padding to keep the contents of the
frame far enough away from it border. Once again, there’s no actual widget
called box, but the box is almost always a Bin
. We haven’t talked about
Bin
before, but it’s just a simple container that holds one widget at a time.
It’s possible to make the box any kind of container you want – sometimes
Grid
is useful for highly structured frames – but you’ll probably have to
override the add() and clear() methods of your subclass to make them do
something reasonable.
Those last two paragraphs were a little abstract, so hopefully an example will make things more concrete:
Notice that the padding we specified for the bin keeps the placeholder an appropriate distance from the edge of the frame.
Dialog — popup messages¶
Dialog boxes are widgets that appear with a brief message or question for the
user, and disappear when the user clicks a button to acknowledge the message or
answer the question. There are two dialog box widgets provided by glooey:
OkDialog
and YesNoDialog
. The former comes with a single button that
simply closes the dialog. The latter comes with two buttons that both close
the dialog, but it remembers which one was clicked. There are also a few
dialog superclasses that you can use if you want even more buttons, but those
are beyond the scope of this tutorial.
Dialog boxes are configured much like frames, but there are a few differences
to be aware of. First, the Box
inner class must be a Grid
1 because
the dialog needs a grid to position its buttons relative to its content.
Second, there is an inner class called Buttons
that you can use to control
the alignment and padding of the buttons in the dialog box. Typically
Buttons
is an HBox
, but anything with an add()
method will work.
Third, there are inner classes for each button in the dialog box. For
OkDialog
, this is OkButton
; for YesNoDialog
, this is YesButton
and
NoButton
. Finally, unlike every other widget, dialog boxes do not need to be
added to a parent widget. Instead, they are displayed by calling their
open()
method with the root GUI widget as the argument.
This example shows how to use YesNoDialog
:
Form — text input¶
The Form
widget allows users to provide text input. It has three inner
classes you can customize: Label
, Base
, and Focused
. Label
draws the text and – this is a little bit of a gotcha – should inherit from
EditableLabel
(not Label
). Base
draws the form when it doesn’t have
focus, and Focused
draws it when it does. These two inner classes usually
inherit from Background
or Image
. Focused
is optional. If you don’t
provide it, the form will just stay in its base state all the time. You can
use the form’s on_unfocus
event in conjunction with the its text property
to get the string the user entered:
ScrollBox — fit large content¶
The ScrollBox
widget allows the user to scroll around a widget that might
otherwise be too large to fit in the GUI. It has a number of different parts
(the background, the scroll bars, the scroll grips, etc) and each one can be
configured with a different inner class:
Frame
: This inner class controls the background and padding for the actual content being scrolled. As the name implies, it typically inherits fromFrame
.VBar
: This inner class is responsible for the vertical scroll bar. It inherits fromVScrollBar
and contains the following inner classes and custom attributes:Decoration
: The background of the scroll bar, which typically inherits from Background. Note that this background extends behind the forward and backward buttons (if they are present), so you may need to add a padding to get the background to line up with the region the grip can move in.Forward
: The button that will scroll “forward” (down for a vertical scroll bar, right for a horizontal one). This inner class typically inherits fromButton
.Backward
: The same as forward, but for scrolling in the other direction.Grip
: The button that you can click on and drag around to scroll. This inner class typically inherits from eitherButton
(if you want to react to mouse hovers and clicks) orImage
orBackground
(if you don’t).custom_scale_grip
: If true, the size of the scroll grip will be proportional to the fraction of the content that is currently visible. Note that the effect will not work right unless the grip class is able to expand vertically. This requires that its alignment be'fill'
and that it usesBackground
(either directly or viaButton
).
Note
If no
VBar
inner class is specified, the scroll box will not be scrollable in the vertical direction. Likewise forHBar
and horizontal scrolling. Therefore, a class that inherits fromScrollBox
but that doesn’t implement eitherHBar
orVBar
will not actually be scrollable. This is an easy mistake to make.Note
If you want to have both vertical and horizontal scroll bars: put all your customizations in a common class that doesn’t inherit from any widget, then use multiple inheritance to derive
HBar
andVBar
classes that derive from both the common class and eitherHScrollBar
orVScrollBar
.HBar
: This inner class is responsible for the horizontal scroll bar. It’s pretty much identical toVBar
, but it inherits fromHScrollBar
.Corner
: This inner class fills in the space created by the two scroll bars in the bottom right corner of the scroll box. It typically inherits fromImage
, and it will only be displayed if there are two scroll bars.
- 1
Strictly speaking, the
Box
inner class only needs to be aGrid
if you’re inheriting fromButtonDialog
or one of its subclasses (which includeOkDialog
andYesNoDialog
). It can be whatever you want if you’re directly inheriting fromDialog
.