TabコンテナのStyleが思ったように変更できない、TabコンテナのようなUIを作りたい

お世話になります、からなと申します。
よろしくお願いいたします。

始めたばかりでいろいろと情報が不足していたり
記載方法が間違っていたりする可能性がありますが
何かありましたら教えてください。申し訳ありません。

Godotバージョン

4.2.1

OSとそのバージョン

Windows10

使用言語

GDScript?

内容

キャラメイク用のUIを作成しようとしています。
TabContainerを利用して動的に生成しようとしたのですが
デザインが上手くいかずに困っています。

###現在どのような状況か
TabContainerにスクリプトをアタッチしています。
・ScrollContainerを作成
(とりあえず横幅600で固定)
・スクロールの設定を変更
(縦のみ表示し、custom_minimum_size.xを20にしている)
・GridContainerを作成
(columnは5設定、横幅は600設定にし、size_flagsは縦横両方ともSIZE_SHRINK_CENTERに設定)
・フォルダから画像を取得してボタンを生成
ボタンサイズは110×110にしている
(サイズ指定しないとキレイに入らなかった)
・配置されたボタンを押すと、何タブの何をクリックしたかが分かる

→有料のChatGPTと長時間話し合いながら作成しました

困っていること

現状.PNGの状態まで作成できました。

・Tabの部分が横スクロールできない
パソコンとスマホの両方で利用したいため、
もう少し大きく、選択しやすいようにしたいです。

・Tabの右端にある、左右<>のデザインやサイズが変更できない
自作画像を入れてみたりもしましたが、異常に幅を取るだけでした

考えていること

・キャプチャ.pngのように、灰色部分と水色部分で
別パーツにして連動はできるでしょうか?
→実際に動作させているときは、どこの何を選んだか
グローバル関数?に記録する必要があります

・私のやりたいことについて、おすすめの方法は
ありますか?

・Styleの変更コツなどはありませんか?
色々サイトを見たりYoutubeを見たりしているのですが、思ったように変更ができません

・パーツ化してほかの場所でも利用したいのですが
参考になるサイト等はありますでしょうか?

スクリーンショット

なぜか「エラーが発生しました: 投稿にメディア項目を埋め込むことはできません。」と出てスクリーンショットが追加できませんでした。
追記で出来そうなら試してみます。申し訳ありません。

上記にスクショ画像をアップしました。

「いいね!」 1

初めまして。

おそらくこういう挙動かなぁと思って試作してみました。

やり方としては

  1. TabContainerの下にコードで動的にコンテナを追加
  2. 同数のButtonをScrollContainerの下にあるHBoxContainerに追加
  3. ButtonのPressedシグナルにtabのidを引数として持たせてタブ切り替え関数にconnect

という感じでやってます

シーン構成は

  • Control
    • TabContainer # ここにコンテナを追加
    • ScrollContainer
      • HBoxContainer # ここにボタンを追加

です

extends Control

const TAB_1 : PackedScene = preload("res://tab_1.tscn") # VBoxContainerのシーン
@onready var tab_container: TabContainer = $TabContainer
@onready var h_box_container: HBoxContainer = $ScrollContainer/HBoxContainer

func _ready() -> void:
	tab_create(40)

func tab_create(num : int):
	for i in num:
		var tab_scene : Control = TAB_1.instantiate() # シーンを初期化
		var button : Button = Button.new() # buttonを生成
		button.text = "たぶ" + str(i+1)
		tab_scene.tab_text = "たぶ" + str(i+1)
		h_box_container.add_child(button)
		button.pressed.connect(tab_change.bind(i)) # tab_change関数にidを引数として持たせてconnect
		tab_container.add_child(tab_scene)

func tab_change(id : int):
	tab_container.current_tab = id # idでえらんでいるタブを切り替える

意図と違った挙動になってたら申し訳ないです。

追記

多分違うとは思うんですが、選んでいるコンテナーと対応したボタンのスタイルを変える方法ですが、これで行けると思います。
ボタンのトグルモードをONにするやり方です。

extends Control

const TAB_1 : PackedScene = preload("res://tab_1.tscn") # VBoxContainerのシーン
@onready var tab_container: TabContainer = $TabContainer
@onready var h_box_container: HBoxContainer = $ScrollContainer/HBoxContainer

var button_list : Array = []

func _ready() -> void:
	tab_create(40)

func tab_create(num : int):
	for i in num:
		var tab_scene : Control = TAB_1.instantiate() # シーンを初期化
		var button : Button = Button.new() # buttonを生成
		button.text = "たぶ" + str(i+1)
		tab_scene.tab_text = "たぶ" + str(i+1)
		h_box_container.add_child(button)
		button.toggle_mode = true # ボタンのトグルモードをONにする。
		button.pressed.connect(tab_change.bind(i)) # tab_change関数にidを引数として持たせてconnect
		tab_container.add_child(tab_scene)
		button_list.append(button)
	button_list[0].button_pressed = true # 追記部分。最初は0個目をONにしておく。

func tab_change(id : int):
	button_list[tab_container.current_tab].button_pressed = false # 前回のボタンをOFFにする
	tab_container.current_tab = id # idでえらんでいるタブを切り替える

これでボタンのテーマかテクスチャボタンのテクスチャのpressedが使えるので連動しているように見える……んじゃないかなぁ~~と思います。

パーツ化して流用するにはシーンをブランチとして保存でシーンとして保存できます。
それを他のところで読み込んでinstantiateして任意の場所にadd_childすれば流用できます。

Styleの変更のコツについては詳しくないので他の方にお任せします。

以上です。

「いいね!」 1

フォーラムでの画像投稿の件
すいません。Trust Level 1からの設定になってました。
現時点ではTrust Level の制限を緩和します(そのうち変えます)

ご報告いただきありがとうございました
(本題とズレるのでレスは不要です)

「いいね!」 1

回答ありがとうございます。
返信が遅くなり大変申し訳ありません。

おぉ…私がやりたい操作そのものなのです!
ですが、どのようにアタッチ?するのかが分かりません。

ここ1週間色々と試行錯誤したのですが
Tab表示が出ずに
tab_scene.tab_text = “たぶ” + str(i+1)
でstringが…というようなエラーが出て止まったりします。

初歩的な質問で大変申し訳ありませんが
適用方法を教えていただけますでしょうか。

ファイルについて

UIフォルダににtab_1.tscnを作成
ScenesフォルダにMenuScence.tscnを作成

【scenes】フォルダ
◆MenuScence.tscn ←ここに頂いたソースを適用する?
TabContainer
ScrollContainer
HBoxContainer

【UI】フォルダ
◆tab_1.tscn
TabCOntainer
ScrollContainer
HBoxContainer

私が記載したサンプルのソース

◆MenuScence.tscn
TabContainer
ScrollContainer
HBoxContainer

添付した画像のものは、MenuScenceの
TabContainerに以下スクリプトを適用しています(ChatGPTと協力して作ったもの)

extends TabContainer

# スクロールコンテナの名前リスト
var scroll_container_names = [
	"Body", "Eye", "Front_Hair", "Back_Hair"
]

# アイコンが格納されているベースフォルダ
var icon_base_path = "res://icon_test/"

func _ready():

	for scroll_container_name in scroll_container_names:
		# ScrollContainerを作成
		var scroll_container = ScrollContainer.new()
		scroll_container.name = scroll_container_name
		scroll_container.custom_minimum_size = Vector2(600, 0)  # ScrollContainerの横幅を600pxに固定

		# スクロール設定
		scroll_container.get_h_scroll_bar().visible = false
		scroll_container.get_v_scroll_bar().visible = true
		scroll_container.get_v_scroll_bar().custom_minimum_size.x = 20

		# GridContainerを作成
		var grid_container = GridContainer.new()
		grid_container.columns = 5
		grid_container.custom_minimum_size = Vector2(600, 0)  # 横幅を600pxに固定
		grid_container.size_flags_horizontal = Control.SIZE_SHRINK_CENTER  # 中央揃えに変更
		grid_container.size_flags_vertical = Control.SIZE_SHRINK_CENTER  # 中央揃えに変更
		
		# フォルダから画像を取得し、ボタンを生成
		var dir_path = icon_base_path + scroll_container_name
		var dir = DirAccess.open(dir_path)
		
		var files = []
		var null_file_path = ""
		
		if dir:
			dir.list_dir_begin()
			var file_name = dir.get_next()
			while file_name != "":
				if file_name.ends_with(".png"):  # PNGファイルのみ処理
					if file_name == "null.png":
						# null.pngの場合は特別に保存
						null_file_path = dir_path + "/" + file_name
					else:
						files.append(file_name)
				file_name = dir.get_next()
			dir.list_dir_end()
		
		# null.pngを最優先で処理
		if null_file_path != "":
			_create_button(scroll_container_name, null_file_path, grid_container)
		
		# 残りのファイルを処理
		for file_name in files:
			var file_path = dir_path + "/" + file_name
			_create_button(scroll_container_name, file_path, grid_container)
		
		# ScrollContainerにGridContainerを追加
		scroll_container.add_child(grid_container)
		
		# TabContainerにScrollContainerを追加
		add_child(scroll_container)
		
		# タブのタイトルを設定
		#set_tab_title(get_child_count() - 1, scroll_container_name)
		#var tabiconpath=tab_icon_path + scroll_container_name + "Icon.png"
		#set_tab_title(get_child_count() - 1, "")  # 3番目のタブにアイコンを設定
		#set_tab_icon(get_child_count()- 1,load(tabiconpath))
		
# ボタン生成と接続を行う関数
func _create_button(tab_name, file_path, grid_container):
	# 拡張子を除いたファイル名を取得
	var base_name = file_path.get_file().substr(0, file_path.get_file().rfind("."))

	var button = Button.new()
	button.text = ""  # ボタンのテキストを空にする

	# ボタンのサイズを110x110に固定
	button.set_custom_minimum_size(Vector2(110, 110))

	# アイコンを設定
	var icon_texture = load(file_path)
	button.icon = icon_texture
	button.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER

	# ボタンにクリック処理を接続、タブ名と拡張子なしのファイル名を渡す
	button.connect("pressed", Callable(self, "_on_button_pressed").bind(tab_name, base_name))

	grid_container.add_child(button)

# ボタンがクリックされたときに呼ばれる関数
func _on_button_pressed(tab_name, base_name):
	# タブ名と拡張子なしのファイル名を出力
	print("Tab: ", tab_name, ", File: ", base_name)

あ~~~~すみません!
私の説明不足です。

追加しているシーンの説明を忘れていました。

  • VBoxContainer
    • Label

となっていて、Label用のテキストをreadyの時に変えるようにtab_textって変数を作ったのですが、
それに代入するよ~~っていうところで、tab_textなんて変数ねーぜって言われてるんだと思います。私が作る必要があると言っていなかったので……

多分プロジェクトお渡ししたほうが早いと思うので置いておきますね。

tab_container.tscnと.gdがメインシーン、tab_1.tscnとgdが問題のシーンです。

私から教えられたコードでエラー吐く時はどんどん聞いて下さい。大体私の凡ミスですので……

「いいね!」 1

ニチカ様

回答いただいているのに返信が遅く申し訳ありません!!

既存プロジェクトに追加したら
タブのサイズがおかしなことになったり
動作が上手くいかずに色々と動作確認をしていました。

新規プロジェクトを作成してテストしてみたところ、
シーン等をコピペしたのですが、
タブをクリック+フリック?しても
頂いた動画のように横スクロールできなかったです。
(そもそも私がそうしたいと希望書き漏れてました、申し訳ありません)

タブ上でマウスホイールを動かしたら、タブ横スクロールになりました!

我儘を言って大変申し訳ないのですが、
タブをつかんで横移動したら横スクロールといったことは可能でしょうか?

1週間ググって情報が見つかりませんでした。
引き続き調べます。

スマホのスワイプやマウスのドラッグで動かすやつですね。

SmoothScrollというアドオンがありまして、それで実現できそうだったのでちょっとシーン組んでみました

https://godotengine.org/asset-library/asset/1399
↑をダウンロードして有効にしてから↓のシーン触ってみてください

コメントがコードの中に入っているので参考にしてみてください。
わからない箇所有ったらきいてください。説明します。

既知の不具合としては

  • スマホのスワイプだとありえん速度でスクロールしちゃう
  • PCだとボタン外にマウスが行くと動かなくなる

とかがあります。
なんでだ……

色々調整は必要ですが、とりあえずできるよ……ということで大目に見てください。

「いいね!」 1

ニチカ様

たびたび申し訳ありません、
ありがとうございます!!

おぉ~、すごいスワイプ?スクロールできました!
画面買いに行ってスクロールしないのは全然良いと思います!

ただ、タブクリック2回目以降、
タブのボタン色がピンク色に変わらないです。
tab_changeにいかないのかなと思いますが
ブレークポイント置いてF11とかで見ていったのですが
良くわかりませんでした…。

たぶ1クリック→たぶ8クリック→たぶ11クリック
上記の流れでクリックしても、たぶ8で止まっていて
スクロールして他のタブをクリックしても移動できない感じです。

button_up および mouse_entered イベントに関するヘルプ

上記が参考になりそうだと読んでいたのですが
私にはまだ早いのかちょっと理解ができませんでした…。

質問ばかりで申し訳ありません。

私の推測なので詳しい人に解説してほしいんですが、
gui_inputを他のノードに渡したまんまだと良くないっぽいのでボタン離したらコネクトを外すようにしてみました。

あとついでに色々直してみたので触ってみてください。
どうやって直したかは私にもよくわかってないのですが、とりあえずこれでいい感じになったとは思います。

相変わらずスマホでのスクロール速度がおかしいですがちょっとこれ以上はわからないですね……

コードのコメント読んでわからないところあったら教えて下さい。

すみませんバグが有ったので修正しました。
リンクは変わりません。
これでたぶん大丈夫なはずです。