Godot4 テキストを持つControl派生クラスの判別方法(4.3暫定)

無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4.3 で、Button や Label などテキストを表示する Control 派生クラスのノードのテキスト文字列を取得する関数の実装例を紹介します。
4.3 公式の Control 派生クラス全てのテキストプロパティの特徴を利用して簡単に実装でき、その特徴をまねることで外部 Control 派生クラスでも利用可能です。

また、それを利用して、表示テキストがコントロールのサイズを超えない最大のフォントサイズ調節する関数改良版も紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。

前回の記事

前回は、ボタンなどのコントロールのサイズに合わせて、表示するテキストのフォントサイズを自動的に調整するスクリプト例とその実行結果を紹介しました。

今回は、それを改良して、テキストを持っている Control 派生クラスのノードからのみテキストを得る処理を追加します。

コントロールのテキストを取得する関数を使ったスクリプト例

以下は、Control 派生クラスの表示テキストがコントロールのサイズを超えない最大のフォントサイズに自動的に調節する 4 行目の fit_control_font_size 関数と、その関数が呼び出す関数群です。

ハイライトしている 73 行目の get_control_text_from_text_property 関数が、ボタンやラベルなどのコントロールの表示テキストを取得する関数です。
実装はシンプルで、 Object クラスのメンバ関数 get で、 text という名前のプロパティを持っているかを判定するだけです。

最初は、クラスごとに判定しようと調べたのですが、表示するテキストを持つ Control 派生クラスは 4.3 では全て String 型の text プロパティを持っている特徴があったので、未知の型に対応できるメリットと、型判別よりもコストがかからないことを考慮して、以下のようにシンプルな実装にしました。

## [param control] のサイズにフィットするように、 [param text] を描画できる最適なフォントサイズを設定します。
## [param text] が空文字列の場合は何もしません。
## フォントサイズは、 [param control] の Theme Overrides の Font Size で設定します。	
static func fit_control_font_size(control: Control, text: String) -> void:
	# 表示するテキストが空文字列の場合は調整できないので何もしません。
	if text.length() == 0:
		return
	
	# コントロールのサイズを取得します。
	var control_size = control.size
	
	# コントロールの用いるフォントを取得します。
	var font: Font = get_control_font(control)
	
	# 描画サイズを測定するために、テキストを描画するオブジェクトを生成します。
	# RefCounted 派生なので消去は自動的に行われます。
	var text_paragraph: TextParagraph = TextParagraph.new()
	
	# フォントサイズを1ずつ増やしていき、コントロールのサイズからはみ出ない最大のフォントサイズを探します。
	var font_size = 1 # 初期フォントサイズ
	while true:
		# 指定したフォント・フォントサイズ・テキストを設定して、その描画サイズを取得します。
		text_paragraph.clear()
		text_paragraph.add_string(text, font, font_size)
		var text_size: Vector2 = text_paragraph.get_size()
		# テキストの描画サイズがコントロールのサイズ(横または縦)を超えた場合、その直前のフォントサイズで調整します。
		if control_size.x < text_size.x or control_size.y < text_size.y:
			break
		# テキストの描画サイズがコントロールのサイズを超えない場合、さらに 1 増やしたフォントサイズで確認を繰り返します。
		font_size += 1
	
	# コントロールからはみでないフォントサイズを設定します。
	# すでに Theme Overrides で設定されている Font Size は上書きされます。
	control.add_theme_font_size_override("font_size", font_size)
	return

## [param control] が用いるフォントを取得します。
static func get_control_font(control: Control) -> Font:
	# control が使用しているフォントを取得します。
	# theme から取得する関数の引数には、テーマリソースのフォントに関する項目名 "font" (snake_case)を指定します。
	# 参照:https://docs.godotengine.org/ja/4.x/classes/class_control.html#class-control-method-get-theme-color
	var font: Font = null
	if control.has_theme_font_override("font") or control.has_theme_font("font") == true:
		# テーマの font 項目または Control クラス派生のノードが持つ Theme Overrides の font 項目が設定されている場合
		# テーマから font 項目の値(Font)を取得します。
		font = control.get_theme_font("font") 
	else:
		# フォントが設定されていない場合
		# テーマのデフォルトの font 項目の値(Font)を取得します。
		font = control.get_theme_default_font()
	return font

## [param control] の表示テキストの文字列を返します。
## また、[Control] 以下のクラスを継承した、独自の派生クラスも String 型の text プロパティを持たせることで
## 本関数で表示テキストを取得できます。
##
## 現状は [method ScUtil.get_control_text_from_text_property] と同じです。
## しかし text プロパティ以外から表示テキストを得るクラスが追加された場合は、
## 本関数で、クラス判別、クラス名判別を用いて、拡張する予定です。
## そのため、表示テキストを得る場合は、本関数を使用してください。
##
## Godot 4.3 の Control クラスの派生クラスを確認すると、表示テキストは全て String 型の text プロパティでした。
## 該当クラスは Button, TextEdit, LinkButton, Label, LineEdit, RichTextLabel とその派生クラスです。
## https://docs.godotengine.org/ja/4.3/classes/class_control.html#class-control
static func get_control_text(control: Control) -> String:
	return get_control_text_from_text_property(control)

## [Control] 派生のクラスが text プロパティを持っている場合、その text 文字列を返します。
## これは [Control] 派生の表示するテキストがあるクラスが text という名前のプロパティに設定している特徴を利用するものです。
## また、公式ではない独自の [Control] 派生クラスにも対応する方法としても使えます。
##
## [method ScUtil.get_control_text] は、現状同じ処理ですが、 text プロパティ以外にも対応する関数です。
static func get_control_text_from_text_property(control: Control) -> String:
	if control.get("text") != null and control.text is String:
		# String 型の text プロパティを持っている場合
		return control.text
	return ""

RichTextLabel だけプロパティ名が異なります

他は font_size ですが、 RichTextLabel クラスは複数あり、名前も normal_font_size などほかのコントロールとは異なるので、以下のようにクラスを判定してプロパティ名を分けて使いましょう。

# Thmee Overrides のフォントサイズのプロパティ名をクラスから判別します。
var font_size_property_name: String = "font_size"
if control is RichTextLabel:
	font_size_property_name = "normal_font_size"https://compota-soft.work/archives/46367

型判別でテキストの有無を判定するスクリプト(結局使わなかった)

前述のとおり、GodotEngine 4.3 では、表示するテキストを持つ公式の Control 派生クラスは全て String 型の text という名前のプロパティを持っていたので、”text” というプロパティを持っているかを get 関数で判定するだけで対処できることが分かりました。

これは、現状の偶然かもしれない特徴を利用しているだけですが、型判別などを行わないので処理コストが少なく、また外部で作られた Control 派生クラスでも text というプロパティに表示する文字列を設定しておけば対応できるメリットもあります。

以下は、その特徴に気づくまで、公式の Control 派生クラスを全て調べながら作った、クラスごとにテキストを取得するスクリプトです。
テストをしていないので動作は不明ですが、4.3 でどのクラスとその派生がテキストを持っていて、どのクラスは持たないかを説明する代わりになればと思い掲載します。
#使わずに消すのがもったいなかったという理由のほうが大きいかも。

## [param control] の派生クラスの型に応じて、表示するテキストの文字列を返します。
## テキストを持たない Control 派生クラス、または、本関数で対応していないクラスについては空文字列 "" を返します。
## また、公式リファレンスにない独自 Control 派生クラスも text プロパティに表示するテキストを持たせることで、対応します。 
##
## Godot 4.3 の Control クラスの派生クラスを確認しました。String text プロパティがあるかどうかで判断しました。
## https://docs.godotengine.org/ja/4.3/classes/class_control.html#class-control
static func get_control_text(control: Control) -> String:
	var text = null
	
	# Button, TextEdit がテキストを持ち、その派生も text プロパティを持ちます。 
	if control is Button:
		text = control.text
	elif control is TextEdit:
		text = control.text
	elif control is LinkButton:
		text = control.text
	elif control is Label:
		text = control.text
	elif control is LineEdit:
		text = control.text
	elif control is RichTextLabel:
		text = control.text
	
	if text == null:
		# クラス名の文字列で個別に判定して、テキストを text 変数に設定します。
		var name_of_class :String = control.get_class()
		match name_of_class:
			# テキストを持たないクラスの場合。
			# テキストを持たないクラスから派生した独自クラスがテキストを持つ可能性があるので、
			# is による派生を含めたクラス判定は避け、テキストを持っていないことを確認したすべての派生クラスを個別に確認します。
			"Container", "AspectRatioContainer", "BoxContainer", "CenterContainer", "EditorProperty", \
			"FlowContainer", "GraphElement", "GridContainer", "MarginContainer", "PanelContainer", \
			"ScrollContainer", "SplitContainer", "SubViewportContainer", "TabContainer", \
			"TextureButton", "ColorRect", "NinePatchRect", "Panel", "Range", "EditorSpinSlider", \
			"ProgressBar", "ScrollBar", "Slider", "SpinBox", "TextureProgressBar", "ReferenceRect", \
			"Separator", "HSeparator", "VSeparator", "TabBar", "TextureRect", "Tree", "VideoStreamPlayer":
				text = ""
			# Control 派生かつ想定していないクラス(独自の Control 以下の派生クラスを想定)の場合
			_ :
				# 公式リファレンスにない独自の派生クラスなどへの対応です。 text プロパティを持っていればテキストを得ます。
				text = get_control_text_from_text_property(control)
				push_warning("ScUtil.gd get_control_text: 本関数でサポートされていない Control 派生クラスです。公式のクラスの場合、処理の追加を要望します。クラス名 = ", name_of_class)
	return text

テスト

テスト用に、text プロパティを持っているか確認する get 関数の前後print 文を追加して、表示テキストを持つ Control 派生ノード、持たないノードでの出力の違いを確認します。

Godot4.3 表示テキストを持つコントロールを判定してテキスト文字列を取得する例SS1

具体的には先ほどのスクリプトの最後に定義されている get_control_text_from_text_property 関数に以下のように print 文を 3 か所に追加しました。

## [Control] 派生のクラスが text プロパティを持っている場合、その text 文字列を返します。
## これは [Control] 派生の表示するテキストがあるクラスが text という名前のプロパティに設定している特徴を利用するものです。
## また、公式ではない独自の [Control] 派生クラスにも対応する方法としても使えます。
##
## [method ScUtil.get_control_text] は、現状同じ処理ですが、 text プロパティ以外にも対応する関数です。
static func get_control_text_from_text_property(control: Control) -> String:
	print("control = ", control)
	if control.get("text") != null and control.text is String:
		print("テキストプロパティを持っています。", control.text)
		# String 型の text プロパティを持っている場合
		return control.text
	print("テキストプロパティを持っていません。")
	return ""

Label ノードは、表示するテキストを持っていると判定され、テキストを表示できました。
ColorRect ノードは、表示するテキストを持たない Control クラス派生なので、テキストを表示しませんでした。
Node2D ノードは、 Control 派生クラスではないので、処理自体が行われませんでした。

Godot4.3 表示テキストを持つコントロールを判定してテキスト文字列を取得する例SS2
found_nodes = [Label:<Label#1781807513615>, ColorRect:<ColorRect#1782411493421>]
control = Label:<Label#1781807513615>
テキストプロパティを持っています。Label
↓のPanel,ColorRectは
  テキストがない
 コントロールです
control = ColorRect:<ColorRect#1782411493421>
テキストプロパティを持っていません。

以下は、行ったテストの動画です。

まとめ

今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4.3 で、Button や Label などテキストを表示する Control 派生クラスのノードのテキスト文字列を取得する関数の実装例を紹介します。
4.3 公式の Control 派生クラス全てのテキストプロパティの特徴を利用して簡単に実装でき、その特徴をまねることで外部 Control 派生クラスでも利用可能です。

また、それを利用して、表示テキストがコントロールのサイズを超えない最大のフォントサイズ調節する関数改良版も紹介しました。

参照サイト Thank You!

記事一覧 → Compota-Soft-Press

コメント

Ads Blocker Image Powered by Code Help Pro

お願い - Ads Blocker Detected

このサイトは広告を掲載して運営しています。

ポップアップを閉じて閲覧できますが、よろしければ

このサイト内の広告を非表示にする拡張機能をオフにしていただけませんか?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

タイトルとURLをコピーしました