Advanced Modding - GUI Widgets


In this tutorial I'll show you how to use the Widget mechanic provided by Miner's Basic.


4/10 - Moderately Easy


Forge Version

This Tutorial was created with Forge for Minecraft 1.8. If anything doesn't work with other versions, please contact me!


This tutorial requires at least version 1.0-b.325 of Miner's Basic.

Why using Widgets?

Miner's Basic offers the ability to create a GUI not from raw code but with simple widgets. Those widgets have several advantages compared to raw code:

  • The code is easier to read
    You can place all the complicated rendering code in a widget class. The GUI class itself only contains references to those classes which makes it way easier to understand what the GUI does.
  • The GUI is easier to modify
    Changes can be made in seconds. One image is a few pixels too large? Change the size in the constructor of the GUI instead of spending hours of searching for the right rendering line!
  • Easiest way to add tooltips or scrollbars
    Each widget has the ability to show a tooltip. This can be used to create well-documented controls in your GUI.
    The WidgetScrollableContainer class is the easiest way to add scrollbars or a draggable surface.
  • And a lot more...

If this has not persuaded you yet, take a look at this example:

Here I've created a GUI with a draggable layer with several icons on it that can be clicked to open a book-like information window.

In the upper box you can see the code for this GUI without widgets and in the lower one with widgets.

(Note that the two examples don't exactly look the same, the widget example has some features the other one hasn't. I also didn't show everything, only the GUI class, but you can get an overview on the differences).

Code without widgets - Show
Code with widgets - Show

As you can see here, the code with widgets is much easier to read and understand, even if you don't exactly know what the widgets used there do.

By the way, the code with widgets is way more powerful as well.

Using Widgets for a GUI

Don't worry, we won't create such a complicated example as I showed you above. Instead, we'll start with something very simple.

For this example, I'll use a subclass of GuiScreen, but you can do it with a subclass of GuiContainer as well. However, you then need to use the method renderBackgroundLayer instead of drawScreen.


The first thing we need to create is an instance of the class WidgetTreeParent (minersbasic.api.client.gui.widgets.WidgetTreeParent). We can store this in the GUI as a variable named root.
public class GuiWidgetTutorial extends GuiScreen {

    public WidgetTreeParent root;

    public GuiWidgetTutorial() {
        this.root = new WidgetTreeParent();

The WidgetTreeParent does exactly what it's name says, it's the parent of a widget tree. It has several methods that need to be hooked into the methods of the GUI.

Therefore, we need to override

drawScreen() (or renderBackgroundLayer), handleMouseInput() and handleKeyboardInput().

If we do not want to process keyboard or mouse input we can leave those methods out, but generally its good to create all of them:
public void drawScreen(int mouseX, int mouseY, float partialTicks) {

public void handleMouseInput() throws IOException {

public void handleKeyboardInput() throws IOException {

The method drawDefaultBackground is not necessary, but useful because it draws the standard GUI background.

If you are using a subclass of GuiContainer, this is done automatically, so you don't need to add the method there.

It is very important that you use the method drawWidgetTree to draw the tree and not doDraw. Thats because drawWidgetTree refreshes the scaled resolution and prepares some other stuff which is necessary for the GUI to work properly.

Now we can add our GUI content.

It's useful to add a WidgetCenteredContainer (minersbasic.api.client.gui.widgets.WidgetCenteredContainer) first, because it will always keep it's content centered, depending on it's size.

As an example, I'll use the size 150*180:
public WidgetCenteredContainer center;

public GuiWidgetTutorial() {
    this.root = new WidgetTreeParent(); = new WidgetCenteredContainer()
            .setSize(new Dimensions(150, 180));


As you can see here, every setter method returns the object itself so they can be chained like this.

The class Dimensions (minersbasic.api.client.render.Dimensions) I used here is a class defining the a size. It contains one variable for width and one for height.

Now we have a centered GUI, but with nothing in it yet. So, for example, we can add a background image.

What are the specifications of this background image?

  • It covers the whole available space (size = 150*180)
  • It's top-left corner is located in the top-left corner of the available space
  • It displays the correct image

These specifications can easily be translated into the correct method calls:
public static Image bg = new Image("tutorial:textures/gui/container/widgetbg.png");

public WidgetImage backgroundimage;

public GuiWidgetTutorial() {
    this.root = new WidgetTreeParent(); = new WidgetCenteredContainer()
            .setSize(new Dimensions(150, 180));
    this.backgroundimage = new WidgetImage()
            .setPosition(new AlignedPosition(0, 0, Align.TL))
            .setSize(new Dimensions(150, 180))


Here, we're creating out image.

The first method in green sets the position. Here the class AlignedPosition (minersbasic.api.client.gui.AlignedPosition) is used. This class does not only tell the position, but also the alignment of the widget. Here's an example:

The AlignedPosition new AlignedPosition(100, 100, Align.TL) or shorter new AlignedPosition(100, 100) can be visualized like this:

This is how the AlignedPosition new AlignedPosition(-100, -50, Align.CR) looks like:

I could create more of those pictures, but I think you understand what I mean.

The next setter method in red defines the size of the Image. This is nothing special, we had that before with the centered container.

The last setter method in blue sets the image that should be displayed. Here, it's necessary that the image object is created as a static object, so that we don't need to take care when we release the RAM. The image will now be displayed as the background of our GUI in the very center of the screen.

Note that the image file needs to have the size 150*180 (or multiples of the size, like 300*360)

You can try the GUI out now; if you have the texture file located at the correct place, it will be displayed in the center of the screen.

You've just created a GUI with widgets!

List of widget types in Miner's Basic

Here I've collected all the Widgets in Miner's Basic. Please note that I cannot explain every method in detail here, that would be way to much but most of them are self-explanatory or explained in the Javadoc. If you have problems anyway, please contact me.

To find certain methods, just use Code-Completion.

  • Widget
    Base class for all widgets. Provides methods to set the position, size, zLevel, widget event handlers, tooltip or visibility.
  • WidgetContainer extends Widget
    Container for several sub-widgets. Provides methods to add or remove widgets.
    The position and align of sub-widgets depends on the Container, not on the whole GUI. If the container is made invisible, the sub-widgets are invisible as well.
    • WidgetCenteredContainer extends WidgetContainer
      The same as the container, but it is always centered in it's parent's space.
    • WidgetScrollableContainer extends WidgetContainer
      A container which can contain a larger space than it occupies. Provides methods to set the container space and the scrolling mode. Available modes are horizontal, vertical or both scrollbars or dragging mode.
    • WidgetTreeParent extends WidgetContainer
      The main container for every widget tree. Provides methods to hook into a GUI.
  • WidgetColoredRect extends Widget
    A colored rectangle. Provides methods to set the color.
  • WidgetImage extends Widget
    A textured rectangle. Provides methods to set the image and the ImageMode, which defines how the image is resized. The different possibilities are RESIZE, FITINSIDE, FIXEDHEIGHT and FIXEDWIDTH. They are explained in detail in the Javadoc.
    • WidgetImageButton extends WidgetImage
      An image with button behaviour. Sends click events to every registered event handler. Has three additional images for hovering, clicking and disabled state. Provides methods to set those and all at once. Note that no Image is set when created.
  • WidgetLabel extends Widget
    A simple text label. Provides methods to set the text, the inner alignment, the text color and to turn word-wrap on and off.
  • WidgetProgressBar extends Widget
    A progress bar with an optional progress text (by default the percentage). Provides methods to change the minimum and maximum value, the current value, the foreground and background images and the text color. It also allows to turn the text off completely.
  • WidgetTextButton extends Widget
    A button showing a text, similar to Minecraft vanilla buttons. Provides methods to change the images, the text color and the caption. Sends click events to every registered event handler.
    • WidgetIconButton extends WidgetTextButton
      A 20*20 button showing a 16*16 icon. Provides methods to change the icon.
    • WidgetIconTextButton extends WidgetTextButton
      A button showing an icon as well as a text. Provides methods to change the icon.
  • WidgetTextEdit extends Widget
    A text editor widget. Provides methods to change the text and text color and to switch between single- and multiline mode.
  • WidgetSelectBox extends Widget
    A box that allows the selection of one of several predefined values. Provides methods to change those values.
  • WidgetCheckbox extends Widget
    A checkbox with a caption. Provides methods to change the state and the caption.
  • WidgetSlider extends Widget
    A slider similar to those used to edit the music volume in Minecraft. Provides methods to change the minimum and maximum value, the current value, the images and the text color.

Widget event handler

It is possible to create an event handler for certain widgets. There are two types of event handlers, namely normal and direct event handlers. Normal handlers (interface minersbasic.api.client.gui.widgets.IWidgetEventHandler) receive events produced by the widget, for instance click events by a button widget. Direct event handlers (interface minersbasic.api.client.gui.widgets.IDirectWidgetEventHandler) can be used to intercept user input, they receive events when the mouse was clicked or the user pressed a key.


Each widget has methods to register both event handler types:

widget.addEventHandler(IWidgetEventHandler handler);

widget.addDirectEventHandler(IDirectWidgetEventHandler handler);

The method in the interface is called when an event is posted. An event consists of the sender and an action command, or for the direct event the sender, a type and an action command and optionally additional data.


Direct events are only available for the widget itself while normal events are passed up the hierarchy until they are marked as processed or reach the WidgetTreeParent. This means that a direct event handler must be registered with the widget it should work with.

A list of direct events can be found in the javadoc of the interface IDirectWidgetEventHandler.

Normal events are listed in the javadoc of the corresponding widget class.

Here's an example for an event handler that reacts to a button being pressed:
this.button.addEventHandler(new IWidgetEventHandler() {
    @Override public boolean onAction(Widget sender, String actionCommand) {
        if (sender == this.button && actionCommand.equals("click")) {
            this.doSomething(); return true;
        } else
            return false;

If an event handler returns true, the event is processed and no longer passed to the parents or other event handlers.

Creating custom widgets

It is possible to create custom Widgets by just extending a Widget class. If you want to create a completely new widget, you need to override the method draw() and add the rendering code there, depending on the widget's state.

You can also override the direct event methods, like onMouseClick or similar, but you always need to check if the superclass method returns true, because then the event has been processed:
protected boolean onMouseDown(int x, int y, int button) {
    if (super.onMouseDown(x, y, button))
        return true;
    // Do whatever you want here.
    return true; //Or false, depending on what you've done

If you want to post an event in your widget, you can use the method postEvent. This will trigger the receiveEvent method in your widget and pass the event to the parents if it was not processed.
this.postEvent(this, "click");

Here, "click" is the action command that will be sent.


If your widget needs to have a specific size or if the size needs to be in a certain range, you can fix it.

Set the perfect size or the perfect minimum and maximum size and call fixSize(true) or fixSizeRange(true).

Then the size (or size range) cannot be changed anymore.

With these tips and the widgets that exist already it should be easy to create custom widgets that fit your needs.

They can be really small, but they are very useful. For instance, I've created a widget called WidgetHeatStatus, which is nothing but a retextured WidgetProgressBar for furnaces, but it shortens the code a lot.

A few notes

Just some notes here that are interesting to know.

  • Every caption or tooltip will be translated. That means you can set the caption of a button to "button.clear_inventory" and add this key to your language file. However that also means that the percentage sign '%' serves as a formatter. To add a percentage sign to the text, you need to double it ("%%").
  • The tooltip can have a delay. To use it, set the variable TOOLTIP_DELAY to a differnt value than 0. (Note that this variable is protected)
  • Remember to use setZ(float value) to set the z level of your widgets. It may be useful to set it to 1 for most of the widgets to avoid rendering bugs.

I don't provide a code download link as GUIs are so different from each other, there cannot be a perfect solution.

Recommended tutorials to continue with

Advanced Modding:

  • Creating an ingame GUI

Comments and Questions:

If you want to report modding problems, please make sure to include the code in a pastebin link or something else! Don't just write "It doesn't work", otherwise your post will be deleted. For more complicated problems, please use the troubleshooter form.