Oh man, looking at all of the lines required for creating Derma elements reminded me why I created xlib for XGUI

Building off what Mr. President said, I'm going to let you know what I did for XGUI. Note that my information may be slightly outdated as I'm going off of what I remember from working on XGUI a couple years back.
Anyways, the design philosophy I chose to stick with for XGUI was to:
1) Create all GUI elements, functions, hooks, etc. once if possible. (can be done when the script is loaded or when it's first opened)
2) Rely on hooks, initialization functions, or serverside calls to populate the data in the menu when ready.
3) Use show/hide functions to handle the visibility of the GUI.
#1 is obvious- Creating the VGUI elements takes up a bit more processing time than you'd think. Back in the day, I believe the spawnmenu used to recreate VGUI controls each time it was opened, which caused a nice tiny freeze each time you opened it. I'm pretty sure it doesn't do that anymore, though. #3 will handle the opening and closing of the VGUI without the need to do anything extra.
So, in a nutshell, the skeleton of your GUI should look something like this:
local tdm_menu = {} --Set a table that will store all of your GUI elements in it, so they can be referenced in this whole file. It can be local or not.
local tdm_menu.GAMEMODE_VERSION = "1.0b"
function tdm_menu.initialize()
-- This is where all of your VGUI creation, static functions, etc. go
-- It should only be called ONCE
tdm_menu.MainMenuFrame = vgui.Create( "DFrame" )
tdm_menu.MainMenuFrame:SetSize( 600, 250 )
tdm_menu.MainMenuFrame:SetTitle("Team Deathmatch Menu: Version "..GAMEMODE_VERSION )
tdm_menu.MainMenuFrame:Center()
tdm_menu.MainMenuFrame:ShowCloseButton(false)
tdm_menu.MainMenuFrame:SetVisible( true )
tdm_menu.MainMenuFrame:SetDraggable( false )
tdm_menu.MainMenuFrame:MakePopup()
function tdm_menu.MainMenuFrame:Paint( w, h )
draw.RoundedBox( 0, 0, 0, w, h, Color(team.GetColor(LocalPlayer():Team()).r,team.GetColor(LocalPlayer():Team()).g,team.GetColor(LocalPlayer():Team()).b,50))
surface.SetDrawColor(0,0,0)
surface.DrawOutlinedRect(1,1,w-1,h-1)
end
-- (Rest of GUI creation code here)
-- Be sure to call any populate functions here, for first-time population. (created and explained below)
tdm_menu.populatePlayers()
-- Since hooks only need to be created once, here's a good place to put them.
-- I forgot how to hooks, but I think this is right
hook.Add( "PlayerConnect", "tdm_menu_PlayerConnect", tdm_menu.populatePlayers )
hook.Add( "PlayerDisconnect", "tdm_menu_PlayerDisconnect", tdm_menu.populatePlayers )
-- Not sure what you had planned with this line, but you can hook it up to a data refresh or toggling the GUI.
usermessage.Hook( "MyMenu", tdm_menu.toggleMenu )
end
function tdm_menu.populatePlayers()
-- This is where all of the code to handle any lists of players will go.
-- As Mr. President said, since this is tecnically a refresh function, you'll want to clear out any existing lines before adding new ones.
tdm_menu.PlayerTeamList:Clear()
tdm_menu.GetGiveMoneyPlayers:Clear()
for k,v in pairs(player.GetAll()) do
tdm_menu.PlayerTeamList:AddLine(v:Nick(),team.GetName(v:Team()),v:Frags(),v:Deaths())
end
for k,v in pairs(player.GetAll()) do
tdm_menu.GetGiveMoneyPlayers:AddLine(v:Nick(),v:GetPData('MyXPPoints'))
end
end
function tdm_menu.toggleMenu()
-- Check if the menu has been created
if base.MainMenuFrame == nil then
tdm_menu.initialize()
else
-- Show or hide the frame based on if it's visible or not.
if tdm_menu.MainMenuFrame:IsVisible() then
tdm_menu.MainMenuFrame:hide()
else
tdm_menu.MainMenuFrame:show()
end
end
end
-- Console command to toggle (or initialize) the menu
concommand.Add( "tdm_menu", tdm_menu.toggleMenu )
-- Uncomment this line if you want the GUI to initialize when the script is loaded instead of first open.
-- tdm_menu.initialize()
Things to note:
That's entirely untested, I'm sure there are minor syntax errors that should be easy to fix.
In order to properly access all of your GUI elements throughout the file, it is proper to store everything in it's own table.
You can make the tdm_menu global if you want to access it in-game via console, which is useful for debugging.
You'll obviously want to make more functions like poulatePlayers() to update non-player or other data that gets updated from different hooks/triggers.
DermaMenus are always created at the time of clicking on them, so you can keep most of that code in initialize()
... seeing as XGUI is made up all of client ...
Just an FYI, XGUI does have both serverside and clientside code. Here's the general layout for XGUI code:
The base XGUI code can be found in lua/ulx/modules/cl, with xgui_client.lua, xgui_helpers.lua, and xlib.lua.
The base XGUI serverside code is found at lua/ulx/modules/xgui_server.lua.
Individual client-side modules for XGUI are found in lua/ulx/xgui/, except the 'server' folder.
The serverside code for the clientside modules is found in lua/ulx/xgui/server/.
Hope that helps!