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


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
  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
A Scalebane Royal Guard
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
This is entirely implemented in Lua so you can just read the source code.

Lua Code:
  1. ObjectPoolMixin = {};
  3. function ObjectPoolMixin:OnLoad(creationFunc, resetterFunc)
  4.     self.creationFunc = creationFunc;
  5.     self.resetterFunc = resetterFunc;
  7.     self.activeObjects = {};
  8.     self.inactiveObjects = {};
  10.     self.numActiveObjects = 0;
  11. end
  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
  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
  32. function ObjectPoolMixin:Release(obj)
  33.     assert(self.activeObjects[obj]);
  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
  43. function ObjectPoolMixin:ReleaseAll()
  44.     for obj in pairs(self.activeObjects) do
  45.         self:Release(obj);
  46.     end
  47. end
  49. function ObjectPoolMixin:EnumerateActive()
  50.     return pairs(self.activeObjects);
  51. end
  53. function ObjectPoolMixin:GetNextActive(current)
  54.     return (next(self.activeObjects, current));
  55. end
  57. function ObjectPoolMixin:GetNumActive()
  58.     return self.numActiveObjects;
  59. end
  61. function ObjectPoolMixin:EnumerateInactive()
  62.     return ipairs(self.inactiveObjects);
  63. end
  65. function CreateObjectPool(creationFunc, resetterFunc)
  66.     local objectPool = CreateFromMixins(ObjectPoolMixin);
  67.     objectPool:OnLoad(creationFunc, resetterFunc);
  68.     return objectPool;
  69. end
  71. FramePoolMixin = Mixin({}, ObjectPoolMixin);
  73. local function FramePoolFactory(framePool)
  74.     return CreateFrame(framePool.frameType, nil, framePool.parent, framePool.frameTemplate);
  75. end
  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
  84. function FramePool_Hide(framePool, frame)
  85.     frame:Hide();
  86. end
  88. function FramePool_HideAndClearAnchors(framePool, frame)
  89.     frame:Hide();
  90.     frame:ClearAllPoints();
  91. end
  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
A Frostmaul Preserver
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 266
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
A Molten Giant
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 533
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
A Frostmaul Preserver
Mayron's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2010
Posts: 266
@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
A Pyroguard Emberseer
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,705
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