WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Having trouble understanding looped frame creation (https://www.wowinterface.com/forums/showthread.php?t=56455)

Theroxis 07-26-18 06:38 PM

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!

Kanegasi 07-26-18 06:51 PM

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.

Chokobo 07-26-18 07:00 PM

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


Theroxis 07-26-18 07:16 PM

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.


All times are GMT -6. The time now is 07:53 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI