Derived from: <LayoutFrame>
Contained in: <Frames>, <Ui>
Runtime object: UIOBJECT_Frame
- <TitleRegion />
- (see Widget handlers)
- (float) The opacity of the frame, where 1.0 is opaque and 0.0 is fully transparent.
- (boolean) Whether or not the frame should be displayed on top of all the other frames in its strata (see frameStrata).
- (boolean) Whether the frame can be moved by the user.
- (boolean) Whether the frame can be resized by the user.
- (string) Which layer your frame should be on. Some words of caution: if you set your frameStrata to "BACKGROUND" it will be blocked from receiving mouse events unless you set frameLevel to 1 or more. Same goes for "TOOLTIP" regardless of frameLevel. Possible values are, from highest to lowest:
- (int) What level your frame is on, in the strata. Normally decided by parent-child relationships and better left untouched - also, see the difference between frameLevel and frameStrata below.
- (boolean) Whether mouse events are sent to the frame.
- (boolean) Whether keystroke events are sent to the frame.
- (boolean) Whether the frame is kept inside the screen boundaries.
- (boolean) Whether the frame is allowed to run protected code (only allowed in Blizzard code).
- (string) Defines a name for a key in the parent element, which will reference this element at runtime.
<Frame name="MyFrame"> <Frames> <Frame name="$parentChild" parentKey="child" /> </Frames> </Frame>
- At runtime, you can refer to the child frame as either
- (string) Defines a name for an array in the parent element, which will reference this element at runtime.
<Frame name="MyFrame"> <Frames> <Frame name="$parentChild1" parentArray="children" /> <Frame name="$parentChild2" parentArray="children" /> </Frames> </Frame>
- You can iterate over this using MyFrame.children, MyFrame.children, etc.
Inherited from <LayoutFrame>:
- (string) Defines the name of the element. This gets registered in the LUA global variables. Using the $parent tag here refers to the parent's name - or the parent's parent's name, if the parent is unnamed, or even further up.
- (string) Instantiates the element using a virtual element as a template.
- (boolean) Defines the element as template, to be inherited from. The element itself is not created.
- (boolean) Automatically anchors the TOPLEFT, TOPRIGHT, BOTTOMLEFT and BOTTOMRIGHT points to the parent.
- (boolean) Makes the element hidden by default.
Frames are the building blocks of the visual components of the user interface. All of the various visual elements of the UI are types of Frame, and inherit most if not all of the basic frame properties, in addition to adding some more. Frames are defined in the various
.xml files in the
Interface directory (except for the
Bindings.xml files, which provide key bindings).
In addition to Frames being the things that you can see, Frames are also the things which UI and game events are delivered to. If you're writing code that needs to know about something, it will need a Frame (though not necessarily a visible one) to receive the event. There are many types of events, though often in AddOn development it refers to a Game Event rather than other UI events.
A frame indicates its interest in events in a number of ways:
The <Scripts> XML element of a frame definition defines a bunch of different handler types, for most of these (<OnEvent> being the exception) the Frame will automatically be informed of the appropriate events when they occur, via the defined handler script.
Most of the useful information comes from game events, which are all passed to the frame via the generic <OnEvent> script handler. There are literally hundreds of types of Game Events, so rather than spend a lot of time passing every event to every handler, an AddOn must register its interest in a frame receiving a certain event. This is accomplished through the Frame:RegisterEvent("event") function, and is typically performed within the <OnLoad> or <OnShow> handlers. Once an event has been registered, the Frame's <OnEvent> handler will be called whenever that event occurs.
Frames can be defined as virtual, in which case instead of defining an actual UI element that shows up, the definition provides a template which can then be used multiple times by other Frames. A good example of a virtual Frame is the chat window, there are actually several virtual frames which are assembled into a chat window, but then each potential chat window simply implements the virtual one, which reduces the amount of duplicated code required.
Every Frame can have a parent frame, and well behaved UI AddOns will want to set their parent to
UIParent (Failure to do so means, amongst other things, that the AddOn doesn't vanish when the Hide GUI key is pressed). A complex visual element is likely formed of multiple Frames, and it's considered good design to designate a parent Frame amongst them, and have the rest use that (or its children) as their parent. Doing this is useful for a couple of reasons.
Each Frame can be shown and hidden, if a Frame is Hidden, then it and all of its children cease to be visible. It's far simpler to show and hide the parent frame of a complex set, than to try and manage the visibility of many elements independently.
The World of Warcraft UI engine is built to perform automatic scaling of UI elements, the entire UI (actually, the UIParent frame, which most frames are children of), or any component of it can be enlarged or shrunk to fit on a screen appropriately. Frames are scaled and located relative to their parent rather than the whole screen, which means that you only need to worry about how your subcomponents relate to each other, and then your component can be placed and sized any way necessary.
Frame levels are that which determines what frame will be on top of other frame. Each frame has a frame level value. If frame A is placed in the same area as frame B, then the frame with the highest frame level will be on top of the other frame.
Instead of going around and specifying that frame A should have frame level 12, and frame B frame level 15, Blizzard uses a set of predefined "groups" of frame levels called frameStrata. The valid values for frameStrata are "PARENT", "BACKGROUND", "LOW", "MEDIUM", "HIGH", "DIALOG", "FULLSCREEN_DIALOG" and "TOOLTIP" (there may be more). For the values "BACKGROUND" through "TOOLTIP" the values are listed in their assumed ascendancy (i.e. it is assumed that "BACKGROUND" will be below "LOW"). The default value is "PARENT" if no frameStrata is specified.
There is also a special attribute called toplevel - this means (hopefully) that the frame should be on top of any other frame (or, possibly, on top of any other frame in the same frameStrata).
What is the difference between frameLevel and frameStrata?
Well first off, though you can set frameLevel in your <Frame> tag, frameLevel is dictated by XML nesting. Check this example out:
<Frame name="MyFrame" frameStrata="DIALOG" parent="UIParent"> <Frames> <Button name="MyButton"/> </Frames> </Frame>
Since UIParent's frameLevel is 0 (verifiable with "/dump UIParent:GetFrameLevel()"), the frame we created here should be frameLevel 1 and the Button should be frameLevel 2.
You can check a frame's level with Frame:GetFrameLevel() and you can set it with Frame:SetFrameLevel(). However, setting a frame's level is ill-advised. It is given its level automatically and it's best to leave it that way. If you need to change a frame's level in your own code, best thing to do is just nest your code differently.
Note: If the parent of a frame is changed by your code (via "someFrame:SetParent(newParent)"), the frame levels are automatically adjusted to the new parent's frame level plus 1. So if you change the parent to UIParent (which has level 0), your frame would get level 1. Or if you change the parent to something with level 3, your frame would get level 4, and so on...
- Possible Values
- 0 - No parent (UIParent uses this level)
- 1 - Parent is most likely UIParent, but may be different if some code has manually forced a frame's level to 1.
- 2 and higher for deeper frames...
The maximum value seems to be 129. If you call SetFrameLevel with a value greater than 129, the value passed will be ignored, and the frame level will be set to 129.
In my experimentation, and with my WoW client (Windows), it seems higher values will stick, and be honored, if you call SetFrameLevel twice in a row. This is probably unreliable. If you find that you are having to set frame levels greater than 129, see if you can use a hierarchical set of parent frames instead.
A more complete explanation of how frame levels are used is found at How the user interface is rendered.
FrameLevels in 7.0 and beyond
Taken from an IRC conversation on July 20, 2016:
With 7.0.3, frame levels will no longer change automatically. Frame levels used to "compress" which caused all sorts of weird behavior, like just the ordering of creating child frames could adjust your frame levels differently. Frame levels will now always stay what you set them to, and always sort correctly using that frame level. The new range on frame levels is 0-10000.
There's a couple things that override frame levels, primarily useParentLevel and topLevel. If you have two frames at the same strata and frame level, both marked as topLevel, the last frame that Raise() was called on will still be higher. Clicking on a toplevel frame will implicitly call Raise, as will showing it from a hidden state.