Thread Tools Display Modes
07-26-18, 06:38 PM   #1
Theroxis
A Fallenroot Satyr
Join Date: Jun 2018
Posts: 24
Having trouble understanding looped frame creation

Basically what I'm trying to do is learn how to do various things by creating UI elements that I desire in my personal gameplay. I've learned a lot, but there's a lot left to go. I want to create several extra action buttons along the bottom side of my minimap, squished tightly together. I can create one button successfully, using SecureActionButtonTemplate and SecureHandlerDragTemplate so that the buttons can have basically anything dragged onto/off of them at will.
But when I try to loop to create multiple buttons it does not work, saying that the local variable I'm using to store the array is nil (which it should be, as I haven't defined any buttons yet) The question is how am I supposed to handle this??
Thanks for the help


Code:
local numMapButtons = math.floor(Minimap:GetWidth() / 20)
	local mapButton;
for i=1, numMapButtons do

	mapButton[i]=DragExample or CreateFrame("Button", "DragExample", UIParent, "ActionButtonTemplate,SecureActionButtonTemplate,SecureHandlerDragTemplate")
	mapButton[i]:SetWidth(20)
	mapButton[i]:SetHeight(20)
	if i==1 then
	mapButton[i]:SetPoint("TOPLEFT",Minimap,"BOTTOMLEFT",5,-5)
	else
	mapButton[i]:SetPoint("LEFT",mapButton[i-1],"RIGHT",5)
	end

	mapButton[i]:SetAttribute("_onreceivedrag", [[
	  -- kind,value,... are returns of GetCursorInfo()
	  if kind=="item" or kind=="spell" or kind=="macro" then
	    self:SetAttribute("type",kind)
	    if kind=="item" then
	      value = "item:"..value
	    elseif kind=="spell" then
	      value = select(2,...) -- the raw spell id (4th return GetCursorInfo)
	    end
	    -- "item","item:1234" or "spell",1234 or "macro",1234
	    self:SetAttribute(kind,value)
	    return "clear"
	  end
	]])

	mapButton[i]:SetScript("OnAttributeChanged",function(self,attribType,attribDetail)
	  -- only changing texture. not dealing with cooldowns or item counts
	  if attribType=="item" then
	    self.icon:SetTexture((select(10,GetItemInfo(attribDetail))))
	  elseif attribType=="spell" then
	    self.icon:SetTexture((select(3,GetSpellInfo(attribDetail))))
	  elseif attribType=="macro" then
	    self.icon:SetTexture((select(2,GetMacroInfo(attribDetail))))
	  end
	end)
end
EDIT:
I'm an idiot, I need to declare the variable as an array:
local mapButton ={}; is sufficient to make that happen.

From there I've got other problems, but this makes more sense now. I obviously need to change the way I am using SetPoint now that I've progressed forward. PROGRESS THOUGH!

Last edited by Theroxis : 07-26-18 at 07:14 PM.
  Reply With Quote
07-26-18, 06:51 PM   #2
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 666
That's the issue. The local variable is nil. It needs to be a table before you assign any indexes.

You also need to create a separate frame for each button, but that top line in the loop will reuse the same frame over and over again, only creating one button that will either keep moving over 5 pixels or error trying to create a second button because you can't anchor a frame to itself.

Change these two lines:

Lua Code:
  1. local mapButton;
  2. mapButton[i]=DragExample or CreateFrame("Button", "DragExample", UIParent, "ActionButtonTemplate,SecureActionButtonTemplate,SecureHandlerDragTemplate")

To these:

Lua Code:
  1. local mapButton = {};
  2. mapButton[i]=CreateFrame("Button", "DragExample" .. i, UIParent, "ActionButtonTemplate,SecureActionButtonTemplate,SecureHandlerDragTemplate")

This makes mapButton an empty table, ready to accept the indexes you're trying to assign, and properly creates a separate frame for each button with the index appended to the global name so they can all coexist.
  Reply With Quote
07-26-18, 07:00 PM   #3
Chokobo
A Murloc Raider
Join Date: Jul 2018
Posts: 9
Just an example of how I do it in my addons. Not saying it's right. But using a class and a loop to create some frames. Should be able to copy this into an existing addon and see the effect.

Code:
TestAddon = {}
MyFrames = {}

--Static frame class.
function TestAddon:CreateStaticFrameX(shade, x, y, xoff, yoff, name, parent)
	local self = {}
	self.frame = CreateFrame("Frame",name,parent)
	self.frame:SetPoint("CENTER",xoff,yoff)
	self.frame:SetSize(x, y)
	self.texture = self.frame:CreateTexture("ARTWORK") 
	self.texture:SetColorTexture(shade,shade,shade,1)
	self.texture:SetAllPoints(self.frame)
	self.frame:SetFrameStrata("HIGH")
	self.frame:Show()
    return self
end

for i=20,200,10 do
	local f = TestAddon:CreateStaticFrameX(0.2, 15, 15, i, i, "TestFrame", UIParent)
	tinsert(MyFrames ,f)
end
  Reply With Quote
07-26-18, 07:16 PM   #4
Theroxis
A Fallenroot Satyr
Join Date: Jun 2018
Posts: 24
FANTASTIC.
This makes SO MUCH more sense now. I knew it had to be something small that I was missing with the way frame creation is handled within the WoW API and the way variable typing happens in lua. Holy cow that is such a relief lol.

Now it's just time to work on the positioning via setpoint but that's a different battle, and much simpler.

Last edited by Theroxis : 07-26-18 at 07:19 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Having trouble understanding looped frame creation

Thread Tools
Display Modes

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