Quantcast
How to properly use CreateFramePool() ? - WoWInterface
Thread Tools Display Modes
08-05-17, 09:51 AM   #1
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 260
How to properly use CreateFramePool() ?

I've been seeing a lot of Blizzard code using CreateFramePool() and I'm wondering if it's worth using this myself as opposed to creating my own stack-like data structure. However, maybe it does something more than this but I can't find any documentation on it.

This is the content found inside a returned frame pool object:

ReleaseAll
achieveObjects
numActiveObjects
inactiveObjects
GetNumActive
resettingFunc
OnLoad
creationFunc
EnumerateActive
Release
Acquire
GetNextActive
EnumerateIntactive

My question is this: Is there any documentation on how to use this?

I'm assuming that you can disable/enable frames from the pool using:

Lua Code:
  1. local pool = CreateFramePool()
  2. local frame = pool:Acquire() -- uses an inactive frame or creates one with "creationFunc" function
  3. pool:Release(frame) -- not really sure if this is the correct way to disable the frame
  4.  
  5. -- something is always true. Maybe it represents if the frame is active, but since I am iterating over only active frames this seems pointless
  6. for frame, something in pool:EnumerateActive() do
  7.     -- run code to update your frame (could be a buff icon for example)
  8. end

Not sure what OnLoad does. Does it run when a frame becomes active?

Last edited by Mayron : 08-05-17 at 09:53 AM.
  Reply With Quote
08-05-17, 10:54 AM   #2
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 427
This is entirely implemented in Lua so you can just read the source code.

Lua Code:
  1. ObjectPoolMixin = {};
  2.  
  3. function ObjectPoolMixin:OnLoad(creationFunc, resetterFunc)
  4.     self.creationFunc = creationFunc;
  5.     self.resetterFunc = resetterFunc;
  6.  
  7.     self.activeObjects = {};
  8.     self.inactiveObjects = {};
  9.  
  10.     self.numActiveObjects = 0;
  11. end
  12.  
  13. function ObjectPoolMixin:Acquire()
  14.     local numInactiveObjects = #self.inactiveObjects;
  15.     if numInactiveObjects > 0 then
  16.         local obj = self.inactiveObjects[numInactiveObjects];
  17.         self.activeObjects[obj] = true;
  18.         self.numActiveObjects = self.numActiveObjects + 1;
  19.         self.inactiveObjects[numInactiveObjects] = nil;
  20.         return obj, false;
  21.     end
  22.  
  23.     local newObj = self.creationFunc(self);
  24.     if self.resetterFunc then
  25.         self.resetterFunc(self, newObj);
  26.     end
  27.     self.activeObjects[newObj] = true;
  28.     self.numActiveObjects = self.numActiveObjects + 1;
  29.     return newObj, true;
  30. end
  31.  
  32. function ObjectPoolMixin:Release(obj)
  33.     assert(self.activeObjects[obj]);
  34.  
  35.     self.inactiveObjects[#self.inactiveObjects + 1] = obj;
  36.     self.activeObjects[obj] = nil;
  37.     self.numActiveObjects = self.numActiveObjects - 1;
  38.     if self.resetterFunc then
  39.         self.resetterFunc(self, obj);
  40.     end
  41. end
  42.  
  43. function ObjectPoolMixin:ReleaseAll()
  44.     for obj in pairs(self.activeObjects) do
  45.         self:Release(obj);
  46.     end
  47. end
  48.  
  49. function ObjectPoolMixin:EnumerateActive()
  50.     return pairs(self.activeObjects);
  51. end
  52.  
  53. function ObjectPoolMixin:GetNextActive(current)
  54.     return (next(self.activeObjects, current));
  55. end
  56.  
  57. function ObjectPoolMixin:GetNumActive()
  58.     return self.numActiveObjects;
  59. end
  60.  
  61. function ObjectPoolMixin:EnumerateInactive()
  62.     return ipairs(self.inactiveObjects);
  63. end
  64.  
  65. function CreateObjectPool(creationFunc, resetterFunc)
  66.     local objectPool = CreateFromMixins(ObjectPoolMixin);
  67.     objectPool:OnLoad(creationFunc, resetterFunc);
  68.     return objectPool;
  69. end
  70.  
  71. FramePoolMixin = Mixin({}, ObjectPoolMixin);
  72.  
  73. local function FramePoolFactory(framePool)
  74.     return CreateFrame(framePool.frameType, nil, framePool.parent, framePool.frameTemplate);
  75. end
  76.  
  77. function FramePoolMixin:OnLoad(frameType, parent, frameTemplate, resetterFunc)
  78.     ObjectPoolMixin.OnLoad(self, FramePoolFactory, resetterFunc);
  79.     self.frameType = frameType;
  80.     self.parent = parent;
  81.     self.frameTemplate = frameTemplate;
  82. end
  83.  
  84. function FramePool_Hide(framePool, frame)
  85.     frame:Hide();
  86. end
  87.  
  88. function FramePool_HideAndClearAnchors(framePool, frame)
  89.     frame:Hide();
  90.     frame:ClearAllPoints();
  91. end
  92.  
  93. function CreateFramePool(frameType, parent, frameTemplate, resetterFunc)
  94.     local framePool = CreateFromMixins(FramePoolMixin);
  95.     framePool:OnLoad(frameType, parent, frameTemplate, resetterFunc or FramePool_HideAndClearAnchors);
  96.     return framePool;
  97. end
__________________
  Reply With Quote
08-05-17, 11:16 AM   #3
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 260
This is perfect. I wasn't sure what the main object was called. Thank you!
I'll start running some tests and figure out how it all fits together
  Reply With Quote
08-05-17, 12:05 PM   #4
Kanegasi
A Firelord
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 487
Once I understood what this frame pool did, I created a very simple version I use in Decliner for generating OnUpdate responses to some filters. This way, I don't need several dedicated OnUpdate frames, just a dynamic pool that uses the first unused frame or creates a new one that adds to the pool when finished. Blizzard's way is definitely more sophisticated and made for different scenarios, but if you just need a disposable OnUpdate frame with one piece of data included in the frame, you could try what I did.

Lua Code:
  1. local pool={}
  2. function f.pool(t,i)
  3.     if i then
  4.         pool[i]:SetScript('OnUpdate',nil)
  5.         pool[i].t=nil
  6.         return
  7.     end -- function was called with an index, terminate frame at that index
  8.     for i=1,#pool do
  9.         if pool[i] and not pool[i].t then
  10.             pool[i].t={i=i,t=t}
  11.             return i
  12.         end -- loop through frames to find an unused one and return the index, putting "t" into the frame
  13.     end
  14.     insert(pool,CreateFrame('frame'))
  15.     i=#pool
  16.     pool[i].t={i=i,t=t}
  17.     return i -- no unused frames found, generate a new one and return its index, also putting "t" into the frame
  18. end


An example of usage is the following response to blocked guild invites:

Lua Code:
  1. pool[f.pool((GetCVar('Sound_EnableSFX')))]:SetScript('OnUpdate',function(self)
  2.     SetCVar('Sound_EnableSFX',self.t.t)
  3.     f.pool('',self.t.i)
  4. end)
  5. SetCVar('Sound_EnableSFX','0')

This calls a frame directly from the pool table, while getting the index from f.pool's return and putting the current SFX setting into the "t" key of the frame. Then I turn off SFX. Once the OnUpdate fires a frame later, reset SFX and release the frame using its index stored in the "i" key.

This completely blocks the "level up" sound when someone invites you to a guild.

I'm sure there's a cleaner way to do what I did, but it works for me.
  Reply With Quote
08-05-17, 01:13 PM   #5
Mayron
A Frostmaul Preserver
 
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 260
@Kanegasi I've made a few things like this myself for a timer bars tracking addon except it executes the update function for each frame in the pool iteratively and probably not as intricate as your interesting design. Thanks for the example, I like it. Gives me a new approach to consider.
  Reply With Quote
08-05-17, 07:45 PM   #6
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,699
It's mostly good for when you want to fill a list of objects, was messing around with this one and texturepools.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » How to properly use CreateFramePool() ?

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