定制 GUI 的Control节点

已经有好多control节点了...

然而,这远远不够。创建您的自定义控件,并使其按您希望的方式工作,这几乎是每个GUI程序员都向往的事情。Godot提供了大量这样的工具,但它们可能并不完全如您所愿的方式工作。在使用支持对角滚动条的下拉请求与开发人员联系之前,至少应该了解如何从脚本轻松地创建这些控件。

绘制

谈到绘制, 推荐看看这篇 2D中的自定义绘图 的教程。同样的原理适用与控件绘制。这里有些函数值得一提, 因为它们在绘制时有用, 所以接下来将进行详细说明:

检查控件的大小

Unlike 2D nodes, "size" is important with controls, as it helps to organize them in proper layouts. For this, the Control.rect_size property is provided. Checking it during _draw() is vital to ensure everything is kept in-bounds.

检查输入焦点

Some controls (such as buttons or text editors) might provide input focus for keyboard or joypad input. Examples of this are entering text or pressing a button. This is controlled with the Control.focus_mode property. When drawing, and if the control supports input focus, it is always desired to show some sort of indicator (highlight, box, etc.) to indicate that this is the currently focused control. To check for this status, the Control.has_focus() method exists. Example

func _draw():
    if has_focus():
         draw_selected()
    else:
         draw_normal()
public override void _Draw()
{
    if (HasFocus())
    {
        DrawSelected()
    }
    else
    {
        DrawNormal();
    }
}

调整大小

As mentioned before, size is important to controls. This allows them to lay out properly, when set into grids, containers, or anchored. Controls, most of the time, provide a minimum size to help properly lay them out. For example, if controls are placed vertically on top of each other using a VBoxContainer, the minimum size will make sure your custom control is not squished by the other controls in the container.

To provide this callback, just override Control.get_minimum_size(), for example:

func get_minimum_size():
    return Vector2(30, 30)
public override Vector2 _GetMinimumSize()
{
    return new Vector2(20, 20);
}

Alternatively, set it using a function:

func _ready():
    set_custom_minimum_size(Vector2(30, 30))
public override void _Ready()
{
    SetCustomMinimumSize(new Vector2(20, 20));
}

输入

控件(Control)节点提供了一些帮助, 使管理输入事件比常规节点容易得多。

输入事件

在此之前有几个关于输入的教程, 但值得一提的是, 控件有一个特殊的输入方法, 只有在以下情况下才起作用:

  • 鼠标指针悬停在控件上。
  • 鼠标按键在此控件上被按下 (控件始终捕获输入, 直到按钮被释放)
  • Control provides keyboard/joypad focus via Control.focus_mode.

This function is Control._gui_input(). Simply override it in your control. No processing needs to be set.

extends Control

func _gui_input(event):
   if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:
       print("Left mouse button was pressed!")
public override void _GuiInput(InputEvent @event)
{
    if (@event is InputEventMouseButton mbe && mbe.ButtonIndex == (int)ButtonList.Left && mbe.Pressed)
    {
        GD.Print("Left mouse button was pressed!");
    }
}

有关事件(event)本身的详细信息, 请查看 InputEvent 教程。

通知

Controls also have many useful notifications for which no dedicated callback exists, but which can be checked with the _notification callback:

func _notification(what):
    match what:
        NOTIFICATION_MOUSE_ENTER:
            pass # Mouse entered the area of this control.
        NOTIFICATION_MOUSE_EXIT:
            pass # Mouse exited the area of this control.
        NOTIFICATION_FOCUS_ENTER:
            pass # Control gained focus.
        NOTIFICATION_FOCUS_EXIT:
            pass # Control lost focus.
        NOTIFICATION_THEME_CHANGED:
            pass # Theme used to draw the control changed;
            # update and redraw is recommended if using a theme.
        NOTIFICATION_VISIBILITY_CHANGED:
            pass # Control became visible/invisible;
            # check new status with is_visible().
        NOTIFICATION_RESIZED:
            pass # Control changed size; check new size
            # with get_size().
        NOTIFICATION_MODAL_CLOSE:
            pass # For modal pop-ups, notification
            # that the pop-up was closed.
public override void _Notification(int what)
{
    switch (what)
    {
        case NotificationMouseEnter:
            // Mouse entered the area of this control.
            break;

        case NotificationMouseExit:
            // Mouse exited the area of this control.
            break;

        case NotificationFocusEnter:
            // Control gained focus.
            break;

        case NotificationFocusExit:
            // Control lost focus.
            break;

        case NotificationThemeChanged:
            // Theme used to draw the control changed;
            // update and redraw is recommended if using a theme.
            break;

        case NotificationVisibilityChanged:
            // Control became visible/invisible;
            // check new status with is_visible().
            break;

        case NotificationResized:
            // Control changed size; check new size with get_size().
            break;

        case NotificationModalClose:
            // For modal pop-ups, notification that the pop-up was closed.
            break;
    }
}