Thread Tools Display Modes
07-15-16, 11:00 PM   #1
Dejablue
A Wyrmkin Dreamwalker
 
Dejablue's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 58
For loop Table to Frames Creation Assistance Request

Hi guys.

Warning; newb alert, ignorance and cringe-worthy code/scripts ahead ~

I am trying to use one of two tables to create frames for each stat. There are 26 stats available via the API so I obviously do not want to create 26 individual frames. Also, sidenote, I am am trying to implement the ability to select the stats one chooses via table insertion and removal via wipe. Any suggestions on other methods would be appreciated.

The task at hand, however, is to take the table and make a frame from each key's name. I am using ipairs to make them iterate sequentially and display in the order they are in the table:

Code:
-- This is the table of stats I want to create individual frames for
PAPERDOLL_Attributes_STAT_Frames = {
    "Health","Power","Armor","Strength","Agility","Intellect","Stamina","Damage",
    "Attack Speed","Spell Power","Mana Regen","Energy Regen","Rune Regen","Focus Regen","Movement Speed",
}

local yAttributes -- Variable to do math to place each subsequently created frame below the previously created frame

for k, v in ipairs(PAPERDOLL_Attributes_STAT_Frames) do
	if yAttributes == nil then
		yAttributes = 0
	else
		yAttributes = yAttributes
	end
	local counter = (yAttributes + 1)
	yAttributes = counter
	local statframeofy = (-100 - (yAttributes*25))
		--print(yAttributes)
	--print(v)
	
local KStatFrame = CreateFrame("CheckButton", "KStatFrame"..v, DejaCharacterStatsPanel, "InterfaceOptionsCheckButtonTemplate")
	KStatFrame:RegisterEvent("PLAYER_LOGIN")
	KStatFrame:ClearAllPoints()
	KStatFrame:SetPoint("TOP", 25, statframeofy)
	KStatFrame:SetScale(1.0)
	_G[KStatFrame:GetName() .. "Text"]:SetText(format("%s", v))		

	local (kstatname= KStatFrame:GetName()
	--print(kstatname)
				
	yAttributes = yAttributes
end
So I am creating frames by concatenating v to the end of KStatFrame:
Code:
"KStatFrame"..v
How do I reference this? Can I reference this to do OnEvent or OnScript? My attempt is to create a variable and call it as such:

Code:
local (kstatname= KStatFrame:GetName()

KStatFrame:SetScript("OnEvent", function(kstatname, event, arg1)
	local upperstr = string.upper(v)
	--print(upperstr)
	if event == "PLAYER_LOGIN" then
		--print(yAttributes)
		local setchecked = private.db.dejacharacterstatsSelectedStats
		--print(setchecked, upperstr)
		--local ktablename = setchecked:GetName()
		--print(ktablename)
		--local kstatnamechecked = kstatname:GetChecked()
		--print(kstatnamechecked)
		kstatname:SetChecked(setchecked.upperstr)
		if kstatname:GetChecked(true) then
			table.insert(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", tostring(upperstr)) })
			private.db.dejacharacterstatsSelectedStats.upperstr = true
		elseif not kstatname:GetChecked(true) then
			private.db.dejacharacterstatsSelectedStats.upperstr = false
		end
	end
end)

KStatFrame:SetScript("OnClick", function((kstatname,event,arg1) 
	if kstatname:GetChecked(true) then
		table.insert(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", tostring(upperstr)) })
		private.db.dejacharacterstatsSelectedStats.upperstr = true
	elseif not kstatname:GetChecked(true) then
		DCS_SelectStats()
		table.wipe(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", tostring(upperstr)) })
		private.db.dejacharacterstatsSelectedStats.upperstr = false
	end
	PaperDollFrame_UpdateStats();
end)
So, that is where I am at. The frames do create, but now I need to tie them to my saved variables so selected stats save across sessions and work with events.

This means, presumably, that I should probably prefer to use the table below, private.defaults.dejacharacterstatsSelectedStats, instead of the one above, PAPERDOLL_Attributes_STAT_Frames, because it is the database default for the saved variables, but string conversion and concatenation seem ridiculously complex and makes me believe there is a better way, I am ignorant of such a way tho:

Code:
local _, private = ...
private.defaults.dejacharacterstatsSelectedStats = {
	HEALTH = true,POWER = false,ARMOR = false,
	STRENGTH = false,AGILITY = true,INTELLECT = false,STAMINA = false,
	ATTACK_DAMAGE = false,ATTACK_AP = false,ATTACK_ATTACKSPEED = false,SPELLPOWER = false,
	MANAREGEN = false,ENERGY_REGEN = false,RUNE_REGEN = false,FOCUS_REGEN = false,MOVESPEED = false,
	CRITCHANCE = false,HASTE = false,VERSATILITY = false,MASTERY = false,
	LIFESTEAL = false,AVOIDANCE = false,
	DODGE = false,PARRY = false,BLOCK = false,
}
So next we have to get the defaults, well not really the defaults, just the keys of the defaults and later OnEvent and OnClick call up the database to get saved variables:

Code:
local checked = private.defaults.dejacharacterstatsSelectedStats

local yAttributes -- Variable to do math to place each subsequently created frame below the previously created frame
Then I have difficulty because
Code:
for k, v in ipairs(checked)
do doesn't iterate and
Code:
for k, v in ipairs, checked do
gives me a function and next loops appear to be undefined like pairs loops.

Code:
for k, v in ipairs(checked) do
	if yAttributes == nil then
		yAttributes = 0
	else
		yAttributes = yAttributes
	end
	local counter = (yAttributes + 1)
	yAttributes = counter
	local statframeofy = (-100 - (yAttributes*25))
		--print(yAttributes)
	print(v)
	
	local KStatFrame = CreateFrame("CheckButton", "KStatFrame"..v, DejaCharacterStatsPanel, "InterfaceOptionsCheckButtonTemplate")
	KStatFrame:RegisterEvent("PLAYER_LOGIN")
	KStatFrame:ClearAllPoints()
	KStatFrame:SetPoint("TOP", 25, statframeofy)
	KStatFrame:SetScale(1.0)
	_G[KStatFrame:GetName() .. "Text"]:SetText(format("%s", v))		

	local kstatname = KStatFrame:GetName()
	--print(kstatname)
				
	yAttributes = yAttributes
end
Any assistance would be appreciated.

Thank you in advance.

Cheers!

Last edited by Dejablue : 07-15-16 at 11:08 PM.
  Reply With Quote
07-16-16, 07:59 AM   #2
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Not sure if I fully understood everything, but here goes.

Seems like you're making the frame reference a lot more complicated than it is! If you really want to start with its name you can do that easily enough.
Code:
_G["KStatFrame"..v]:SetScript(...)
_G is simply a table of all global variables. However I don't know that you need to be doing any of that. You already have a reference to the frame right here:
Code:
local KStatFrame = CreateFrame("CheckButton", "KStatFrame"..v, DejaCharacterStatsPanel, "InterfaceOptionsCheckButtonTemplate")
KStatFrame is a perfectly good reference to the frame. You shouldn't be using anything else.
Furthermore, you can't do anything with the name of a frame, so this won't really help:
Code:
local kstatname= KStatFrame:GetName()
Moving on.
Code:
local (kstatname= KStatFrame:GetName()

KStatFrame:SetScript("OnEvent", function(kstatname, event, arg1)
The kstatname (along with event and arg1) in the SetScript are not in any way related to any other variables. You can't affect what values will be assigned to these variables. This just specifies what variable names you want to use for those values. In the case of all SetScript functions, for example, the first variable will always refer to the frame for which you set the script. (typically named self) So you could leave it as kstatname and use that as the reference, but that would have nothing to do with a kstatname variable that you defined somewhere else. You should use self though, really.

Onto tables. ipairs indeed works only with tables that use numerical sequential indices, such as these:
Code:
t = {
	[1] = "hi",
	[2] = "sup",
	[3] = "bye",
}

t = {
	"hi",
	"sup",
	"bye",
}
Basically it starts at element 1 and increments by one and stops when nothing is found. You need to use pairs, but the order is then undefined, as I believe you noticed. The only way to iterate over a table in a desired order is to use numerical indices.

Hopefully this helps. Feels free to ask me to clarify or explain something I missed!
__________________
Grab your sword and fight the Horde!
  Reply With Quote
07-16-16, 08:32 AM   #3
Dejablue
A Wyrmkin Dreamwalker
 
Dejablue's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 58
Originally Posted by Lombra View Post
Not sure if I fully understood everything, but here goes.

Seems like you're making the frame reference a lot more complicated than it is! If you really want to start with its name you can do that easily enough.
Code:
_G["KStatFrame"..v]:SetScript(...)
...

That is what I thought but I couldn't get it working before. I will play with it more. thank you
Code:
_G["KStatFrame"..v]:SetScript(...)


Moving on.
Code:
local (kstatname= KStatFrame:GetName()

KStatFrame:SetScript("OnEvent", function(kstatname, event, arg1)
The kstatname (along with event and arg1) in the SetScript are not in any way related to any other variables. ...
Yes, this is me trying to do the above...lol

I thought I needed the arguments for

Code:
if event == "PLAYER_LOGIN" then
Onto tables. ipairs indeed works only with tables that use numerical sequential indices, such as these:
...
I had problems with this because ipairs stops when it hits nil so if I wipe or remove anything it doesn't complete, or at least Blizzard's internal method doesn't.

Hopefully this helps. Feels free to ask me to clarify or explain something I missed!
Thanks for taking the time to help I will get on this ASAP.

I made a video to explain better where I am, before your help. Some of it may be moot now, but if you have time I would appreciate you, or anyone, looking at what I could do to get the database working.

Thanks again.

Cheers!



Here is relevant code for the video:

The database init:
Code:
--SavedVariables Setup
local DejaCharacterStats, private = ...

private.defaults = {
}

local loader = CreateFrame("Frame")
	loader:RegisterEvent("ADDON_LOADED")
	loader:SetScript("OnEvent", function(self, addon)
	if addon ~= DejaCharacterStats then 
		local function initDB(db, defaults)
		if type(db) ~= "table" then db = {} end
		if type(defaults) ~= "table" then return db end
		for k, v in pairs(defaults) do
			if type(v) == "table" then
				db[k] = initDB(db[k], v)
			elseif type(v) ~= type(db[k]) then
				db[k] = v
			end
		end
		return db
	end

	DejaCharacterStatsDBPC = initDB(DejaCharacterStatsDBPC, private.defaults)
	private.db = DejaCharacterStatsDBPC -- add this
	self:UnregisterEvent("ADDON_LOADED")
	-- Don't place any frames here
	end
end)

The progress made on the Op before Lombra's post:

Code:
------------------
-- Select Stats --
------------------
local function DCS_SelectStats()
	PAPERDOLL_STATCATEGORIES= {
		[1] = {	categoryFrame = "AttributesCategory", stats = {}, },
		[2] = { categoryFrame = "EnhancementsCategory", stats = {}, },
	}
	PaperDollFrame_UpdateStats();
end

local _, private = ...
private.defaults.dejacharacterstatsSelectStatsChecked = {
	SelectStatsSetChecked = true,
}	

local _, private = ...
private.defaults.dejacharacterstatsSelectedStats = {
--	HEALTH = false,POWER = false,ARMOR = false,
--	STRENGTH = true,AGILITY = false,INTELLECT = false,STAMINA = false,
--	ATTACK_DAMAGE = false,ATTACK_AP = false,ATTACK_ATTACKSPEED = false,SPELLPOWER = false,
--	MANAREGEN = false,ENERGY_REGEN = false,RUNE_REGEN = false,FOCUS_REGEN = false,MOVESPEED = false,
--	CRITCHANCE = false,HASTE = false,VERSATILITY = false,MASTERY = false,
--	LIFESTEAL = false,AVOIDANCE = false,
--	DODGE = false,PARRY = false,BLOCK = false,
}

local function DCS_FillSelectStatsTable()
	local checked = private.db.dejacharacterstatsSelectedStats
	for k, v in pairs(checked) do
	--print(v)
	if v == true then 
		--print(k)
		table.insert(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", k) })
	end
	end
	PaperDollFrame_UpdateStats();
end

local DCS_SelectStatsCheck = CreateFrame("CheckButton", "DCS_SelectStatsCheck", DejaCharacterStatsPanel, "InterfaceOptionsCheckButtonTemplate")
	DCS_SelectStatsCheck:RegisterEvent("PLAYER_LOGIN")
	DCS_SelectStatsCheck:ClearAllPoints()
	DCS_SelectStatsCheck:SetPoint("TOP", 0, -60)
	DCS_SelectStatsCheck:SetScale(1.25)
	DCS_SelectStatsCheck.tooltipText = 'Select which stats to show. Use Shift-scroll to snap to top or bottom, Ctrl-scroll for slow scrolling.' --Creates a tooltip on mouseover.
	_G[DCS_SelectStatsCheck:GetName() .. "Text"]:SetText("Select Stats")
	
	DCS_SelectStatsCheck:SetScript("OnEvent", function(self, event, arg1)
		if event == "PLAYER_LOGIN" then
		local checked = private.db.dejacharacterstatsSelectStatsChecked
			self:SetChecked(checked.SelectStatsSetChecked)
			if self:GetChecked(true) then
				DCS_SelectStats()
				DCS_ShowAllStatsCheck:SetChecked(false)
				private.db.dejacharacterstatsShowAllStatsChecked.ShowAllStatsSetChecked = false
				private.db.dejacharacterstatsSelectStatsChecked.SelectStatsSetChecked = true
			elseif not self:GetChecked(true) then
				private.db.dejacharacterstatsSelectStatsChecked.SelectStatsSetChecked = false
			end
		end
	end)

	DCS_SelectStatsCheck:SetScript("OnClick", function(self, button, down)
	local checked = self:GetChecked()
	print(checked)
		if self:GetChecked(true) then
			DCS_SelectStats()
			DCS_ShowAllStatsCheck:SetChecked(false)
			private.db.dejacharacterstatsShowAllStatsChecked.ShowAllStatsSetChecked = false
			private.db.dejacharacterstatsSelectStatsChecked.SelectStatsSetChecked = true
		elseif not self:GetChecked(true) then
			if DCS_ShowAllStatsCheck:GetChecked(true) then
				DCS_AllStats()
				private.db.dejacharacterstatsShowAllStatsChecked.ShowAllStatsSetChecked = true
			elseif not DCS_ShowAllStatsCheck:GetChecked(true) then
				DCS_RelevantStats()
				private.db.dejacharacterstatsShowAllStatsChecked.ShowAllStatsSetChecked = false
			end
		private.db.dejacharacterstatsSelectStatsChecked.SelectStatsSetChecked = false
		end
	end)	

	
PAPERDOLL_Attributes_STAT_Frames = {
	"Health","Power","Armor","Strength","Agility","Intellect","Stamina","Damage",
}

PAPERDOLL_Enhancements_STAT_Frames = {
	"Critical Strike","Haste","Versatility","Mastery","Leech","Avoidance","Dodge","Parry","Block",
}

local yAttributes

for k, v in ipairs(PAPERDOLL_Attributes_STAT_Frames) do
	--print(k,v)
	local upperstr = string.upper(v)
	--print(upperstr)
	local kdatabase = tostring(upperstr)
	--print(kdatabase)
	if yAttributes == nil then
		yAttributes = 0
	else
		yAttributes = yAttributes
	end
	local counter = (yAttributes + 1)
	yAttributes = counter
	local statframeofy = (-100 - (yAttributes*25))
		--print(yAttributes)
	--print(v)
	
	local KStatFrame = format("%s", kdatabase)
	--print(KStatFrame)
	KStatFrame = CreateFrame("CheckButton", "KStatFrame"..v, DejaCharacterStatsPanel, "InterfaceOptionsCheckButtonTemplate")
	KStatFrame:RegisterEvent("PLAYER_LOGIN")
	KStatFrame:ClearAllPoints()
	KStatFrame:SetPoint("TOP", 25, statframeofy)
	KStatFrame:SetScale(1.0)
	_G[KStatFrame:GetName() .. "Text"]:SetText(format("%s", v))		

	local kstatname = KStatFrame:GetName()
	--print(kstatname)
       
	KStatFrame:SetScript("OnEvent", function(self, event, arg1)
		if private.db.dejacharacterstatsSelectedStats.kdatabase == nil then
			private.db.dejacharacterstatsSelectedStats.kdatabase = {};
		end

		if private.db.dejacharacterstatsSelectedStats.kdatabase[v] == nil then
			private.db.dejacharacterstatsSelectedStats.kdatabase[v] = false;
		end
		private.db.dejacharacterstatsSelectedStats.kdatabase[HEALTH] = true;
		if event == "PLAYER_LOGIN" then
			--print(yAttributes)
			local setchecked = private.db.dejacharacterstatsSelectedStats.kdatabase[v];
			--print(setchecked)
			--print(kdatabase)
			--local ktablename = setchecked:GetName()
			--print(ktablename)
			--local kstatnamechecked = kstatname:GetChecked()
			--print(kstatnamechecked)
			self:SetChecked(setchecked)
			if self:GetChecked(true) then
				table.insert(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", kdatabase) })
				private.db.dejacharacterstatsSelectedStats.kdatabase[v] = true;
			elseif not self:GetChecked(true) then
				private.db.dejacharacterstatsSelectedStats.kdatabase[v] = false;
			end
		end
	end)

	KStatFrame:SetScript("OnClick", function(self, button, down)
		if self:GetChecked(true) then
			--print(kdatabase)
			table.insert(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", kdatabase) })
			private.db.dejacharacterstatsSelectedStats.kdatabase[v] = true;
			DCS_FillSelectStatsTable()
		elseif not self:GetChecked(true) then
			DCS_SelectStats()
			table.wipe(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", kdatabase) })
			private.db.dejacharacterstatsSelectedStats.kdatabase[v] = false;
		end
		PaperDollFrame_UpdateStats();
	end)
	yAttributes = yAttributes
end

Last edited by Dejablue : 07-16-16 at 08:48 AM.
  Reply With Quote
07-16-16, 08:28 PM   #4
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Originally Posted by Dejablue View Post
I thought I needed the arguments for

Code:
if event == "PLAYER_LOGIN" then
Yeah, just don't mistake them for being related to variables with the same name defined outside of that function.

Originally Posted by Dejablue View Post
I had problems with this because ipairs stops when it hits nil so if I wipe or remove anything it doesn't complete, or at least Blizzard's internal method doesn't.
You can use table.remove/tremove to remove an element and "collapse" the table afterwards so the indices remain nice and sequential.

I don't quite understand what the problem with the database is. It's not being used on load? Are you updating the UI after your stuff has been loaded?
__________________
Grab your sword and fight the Horde!
  Reply With Quote
07-16-16, 08:42 PM   #5
Dejablue
A Wyrmkin Dreamwalker
 
Dejablue's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 58
I never figured out what I was doing wrong with the database... I went over the loader and scratched my head forever. I took the day to just rebuild step by step with a friend using your suggestions and his.

Here it is all fixed. Database works. I still have yet to rebuild the frame creation loop but all i did there was remove the table insertions and corrall them into DCS_FillSelectStatsTable(). Also have to do string conversion so the check button labels are not, for example, "ATTACK_POWER" and instead appear as "Attack Power".

Thanks for the help Lombra

here is the working code:

Code:
local _, private = ...
private.defaults.dejacharacterstatsSelectedStats = {
	HEALTH = true,POWER = false,ARMOR = false,
	STRENGTH = false,AGILITY = false,INTELLECT = false,STAMINA = false,
	ATTACK_DAMAGE = false,ATTACK_AP = false,ATTACK_ATTACKSPEED = false,SPELLPOWER = false,
	MANAREGEN = false,ENERGY_REGEN = false,RUNE_REGEN = false,FOCUS_REGEN = false,MOVESPEED = false,
	CRITCHANCE = false,HASTE = false,VERSATILITY = false,MASTERY = false,
	LIFESTEAL = false,AVOIDANCE = false,
	DODGE = false,PARRY = false,BLOCK = false,
}

PAPERDOLL_IndexDefaultStats ={
	[1] = "HEALTH",[2] = "POWER",[3] = "ARMOR",
	[4] = "STRENGTH",[5] = "AGILITY",[6] = "INTELLECT",[7] = "STAMINA",
	[8] = "ATTACK_DAMAGE",[9] = "ATTACK_AP",[10] = "ATTACK_ATTACKSPEED",[11] = "SPELLPOWER",
	[12] = "MANAREGEN",[13] = "ENERGY_REGEN",[14] = "RUNE_REGEN",[15] = "FOCUS_REGEN",[16] = "MOVESPEED",
	[17] = "CRITCHANCE",[18] = "HASTE",[19] = "VERSATILITY",[20] = "MASTERY",
	[21] = "LIFESTEAL",[22] = "AVOIDANCE",
	[23] = "DODGE",[24] = "PARRY",[25] = "BLOCK",
}
	
local function DCS_FillSelectStatsTable()
	for k, v in ipairs(PAPERDOLL_IndexDefaultStats) do
	--print(k,v)
	local checked = private.db.dejacharacterstatsSelectedStats[v]
	--print(checked)
		if checked == true then 
			--print(k,v)
			table.insert(PAPERDOLL_STATCATEGORIES[1].stats, { stat = format("%s", v) })
			PaperDollFrame_UpdateStats();
		end
	end
end
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » For loop Table to Frames Creation Assistance Request


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off