自定义 GUI 控件

控件真多呀……

不过这是永远不嫌多的。每个 GUI 程序员几乎都痴迷于创建自己的自定义控件,让这些控件让自己的要求工作。Godot 提供了大量的控件,但它们可能并不完全如你所愿的方式工作。在使用支持对角滚动条的拉取请求与开发人员联系之前,至少应该了解如何从脚本轻松地创建这些控件。

绘制

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

检查控件的大小

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

检查输入焦点

一些控件(如按钮或文本编辑器)可为键盘或手柄输入提供输入焦点. 这方面的例子是输入文本或按下一个按钮. 这可以通过 Control.focus_mode 属性来控制. 绘制时, 如果控件支持输入焦点, 总是希望显示某种指示来表明(高亮, 方框等), 当前这是焦点控件. 为了检查这个状态, 存在一个 Control.has_focus() 的方法. 例子

GDScriptC#

  1. func _draw():
  2. if has_focus():
  3. draw_selected()
  4. else:
  5. draw_normal()
  1. public override void _Draw()
  2. {
  3. if (HasFocus())
  4. {
  5. DrawSelected()
  6. }
  7. else
  8. {
  9. DrawNormal();
  10. }
  11. }

调整大小

如前所述, 尺寸对控件是很重要的. 这可以让它们在设置网格, 容器或锚定时以正确布局. 控件, 在大多数情况下, 提供了一个 minimum size , 以帮助它们正确布局. 例如, 如果控件被垂直放置在彼此的顶部, 使用 VBoxContainer , 最小尺寸将确保你的自定义控件不会被容器中的其他控件挤压.

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

GDScriptC#

  1. func _get_minimum_size():
  2. return Vector2(30, 30)
  1. public override Vector2 _GetMinimumSize()
  2. {
  3. return new Vector2(20, 20);
  4. }

或者, 使用函数进行设置:

GDScriptC#

  1. func _ready():
  2. set_custom_minimum_size(Vector2(30, 30))
  1. public override void _Ready()
  2. {
  3. CustomMinimumSize = new Vector2(20, 20);
  4. }

输入

控件为输入事件的管理提供了一些辅助工具,比普通节点要方便一点。

输入事件

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

  • 鼠标指针悬停在控件上.

  • 鼠标按键在此控件上被按下 (控件始终捕获输入, 直到按钮被释放)

  • 控件通过以下方式提供键盘和手柄焦点 Control.focus_mode.

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

GDScriptC#

  1. extends Control
  2. func _gui_input(event):
  3. if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
  4. print("Left mouse button was pressed!")
  1. public override void _GuiInput(InputEvent @event)
  2. {
  3. if (@event is InputEventMouseButton mbe && mbe.ButtonIndex == MouseButton.Left && mbe.Pressed)
  4. {
  5. GD.Print("Left mouse button was pressed!");
  6. }
  7. }

有关事件本身的详细信息,请查看 使用 InputEvent 教程。

通知

控件也有许多有用的通知, 这些通知不存在专门的回调, 但可以用_notification回调来检查:

GDScriptC#

  1. func _notification(what):
  2. match what:
  3. NOTIFICATION_MOUSE_ENTER:
  4. pass # Mouse entered the area of this control.
  5. NOTIFICATION_MOUSE_EXIT:
  6. pass # Mouse exited the area of this control.
  7. NOTIFICATION_FOCUS_ENTER:
  8. pass # Control gained focus.
  9. NOTIFICATION_FOCUS_EXIT:
  10. pass # Control lost focus.
  11. NOTIFICATION_THEME_CHANGED:
  12. pass # Theme used to draw the control changed;
  13. # update and redraw is recommended if using a theme.
  14. NOTIFICATION_VISIBILITY_CHANGED:
  15. pass # Control became visible/invisible;
  16. # check new status with is_visible().
  17. NOTIFICATION_RESIZED:
  18. pass # Control changed size; check new size
  19. # with get_size().
  20. NOTIFICATION_MODAL_CLOSE:
  21. pass # For modal pop-ups, notification
  22. # that the pop-up was closed.
  1. public override void _Notification(int what)
  2. {
  3. switch (what)
  4. {
  5. case NotificationMouseEnter:
  6. // Mouse entered the area of this control.
  7. break;
  8. case NotificationMouseExit:
  9. // Mouse exited the area of this control.
  10. break;
  11. case NotificationFocusEnter:
  12. // Control gained focus.
  13. break;
  14. case NotificationFocusExit:
  15. // Control lost focus.
  16. break;
  17. case NotificationThemeChanged:
  18. // Theme used to draw the control changed;
  19. // update and redraw is recommended if using a theme.
  20. break;
  21. case NotificationVisibilityChanged:
  22. // Control became visible/invisible;
  23. // check new status with is_visible().
  24. break;
  25. case NotificationResized:
  26. // Control changed size; check new size with get_size().
  27. break;
  28. case NotificationModalClose:
  29. // For modal pop-ups, notification that the pop-up was closed.
  30. break;
  31. }
  32. }