Best way to handle a LOT of buttons

What’s the best way of handling too many buttons? Many people have told me to use a for loop and iterate through them but I want to know what will be the most efficient and best way to handle too many buttons i.e in Screen Gui, my game partner has made like a lot of buttons and I want to know how would I handle all of them efficiently in a local script.

image

In these frames, are a TON of buttons. ( for info )

3 Likes

Can you give me a picture of all these buttons you’re making. You’re post is a bit confusing, not gonna lie.

Explain it more clearly, and I may be able to help you.

1 Like

This all depends on what you plan to do with these. What will your script need to accomplish with that motherload of ImageLabels?

2 Likes

Sorry for the late reply, I want my script to accomplish the MouseButton1Clicks, frame visibilty, and etc.

2 Likes

First of all, if you want to use the .MouseButton1Clicked() event, you are going to need to change those to ImageButtons, not ImageLabels.

If you wanted them all to do the same things, you could do something like this, which connects the .MouseButton1Click() event of all the Buttons to the same function.

--this is just an example to demonstrate how you could deal with this many ImageButton's like this.
for key, item in pairs(Frame:GetChildren()) do
    if item:IsA("ImageButton") then
        item.MouseButton1Click:Connect(function()
            --do whatever you want with the Frame(item). In my example, I'll flip-flop the transparency.
            if item.ImageTransparency == 0 then -- you could create more if statements to make the different ImageButton's do different things when clicked.
                item.ImageTransparency = 1
            else
                item.ImageTransparency = 0
            end

        end)
    end
end

Hope this helps!

3 Likes

As a suggestion, to make this compatible with other devices other than PC, you can use Activated or InputBegan on the buttons. MouseButton1Click, which is pretty obvious, only fires when you have a mouse.

4 Likes

Yes, that is very wise. I almost never use .MouseButton1Click for that very reason. Even if you don’t plan to make a game mobile compatible, you can never be too prepared. .Activated is normally the way to go.

1 Like

I have a similar post with a solution

You can check the buttons name and summon an action accordingly

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Player = Players.LocalPlayer

local MainFrame = script.Parent:WaitForChild("Frame")
local ItemsFrame = MainFrame:WaitForChild("ItemsFrame"):WaitForChild("ScrollingFrame")

local RemoteFunctions = ReplicatedStorage.RemoteFunctions
local RemoteEvents = ReplicatedStorage.RemoteFunctions

local Backpack = ItemsFrame.Backpack
local Crowbar = ItemsFrame.Crowbar
local KeyDetector = ItemsFrame.KeyDetector
local MedKit = ItemsFrame.MedKit
local Torch = ItemsFrame.Torch

local BackpackViewFrame = MainFrame.BackpackViewFrame
local KeyDetectorViewFrame = MainFrame.KeyDetectorViewFrame
local CrowbarViewFrame = MainFrame.CrowbarViewFrame
local MedKitViewFrame = MainFrame.MedKitViewFrame
local TorchViewFrame = MainFrame.TorchViewFrame

Backpack.BuyFrame.Button.MouseButton1Click:Connect(function()
	Backpack.BuyFrame.Button.ClickSound:Play()
	ItemsFrame.Visible = false
	CrowbarViewFrame.Visible = false
	MedKitViewFrame.Visible = false
	KeyDetectorViewFrame.Visible = false
	BackpackViewFrame.Visible = true
end)

Torch.BuyFrame.Button.MouseButton1Click:Connect(function()
	Torch.BuyFrame.Button.ClickSound:Play()
	ItemsFrame.Visible = false
	MedKitViewFrame.Visible = false
	KeyDetectorViewFrame.Visible = false
	BackpackViewFrame.Visible = false
	CrowbarViewFrame.Visible = false
	TorchViewFrame.Visible = true
end)

Crowbar.BuyFrame.Button.MouseButton1Click:Connect(function()
	Crowbar.BuyFrame.Button.ClickSound:Play()
	ItemsFrame.Visible = false
	MedKitViewFrame.Visible = false
	KeyDetectorViewFrame.Visible = false
	BackpackViewFrame.Visible = false
	CrowbarViewFrame.Visible = true
end)

KeyDetector.BuyFrame.Button.MouseButton1Click:Connect(function()
	KeyDetector.BuyFrame.Button.ClickSound:Play()
	ItemsFrame.Visible = false
	MedKitViewFrame.Visible = false
	BackpackViewFrame.Visible = false
	CrowbarViewFrame.Visible = false
	KeyDetectorViewFrame.Visible = true
end)

MedKit.BuyFrame.Button.MouseButton1Click:Connect(function()
	MedKit.BuyFrame.Button.ClickSound:Play()
	ItemsFrame.Visible = false
	BackpackViewFrame.Visible = false
	CrowbarViewFrame.Visible = false
	KeyDetectorViewFrame.Visible = false
	MedKitViewFrame.Visible = true
end)

BackpackViewFrame.Backpack.BuyFrame.Button.MouseButton1Click:Connect(function()
	BackpackViewFrame.Backpack.BuyFrame.Button.ClickSound:Play()
	RemoteFunctions.Backpack:InvokeServer(BackpackViewFrame.Backpack.BuyFrame.Cost.Value, BackpackViewFrame.Backpack.BuyFrame.Level.Value)
end)

KeyDetectorViewFrame.KeyDetector.BuyFrame.Button.MouseButton1Click:Connect(function()
	KeyDetectorViewFrame.KeyDetector.BuyFrame.Button.ClickSound:Play()
	RemoteFunctions.KeyDetector:InvokeServer(KeyDetectorViewFrame.KeyDetector.BuyFrame.Cost.Value, KeyDetectorViewFrame.Backpack.BuyFrame.Level.Value)
end)

return true or 1

This is module, so I’m a little confused on how to handle it all since they do all the same thing…

DRY principle:

You can make your life and your code easier by thinking of the Don’t Repeat Yourself (DRY) principle. It aims to avoid typing the same thing over and over again when it’s more useful to use some kind of abstraction. Instead of specifying exactly how each item has to be set up, we abstract all of that into a mental model of an “item”. An “item” is a GuiObject that has a BuyFrame, a ClickSound, an associated ViewFrame and some other things. When an “item” is clicked, it’s ViewFrame is showed and all others are hidden.

That code is repeated a lot, so that’s an obvious first place to DRY up your code. E.g.:

function hideAllFrames()
	ItemsFrame.Visible = false
	CrowbarViewFrame.Visible = false
	MedKitViewFrame.Visible = false
	KeyDetectorViewFrame.Visible = false
	BackpackViewFrame.Visible = false
end

function showFrame( frame )
	hideAllFrames()
	frame.Visible = true
end

Now you can simplify each MouseButton1Click listener function a lot:

Backpack.BuyFrame.Button.MouseButton1Click:Connect(function()
	Backpack.BuyFrame.Button.ClickSound:Play()
	showFrame(BackpackViewFrame)
end)

Torch.BuyFrame.Button.MouseButton1Click:Connect(function()
	Torch.BuyFrame.Button.ClickSound:Play()
	showFrame(TorchViewFrame)
end)

Now, most of the repetition is in setting up the listener functions. To DRY it up even more, we can loop over all the items and set them up in the same manner:

local items = ItemsFrame:GetChildren() --This might need to filter out other GuiObjects

for _, item in pairs(items) do
    --You might want an assert here to see if the Button exists.
	item.BuyFrame.Button.MouseButton1Click:Connect(function()
		item.BuyFrame.Button.ClickSound:Play()

		local itemViewFrame = MainFrame:FindFirstChild(item.Name .. "ViewFrame")
		showFrame( itemViewFrame )
	end)
end

Not only do you avoid having to type out a bunch of code for each item, if you want to add another item later it’s as simple as setting up the GUI (button, view frames) and it should magically work on it own.


We can actually “simplify” and generalize the hideAllFrames function in the same way:

function hideAllFrames()
	for _, item in pairs(items) do
		local itemViewFrame = MainFrame:FindFirstChild(item.Name .. "ViewFrame")
		itemViewFrame.Visible = false
	end
end

You can also DRY up the last two connections in the same manner.

Here's how I would DRY up your entire script
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Player = Players.LocalPlayer

local MainFrame = script.Parent:WaitForChild("Frame")
local ItemsFrame = MainFrame:WaitForChild("ItemsFrame"):WaitForChild("ScrollingFrame")

local RemoteFunctions = ReplicatedStorage.RemoteFunctions
local RemoteEvents = ReplicatedStorage.RemoteFunctions

function hideAllFrames()
	for _, item in pairs(items) do
		local itemViewFrame = MainFrame:FindFirstChild(item.Name .. "ViewFrame")
		itemViewFrame.Visible = false
	end
end

function showFrame( frame )
	hideAllFrames()
	frame.Visible = true
end

function setupItem( item )
	--Setup item buttons (click sounds, hiding and showing frames)
	item.BuyFrame.Button.MouseButton1Click:Connect(function()
		item.BuyFrame.Button.ClickSound:Play()

		local itemViewFrame = MainFrame:FindFirstChild(item.Name .. "ViewFrame")
		if itemViewFrame then
			showFrame( itemViewFrame )
			ItemsFrame.Visible = false
		end
	end)
end

function setupViewFrame( viewFrame )
	--Setup some other stuff, assuming all the viewFrames work the same way
	local n = viewFrame.Name
	local itemName = string.sub(n, 1, string.find(n, "ViewFrame") - 1)
	local buyFrame = viewFrame[itemName].BuyFrame

	buyFrame.Button.MouseButton1Click:Connect(function()
		buyFrame.Button.ClickSound:Play()
		RemoteFunctions[itemName]:InvokeServer(buyFrame.Cost.Value, buyFrame.Level.Value)
	end)
end

function setup()
	items = ItemsFrame:GetChildren() --This might need to filter out other GuiObjects
	viewFrames = MainFrame:GetChildren() --Same here

	for _, item in pairs(items) do
		setupItem(item)
	end
	
	for _, viewFrame in pairs(viewFrames) do
		setupViewFrame(viewFrame)
	end
end

--Remember to call the function :)
setup()

return true
11 Likes