WoWInterface (
-   Lua/XML Help (
-   -   Help on ScrollFrame with LUA (

gmarco 02-10-13 05:34 AM

Help on ScrollFrame with LUA
Hi all,

I'd like to add a simple scrollframe to my addons to show a list of items (names).
The two book I have explain the scrollframe with the use of xml to build the frames.
And the web links I found usually follow this method.

I prefer if possible to avoid this approach and so I am trying to find some links, addons, code to check how this can be implemented with the plain LUA api interface.

I have tried to convert the xml approach to lua code but I didn't succeded.

Thanks very much for any inputs.

Lombra 02-10-13 03:20 PM

Scroll frames are pretty annoying before you know their workings (well even after you know, too), but here is the simplest implementation I can come up with of a mostly working example. (you probably need to create a font string for the buttons and, of course, fill the list with something)

local NUM_BUTTONS = 8
local BUTTON_HEIGHT = 20

local list = {} -- put contents of the scroll frame here, for example item names
local buttons = {}

local function update(self)
        local numItems = #list
        FauxScrollFrame_Update(self, numItems, NUM_BUTTONS, BUTTON_HEIGHT)
        local offset = FauxScrollFrame_GetOffset(self)
        for line = 1, NUM_BUTTONS do
                local lineplusoffset = line + offset
                local button = buttons[line]
                if lineplusoffset > numItems then

local scrollFrame = CreateFrame("ScrollFrame", "MyFirstNotReallyScrollFrame", UIParent, "FauxScrollFrameTemplate")
scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
        FauxScrollFrame_OnVerticalScroll(self, offset, BUTTON_HEIGHT, update)

for i = 1, NUM_BUTTONS do
        local button = CreateFrame("Button", nil, scrollFrame:GetParent())
        if i == 1 then
                button:SetPoint("TOP", scrollFrame)
                button:SetPoint("TOP", buttons[i - 1], "BOTTOM")
        button:SetSize(96, BUTTON_HEIGHT)
        buttons[i] = button

This is a "faux" scroll frame, named so because it doesn't actually scroll. The scroll bar merely gives you an offset value, telling you which part of your list you should display in the "view area". It is intended to be used for simple lists, where the content is visually consistent. (such as the scroll frame where you select which battleground to queue for)

NUM_BUTTONS is the max amount of buttons/frames that will be visible at any one time in the view area, and BUTTON_HEIGHT is the height of these frames. These help deterrmine the position of the scroll bar and more.

The update function will be called everytime you actually scroll, and will reflect the new "view area". The corrent button height and the update function must always be passed to FauxScrollFrame_OnVerticalScroll in the "OnVerticalScroll" handler, as shown.

In the update function you will want to call FauxScrollFrame_Update(self, numItems, NUM_BUTTONS, BUTTON_HEIGHT) to set the scroll bar position. numItems is the total amount of items the scroll frame should represent. In your case, the number of items. You then need to get the offset, which represents the number of frames you have scrolled past. After this we can iterate over all the frame and set them up. The lineplusoffset variable here represents the effective index of your list of items. Assuming 8 buttons; when at the top of the list, offset will be 0, and so items 1 through 8 will be shown. If you scroll past 4 buttons, offset will be 4 and items 5 through 12 will be shown ((1 through 8) + 4). Frames will need to be hidden if the total amount of items is less than the number of items the frame can display at any one time. (< 8, in this case)

Make sure you don't create the subframes as children of the scroll frame itself; then they will be hidden if the size of your list does not exceed the number of items the frame can show.

Maybe this was more than you needed, but there you go. Feel free to ask for more info. :)

gmarco 02-10-13 04:57 PM

Thanks so much for your reply.
I'll begin to study your code now ... :-)

Thanks again.

gmarco 02-11-13 03:04 AM

After a little bit of coding I am not able to display anything inside , probably because I think I miss something more :-/

I have in my addon a defined config frame in this way:

Lua Code:
  1. local options = CreateFrame("Frame", ADDON.."Options", InterfaceOptionsFramePanelContainer)
  2. [...]

and so I changed your code in this way:

Lua Code:
  1. local scrollFrame = CreateFrame("ScrollFrame", "MyFirstNotReallyScrollFrame", options, "FauxScrollFrameTemplate")

Then I begin to populate the list array:

Lua Code:
  1. local list = {"aaa", "bbb", "ccc" }

But I don't get any output (nor errors).

I think I miss the frame to be displayed if I understand well what you wrote to me.

Thanks for attention.

Lombra 02-11-13 06:24 AM

You need to call the update function manually once to "initialize" it. Might be it.

gmarco 02-11-13 08:40 AM

It doesn't work either.

I have double checked everything again and again but I am not able to see any outputs even if I add a :

Lua Code:
  1. update(scrollFrame)

to manually initialize the frame as you suggest.

If I have understood your post, the scrollframe should be the parent frame that will contain the inner scroll child... And so I need another frame to contain all the other things I wanna to be scrolled ...

But here I really don't understand where is this second frame, where I could add, in example, the buttons.

I am sorry if it is a silly question, but I am really lost now :-)

Thanks again for you replies.

Lombra 02-11-13 10:39 AM

No, there is no scroll child [that you need worry about]. That's the thing with the FauxScrollFrameTemplate; it's solely based on the value of the scroll bar. Did you create font strings for the buttons? I can't think of anything else, so if you could post your code we can have a look.

gmarco 02-11-13 12:25 PM

1 Attachment(s)
Thanks again for you replies.

I think I have added the Settext ...
I packed your code in a simple addon so we can test better.

The code is:

Lua Code:
  1. local NUM_BUTTONS = 8
  2. local BUTTON_HEIGHT = 20
  4. local list = {"aaaa","bbbbb","cccccc","ddddddd","eeeeee","ffffff","gggggg","hhhhh"}
  5. local buttons = {}
  7. local function update(self)
  8.     local numItems = #list
  9.     print ("DEBUG: nr. items " .. numItems)
  10.     FauxScrollFrame_Update(self, numItems, NUM_BUTTONS, BUTTON_HEIGHT)
  11.     local offset = FauxScrollFrame_GetOffset(self)
  12.     for line = 1, NUM_BUTTONS do
  13.         local lineplusoffset = line + offset
  14.         local button = buttons[line]
  15.         if lineplusoffset > numItems then
  16.             button:Hide()
  17.         else
  18.             button:SetText(list[lineplusoffset])
  19.             button:Show()
  20.         end
  21.     end
  22. end
  24. local scrollFrame = CreateFrame("ScrollFrame", "MyFirstNotReallyScrollFrame", UIParent, "FauxScrollFrameTemplate")
  25. scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
  26.     FauxScrollFrame_OnVerticalScroll(self, offset, BUTTON_HEIGHT, update)
  27. end)
  29. for i = 1, NUM_BUTTONS do
  30.     local button = CreateFrame("Button", nil, scrollFrame:GetParent())
  31.     if i == 1 then
  32.         button:SetPoint("TOP", scrollFrame)
  33.     else
  34.         button:SetPoint("TOP", buttons[i - 1], "BOTTOM")
  35.     end
  36.     button:SetSize(96, BUTTON_HEIGHT)
  37.     button:SetText(list[i])
  38.     buttons[i] = button
  39. end
  41. print ("DEBUG: Force updating")
  42. update(scrollFrame)

I attach also the zip file of the addon directory.

Thanks again.

zork 02-12-13 01:52 AM

Interesting. I'm currently in the same boat. Setting up my first config panel atm.

Currently into getting my classes up and running. Never created my own classes.

I need a scrollframe aswell. My ScrollFrame should fit right into the huge yellow space:

It should containt a bunc of Sliders/DropDownMenus/Buttons. I hope this is possible because I read ScrollFrame just hide frames while scrolling while showing others.

The thread will be a big help anyway. Thanks.
Maybe I need to create a sort of "lineFrame" first that I can show/hide.

gmarco if you need help on uipanel template stuff you check out:

Those are my test addons.

gmarco 02-12-13 06:49 AM

Hi Zork,
thanks for your reply . I surely check your code and study it.
Let's see if finally I succeded in learning the use of all these frames even if I really don't understand why lombra code will not work for me.

Lombra 02-12-13 07:16 AM

SetText is there yes, but the button needs a font string to display any text. (or maybe it has one by default, can't actually remember)

Either way, the scroll frame needs dimensions and a position before it'll show up.

@ Zork:
Since FauxScrollFrameTemplate is best suited for items with identical height, you might be better off using a real scroll frame. Or it could work if you created identical frames for each widget, as you said.

gmarco 02-12-13 09:25 AM

1 Attachment(s)
I am doing good progress ;)

The code finally is displaying something :-)

Lua Code:
  1. local NUM_BUTTONS = 8
  2. local BUTTON_HEIGHT = 20
  3. local BUTTON_WIDTH = 96
  5. local list = {"aaaa","bbbbb","cccccc","ddddddd","eeeeee","ffffff","gggggg","hhhhh"}
  6. local buttons = {}
  8. local function update(self)
  9.     local numItems = #list
  10.     print ("DEBUG: nr. items " .. numItems)
  11.     FauxScrollFrame_Update(self, numItems, NUM_BUTTONS, BUTTON_HEIGHT)
  12.     local offset = FauxScrollFrame_GetOffset(self)
  13.     for line = 1, NUM_BUTTONS do
  14.         local lineplusoffset = line + offset
  15.         local button = buttons[line]
  16.         if lineplusoffset > numItems then
  17.             button:Hide()
  18.         else
  19.             button:SetText(list[lineplusoffset])
  20.             button:Show()
  21.         end
  22.     end
  23. end
  25. local scrollFrame = CreateFrame("ScrollFrame", "MyFirstNotReallyScrollFrame", UIParent, "FauxScrollFrameTemplate")
  26. scrollFrame:SetWidth(BUTTON_WIDTH)
  27. scrollFrame:SetHeight(BUTTON_HEIGHT*6)
  28. scrollFrame:SetPoint("CENTER",UIParent)
  29. scrollFrame:EnableMouse(true)
  30. scrollFrame:SetMovable(true)
  31. scrollFrame:RegisterForDrag("LeftButton")
  32. scrollFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
  33. scrollFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
  34. scrollFrame:Show()
  35. scrollFrame:SetClampedToScreen(true)
  36. scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
  37.     FauxScrollFrame_OnVerticalScroll(self, offset, BUTTON_HEIGHT, update)
  38. end)
  40. for i = 1, NUM_BUTTONS do
  41.     local button = CreateFrame("Button", nil, scrollFrame:GetParent())
  42.     if i == 1 then
  43.         button:SetPoint("TOP", scrollFrame)
  44.     else
  45.         button:SetPoint("TOP", buttons[i - 1], "BOTTOM")
  46.     end
  47.     button:SetNormalFontObject("GameFontNormal")
  48.     button:SetSize(BUTTON_WIDTH, BUTTON_HEIGHT)
  49.     button:SetText(list[i])
  50.     buttons[i] = button
  51. end
  55. -- enabling the last line will make the slidebar disappears.
  56. -- print ("DEBUG: Force updating")
  57. -- update(scrollFrame)

Now I get the scrollframe with sliders but it is wrong. You can check the picture to see...
It doesn't cover the out of scrollframe part nor it scrolls using the slide.

Other thing: If I enable the manual update of the frame (last line) the sliders will disappears (!??!) :-)

Thanks again for any inputs/clues/tips :-)

Lombra 02-12-13 10:00 AM

Good to hear. :)

This is all expected. The buttons are actually completely independant of the scroll frame and vice versa. They just happen to be anchored to it. For all the scroll frame knows, you could be simply printing different numbers in the update function instead of doing something with the buttons.

You have decided that 8 buttons be created (as per NUM_BUTTONS), and the size of the scroll frame is smaller than the total height of these. That's all there is to it. Again, the scroll frame is completely independent of the buttons, and has no idea how much screen space they take up. If you're using constants for the number of buttons and their height a simple solution would be:

scrollFrame:SetHeight(NUM_BUTTONS * BUTTON_HEIGHT)
which I just noticed you were nearly already doing, you just used 6 instead of 8 which NUM_BUTTONS was set to. This way the appropriate height will always be calculated when you change the amount and height of the buttons via the constants. At least, as long as the offset between each button is 0.

The scroll bar will always remain in its original state (visible and inactive) until you first call FauxScrollFrame_Update, which you do in the update function. The reason it disappears when you do so is that you have enough buttons that the entire list can be displayed without scrolling (you have 8 buttons and 8 items in the list). If you add one more item or remove one button, you will see that it works!

zork 02-12-13 10:00 AM

Try this example

It does not make use of templates yet but it shows how to handle the ScrollChild.

Of course...using FauxTemplate is handling the ScrollChild quite differently I think.


Got exactly what I was looking for.

Code will be coming soon.

I'm using a ScrollFrame with this template: "UIPanelScrollFrameTemplate" with a twist.

To bad I wanted a ScrollBar with this template: "UIPanelScrollBarTrimTemplate". The UIPanelScrollFrameTemplate only uses UIPanelScrollBarTemplate. So I just looked up the SetTexCoord for the scrollbar border and added it manually.


Ok here is the code that does it:

Thanks to templates there is actually veeery few code to write.

gmarco 02-12-13 02:08 PM

Thanks to Lombra !!
Now I have my example ready to be implemented in the addon (remgank :-) .

Zork, I'll give you look to your code too. I am very curious about the template facilities even if the code by Lombra is for my needs the thing I was looking for. :-)

I think this thread should be made sticky or someone should made a little summary sticky :-) because the scrollframes are imho one of the things that a newbie programmer have more problems with.

I'll post the working code later (after the raid if I don't sleep :-) and probably with some more questions ... :-)

Thanks also to Zork, his inputs are really appreciated.

zork 02-12-13 02:46 PM

I finshed my test and implemented a first version into my panel.

You can even freely resize the whole panel and the scrollFrame will be cropped properly. The scrollbar adjusts properly aswell. Very nice.

All what I had to do was:

If you are fine with the default template you can even go with

Lua Code:
  1. --create a scrollframe inside
  2.     local scrollFrame = CreateFrame("ScrollFrame", "$parentScrollFrame", frame, "UIPanelScrollFrameTemplate")
  3.     scrollFrame:SetPoint("TOPLEFT")
  4.     scrollFrame:SetPoint("BOTTOMRIGHT",-22,0)
  6.     local scrollChild = CreateFrame("Frame",nil,ScrollFrame)
  7.     --scrollChild:SetWidth(scrollFrame:GetWidth()) --optional
  8.     --fill scrollchild with data and adjust size
  9.     genData(scrollChild,100)
  10.     scrollFrame:SetScrollChild(scrollChild)

zork 02-13-13 09:43 AM


I just had an "what if"-moment.

Please help me on that.

The scrollFrame crops anything from the ChildFrame that is not visible. That is actually pretty interesting...

I tested only FontStrings...does this work on any frame type? Need to test sth asap.

semlar 02-13-13 10:24 AM

The scrollframe will clip any part of the child frame that passes its border, but be aware that it still has to draw everything, even if you can't see it. The only frame type I'm not sure will clip are models, but it would be easy enough to test.

Here are some ways I've used scrollframes:

And this is what happens if you try to rotate the scroll parent..

And yes, you can put scrollframes inside of scrollframes.

zork 02-13-13 11:58 AM

Holy mother of grail. I'm just testing. Do you know what that means?

I can finally cut animation models depending on orb value state!!!

Lol ... I cannot believe this is for real. But I have a screenshot. It actually does work.

Any kind of animation will be cropped. Models, textures, anything.

No more alpha fading ... HOLY SMOKES!!! This is HUUUGE!!! (at least for me...)

humfras 02-13-13 12:28 PM

I can see clearly now...

This solution is so simple, why didn't someone thought about that before? :D

Kleiner Tipp: Du solltest die RealIDs unkenntlich machen.

All times are GMT -6. The time now is 09:30 PM.

vBulletin © 2018, Jelsoft Enterprises Ltd
© 2004 - 2017 MMOUI