Thread Tools Display Modes
07-09-12, 12:45 AM   #1
Brusalk
An Aku'mai Servant
 
Brusalk's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 32
Determining a frame from a normal table?

Hey There!

So in my addon I need to find a way to differentiate between a table value and a frame value (or texture, fontString, etc).

I've been trying to figure it out, and I can't seem to figure out a way to differentiate it without throwing an error that the method doesn't exist. Type(tableorframename) returns table regardless.


To be clear: I'm trying to do something like

if IsFrame(temp) then -- do stuff since it's a frame
elseif type(temp) == "table" then -- do other stuff since it's a table and not a frame
else -- idk
end

And no, I'm not trying to make a frame if it doesn't exist, I'm trying to differentiate between a table and a frame/widget.


Thanks!
-Brusalk
  Reply With Quote
07-09-12, 01:52 AM   #2
Barjack
A Black Drake
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 89
There may be a more sophisticated way to do this, but you don't need to call a function to find out if it exists or not, so you can use that to kind of check whether something is (probably) a widget. For example:

Lua Code:
  1. if (obj.GetObjectType) then
  2.   -- it's a widget of some sort
  3.   if (obj:GetObjectType() == "Frame") then
  4.     -- do whatever. could also be "Button", "StatusBar", etc.
  5.   end
  6. else
  7.   -- it's a table
  8. end

Of course if someone actually defines a GetObjectType on their table which isn't really a frame, this might backfire. I don't know if that's actually relevant for your purposes though.
  Reply With Quote
07-09-12, 02:01 AM   #3
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Brusalk View Post
So in my addon I need to find a way to differentiate between a table value and a frame value (or texture, fontString, etc).
For most purposes:

Code:
if type(object) == "table" then
     if object.GetObjectType then
          -- it's a frame, texture, font string, or other UI widget
     else
          -- it's a table
     end
end
Slightly slower but slightly more foolproof if you're worried about tables "pretending" to be widgets by defining GetObjectType or methods on themselves:

Code:
if type(object) == "table" then
    if type(object[0]) == "userdata" then
        -- it's a widget
    else
        -- it's a table
    end
end
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-09-12, 03:28 PM   #4
Brusalk
An Aku'mai Servant
 
Brusalk's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 32
Awesome, thanks!

I tried doing a /run print(type(tableVar[0])) and it was returning table when I tried to do that last night. (I defined tableVar as a global frame by /run tableVar = CreateFrame("frame")


On another note, is there a way to make your own UI widget that new frames can inherit off of? I'm working in my addon with a frame which contains a bunch of methods and variables which I'm interested in duplicating (exactly the same as creating a frame which inherits something like a PaperDollFrame or something like that)
  Reply With Quote
07-09-12, 04:41 PM   #5
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,366
Originally Posted by Brusalk View Post
Awesome, thanks!

I tried doing a /run print(type(tableVar[0])) and it was returning table when I tried to do that last night. (I defined tableVar as a global frame by /run tableVar = CreateFrame("frame")


On another note, is there a way to make your own UI widget that new frames can inherit off of? I'm working in my addon with a frame which contains a bunch of methods and variables which I'm interested in duplicating (exactly the same as creating a frame which inherits something like a PaperDollFrame or something like that)
There's 2 ways (that I know) to do this.
a. Use xml for your template frame and set the virtual attribute to true Wowpedia: Using templates.
b. Use a frame constructor function that returns a frame if you want to achieve a similar effect in pure lua.
  Reply With Quote
07-09-12, 05:48 PM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Code:
local function NewItemButton()
	local button = CreateFrame("Button", nil, UIParent)
	button.text = button:CreateFontString(nil, "OVERLAY")
	button.icon = button:CreateTexture(nil, "OVERLAY")
	-- Set up scripts, regions, and other features
	-- that are shared by all buttons here.
end

local button1 = NewItemButton()
button1:SetPoint("CENTER", 0, 200)
-- Set points, icon textures, fontstring text, and other features
-- that are specific to this individual button here.

local button2 = NewItemButton()
button2:SetPoint("RIGHT", -100, 0)
Or, you can use a metatable:

Code:
local buttons = setmetatable({}, { __index = function(t, i)
	local button = CreateFrame("Button", nil, UIParent)
	button.text = button:CreateFontString(nil, "OVERLAY")
	button.icon = button:CreateTexture(nil, "OVERLAY")

	-- Set up scripts, regions, and other features
	-- that are shared by all buttons here.

	if i > 1 then
		-- Not the first button; attach to previous button
		button:SetPoint("TOP", buttons[i-1], "BOTTOM")
	else
		-- First button; no previous button to attach to
		button:SetPoint("TOP", UIParent, "CENTER", 0, 200)
	end

	t[i] = button
	return button
end })

for i = 1, 10 do
	-- This will create 10 buttons, even though you never explicitly call any functions to create them.
	local button = buttons[i]
	button.text:SetText("Button #"..i)
	button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
end
Depending on what kind of objects you want to create, and how you're using them, one method will make more sense than the other. Both make more sense than XML though.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 07-09-12 at 10:09 PM.
  Reply With Quote
07-09-12, 06:14 PM   #7
Brusalk
An Aku'mai Servant
 
Brusalk's Avatar
AddOn Author - Click to view addons
Join Date: May 2010
Posts: 32
Is there a specific speed increase one way over the other and how does WoW/Lua handle the creation of frames using a metatable? Like, they do exactly the same thing, but does one require less memory or execution time or is one faster in completing execution?

When you're defining the metatable, there's __index = function(t, i). Is t a reference to the table that's created or is it a reference to the base object. (From brief reading of metatables in the Lua-man, I see that __index is a metamethod that is basically a catch-all) For example, say I wanted to make a series of new frames that all share some common properties.

I'd define a metatable (using setmetatable) giving it all the stuff you included in your example, letting me make a bunch of frames easily by indexing the metatable. Now, say I wanted to define methods on the created frames, such as returning a custom value contained in the frame. So I would add something like this?

Code:
local buttons = setmetatable({}, { __index = function(t, i)
	local button = CreateFrame("Button", nil, UIParent)
	button.text = button:CreateFontString(nil, "OVERLAY")
	button.icon = button:CreateTexture(nil, "OVERLAY")

	-- Set up scripts, regions, and other features
	-- that are shared by all buttons here.

        function button:GetIconTexture()
              return self.icon:GetTexture()
        end

	if i > 1 then
		-- Not the first button; attach to previous button
		button:SetPoint("TOP", buttons[i-1], "BOTTOM")
	else
		-- First button; no previous button to attach to
		button:SetPoint("TOP", UIParent, "CENTER", 0, 200)
	end
end })

for i = 1, 10 do
	-- This will create 10 buttons, even though you never explicitly call any functions to create them.
	local button = buttons[i]
	button.text:SetText("Button #"..i)
	button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
        print(button:GetIconTexture()) -- prints "Interface\\Icons\\INV_MISC_QuestionMark"
end
So adding that would allow me to hide some commonly used implementation to clean up other sections of code, or am I wrong and misunderstanding something?
  Reply With Quote
07-09-12, 09:33 PM   #8
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,356
Originally Posted by Phanx View Post
Code:
local buttons = setmetatable({}, { __index = function(t, i)
	local button = CreateFrame("Button", nil, UIParent)
	button.text = button:CreateFontString(nil, "OVERLAY")
	button.icon = button:CreateTexture(nil, "OVERLAY")

	-- Set up scripts, regions, and other features
	-- that are shared by all buttons here.

	if i > 1 then
		-- Not the first button; attach to previous button
		button:SetPoint("TOP", buttons[i-1], "BOTTOM")
	else
		-- First button; no previous button to attach to
		button:SetPoint("TOP", UIParent, "CENTER", 0, 200)
	end
end })

for i = 1, 10 do
	-- This will create 10 buttons, even though you never explicitly call any functions to create them.
	local button = buttons[i]
	button.text:SetText("Button #"..i)
	button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
end
You need the __index metamethod to return a value or buttons[i] will still retrieve nil. Also to prevent the table from recreating extra buttons constantly, you should actually set the value in the table.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Determining a frame from a normal table?


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