PlayerButtonDown spams menu open and closes

Not sure if I have to use IsFirstTimePredicted and where should I put

function GM:PlayerButtonDown( ply, btn )
	if not IsFirstTimePredicted() then return end
	if ( btn == KEY_I ) then
		if not self:IsInGame() then return end
		if LocalPlayer():HasWeapon("weapon_handcuffed") or LocalPlayer():HasWeapon("weapon_ziptied") then return end
		
		if not ValidPanel(self.m_pnlQMenu) then
			self.m_pnlQMenu = vgui.Create("SRPQMenu")
			self.m_pnlQMenu:SetSize(math.max(ScrW() * 0.66, 800), math.max(ScrH() * 0.8, 600))
			--self.m_pnlQMenu:SetSize( 800, 600 )
			self.m_pnlQMenu:Center()
			self.m_pnlQMenu:MakePopup()	
		end
				
		self.m_pnlQMenu:Refresh()
		self.m_pnlQMenu:SetVisible(true)
		self.m_pnlQMenu:MakePopup()
		RestoreCursorPosition()
    end
end

function GM:PlayerButtonUp( ply, btn )
  	if ( btn == KEY_I ) then
		if ValidPanel(self.m_pnlQMenu) then
            self.m_pnlQMenu:SetVisible(false)
            CloseDermaMenus()
            RememberCursorPosition()
      	end
  	end
end

You can see how to use it by taking a look at the example on the wiki page: IsFirstTimePredicted - Garry's Mod Wiki

I have but I still cant figure it out

Even with its call position?

what do youn mean

The example on the wiki shows you where to call this function and especially in which context, but if you are still a bit confused, I advise you to check this page which will explain the prediction.

Ive tried using IsFirstTimePredicted but the problem still remains and it spam hides the menu. Might I have to use PANEL:OnKeyCodePressed and if so how do I use it without messing up the other code

function GM:PlayerButtonDown( ply, btn )
	if ( btn == KEY_I ) then
		if not self:IsInGame() then return end
		if LocalPlayer():HasWeapon("weapon_handcuffed") or LocalPlayer():HasWeapon("weapon_ziptied") then return end

		if not IsValid(self.m_pnlQMenu) then
			self.m_pnlQMenu = vgui.Create("SRPQMenu")
			self.m_pnlQMenu:SetSize(math.max(ScrW() * 0.66, 800), math.max(ScrH() * 0.8, 600))
			--self.m_pnlQMenu:SetSize( 800, 600 )
			self.m_pnlQMenu:Center()
			ply:ChatPrint( "Show" )
		end

		self.m_pnlQMenu:Refresh()
		self.m_pnlQMenu:SetVisible(true)
		self.m_pnlQMenu:MakePopup()
		RestoreCursorPosition()
    end
end

function GM:PlayerButtonUp( ply, btn )
  	if ( btn == KEY_I ) then
		if IsValid(self.m_pnlQMenu) then
			self.m_pnlQMenu:SetVisible(false)
			CloseDermaMenus()
			RememberCursorPosition()
			ply:ChatPrint( "Hide" )
		end
	end
end

Have you tried printing the result of the IsFirstTimePredicted function to see how many times it was called and if it returns true or false as it should?

I ended up doing this and it works how I want it to, but I think I might run into a problem in the future with this, but we’ll cross that bridge when we get there

function GM.Gui:Tick()
	if input.IsKeyDown( KEY_I ) then
		if LocalPlayer():HasWeapon("weapon_handcuffed") or LocalPlayer():HasWeapon("weapon_ziptied") then return end
		if vgui.CursorVisible() then return end
		
		if IsFirstTimePredicted then
			if not IsValid(self.m_pnlQMenu) then
				self.m_pnlQMenu = vgui.Create("SRPQMenu")
				self.m_pnlQMenu:SetSize(math.max(ScrW() * 0.66, 800), math.max(ScrH() * 0.8, 600))
				--self.m_pnlQMenu:SetSize( 800, 600 )
				self.m_pnlQMenu:Center()
			end

			self.m_pnlQMenu:Refresh()
			self.m_pnlQMenu:SetVisible(true)
			self.m_pnlQMenu:MakePopup()
		end
    else
		if IsValid(self.m_pnlQMenu) then
			self.m_pnlQMenu:SetVisible(false)
			CloseDermaMenus()
			RememberCursorPosition()
		end
	end
end