How do I stop clicking other CanvasGroups under current CanvasGroup

I have a problem where if I’m trying to only click on the current CanvasGroup using InputBegan, it registers input on other CanvasGroups under the current one. Sorry if that didn’t make sense. Here is a video of what is happening.


I don’t want other CanvasGroups getting input. Here is the script:

local systemContainer = game.Players.LocalPlayer.PlayerGui:WaitForChild("SystemContainer")
local systemWindows = systemContainer.SystemWindows

local function bringToFront(canvasGroup)
	local highestZIndex = 0
	
	for _, window in ipairs(systemWindows:GetChildren()) do
		local zIndex = window.ZIndex
		if zIndex > highestZIndex then
			highestZIndex = zIndex
		end
	end

	if canvasGroup.ZIndex == highestZIndex then
		return
	end

	for _, window in ipairs(systemWindows:GetChildren()) do
		if window ~= canvasGroup then
			window.ZIndex -= 1
		end
	end
	
	canvasGroup.ZIndex = highestZIndex
end


for _, window in ipairs(systemWindows:GetChildren()) do
	window.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			bringToFront(window)
		end
	end)
end


systemWindows.ChildAdded:Connect(function(newWindow)
	newWindow.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			bringToFront(newWindow)
		end
	end)

	local highestZIndex = 0
	for _, window in ipairs(systemWindows:GetChildren()) do
		local zIndex = window.ZIndex
		if zIndex > highestZIndex then
			highestZIndex = zIndex
		end
	end
	newWindow.ZIndex = highestZIndex + 1
end)

If you need clarification, I will be happy to do so.

Thank you all,
Theo

1 Like

When a window is clicked, instead of directly using the BringToFront function, check if the clicked window has the highest Z index, and then use the function.

Why does this not work?

for _, window in ipairs(systemWindows:GetChildren()) do
	window.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			if window.ZIndex == #systemWindows:GetChildren() then
				bringToFront(window)
			end
		end
	end)
end

This just stops the entire script from working.

Just make a function that iterates over all of the existing windows and return the highest Z index one, then check if the clicked one is the same as the returned one. Would be something like:

local windowsLocation = exampleLocation

function GetHighestZIndexWindow(Location)

local Children = Location:GetChildren()
local HighestIndex = 0
local HighestZWindow = nil

for i,v in pairs(Children) do
if v.ZIndex > HighestIndex then
HighestIndex = v.ZIndex
HighestZWindow = v
end
end

return HighestZWindow
end


(i wrote this on mobile, not sure if i missed something :smiley: )

There’s literally an API function for that

2 Likes

oh, i didnt know that. i dont work with ui alot xd

Ok, so I did that, and the entire script just breaks.

May I see it? Also what do you mean by it breaking, show me the error output.

Code:

local systemContainer = game.Players.LocalPlayer.PlayerGui:WaitForChild("SystemContainer")
local windowsLocation = game.Players.LocalPlayer.PlayerGui:WaitForChild("SystemContainer").SystemWindows
local systemWindows = systemContainer.SystemWindows

--Function to keep the windows in the right order
function GetHighestZIndexWindow(Location)

	local Children = Location:GetChildren()
	local HighestIndex = 0
	local HighestZWindow = nil

	for i,v in pairs(Children) do
		if v.ZIndex > HighestIndex then
			HighestIndex = v.ZIndex
			HighestZWindow = v
		end
	end

	return HighestZWindow
end

-- Function to bring a CanvasGroup to the front
local function bringToFront(canvasGroup)
	local highestZIndex = 0

	-- Find the highest ZIndex among all CanvasGroups
	for _, window in ipairs(systemWindows:GetChildren()) do
		local zIndex = window.ZIndex
		if zIndex > highestZIndex then
			highestZIndex = zIndex
		end
	end

	-- If the CanvasGroup already has the highest ZIndex, do nothing
	if canvasGroup.ZIndex == highestZIndex then
		return
	end

	-- Update ZIndex for all CanvasGroups
	for _, window in ipairs(systemWindows:GetChildren()) do
		if window ~= canvasGroup then
			window.ZIndex -= 1
		end
	end

	-- Bring the clicked CanvasGroup to the front
	canvasGroup.ZIndex = highestZIndex
end

-- Connect input began events for existing CanvasGroups
for _, window in ipairs(systemWindows:GetChildren()) do
	window.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			local Result = GetHighestZIndexWindow(windowsLocation)
			print(window.ZIndex)
			if Result == window then
				bringToFront(window)
				print("hi")
			end
		end
	end)
end

-- Connect a function to handle new CanvasGroups being added
systemWindows.ChildAdded:Connect(function(newWindow)
	newWindow.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			bringToFront(newWindow)
		end
	end)

	-- When a new window is added, set its ZIndex to be on top
	local highestZIndex = 0
	for _, window in ipairs(systemWindows:GetChildren()) do
		local zIndex = window.ZIndex
		if zIndex > highestZIndex then
			highestZIndex = zIndex
		end
	end
	newWindow.ZIndex = highestZIndex + 1
end)

The output prints “hi”, but the bringToFront() function does not work.

Try to not use the bringToFront function if the window is already the highest Z index one:

for _, window in ipairs(systemWindows:GetChildren()) do
	window.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			local Result = GetHighestZIndexWindow(windowsLocation)
			if Result == window then
                print("didnt bring to front because its already the highest one")
            else
				bringToFront(window)
			end
		end
	end)
end

That didn’t work. I think the problem is that when i click the top window, it registers clicks on all the others that are under it.

Hey, just following up to see if you have a solution?

Oh hi, I didn’t get the previous reply’s notification. Unfortunately I don’t think I have a solution for you, I barely work with UI. Good luck solving this.

Ah ok, it seems nobody has a solution, but if someone happens to stumble upon this topic I would appreciate some answers.

Bumping this topic. If anyone has a solution, I would much appreciate it. I had an idea to fix this, but I don’t know if it would work. My idea is to check what window is on top, and then if another window was clicked behind it, cancel that click so only the top window registers it, because for some reason UserInputService registers clicks through frames.

TLDR: My problem is UserInputService registers clicks through two frames.