※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。


This is how our AddOn looks, right now. Over the course of this page, you will add the clock text to it and make it draggable to any location on the screen. Currently, it sits quietly at the center of your screen.


4. Layerと時間用のFontString(文字)追加


In order to display numbers on your pretty new Frame, we need to put a FontString on it. We put elements like FontStrings and Textures on different Layers to control what is before what, obviously. Since there will be nothing but our FontString on this clock as of now, we will just use the layer level BACKGROUND (other possible levels include OVERLAY, BORDER and ARTWORK). This is how the whole <Layers> Tag looks for us:

<Layers>
<Layer level="BACKGROUND">
<FontString name="ClockText" inherits="GameFontNormal">
<Size>
<AbsDimension x="128" y="12"/>
</Size>
<Anchors>
<Anchor point="TOP">
<Offset>
<AbsDimension x="0" y="-10"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>

As you can see, we have <Layers> followed by one <Layer>, which contains the <FontString> Tag. I will not explain basic XML here, so let me just explain what the attributes and tags within the <FontString> tag mean.

name:
Oh come on, I'm not gonna explain this again ;)

inherits:
This <FontString> inherits all attributes and settings of the "GameFontNormal" <FontString> that you can find in the Fonts.xml file within the FrameXML folder of the original Blizzard UI. It only defines the font, size and color of the text. In our case this is the typical yellow/orange/whatever (Sorry, I'm red/green blind ;p).

As for the tags inside, what the <Size> and <Anchors> do should be known by now, but what's <Offset>? The <Offset> (and accompanying <AbsDimension> inside) defines how far away from the Anchor point the element should be. Not putting this in, would position the Text right at the top of our Frame - since we want it inside the frame, we move it 10 units down. We could also Anchor it at the BOTTOM of the Frame, moving it slightly upwards, or LEFT.. this is up to your preference.

Let's give this nice FontString a function, by letting it display the time!

5. 時間の追加と更新 - LUAへ引き継ぐ


While we could just write random code into the .lua file, which would be executed on load, this is not what we want. We want to execute LUA Script on certain events, namely: On Load, On Update and for the purpose of dragging: On Drag Start, On Drag Stop and On Mouse Up, which is also an indicator that the user has stopped dragging the window.

We can define code, a function to call from any .lua file we have included via the <Script> Tag or even a function from other AddOns that we defined in the "## Dependencies:" line in the .toc file (more on that in a different HOWTO) to be executed on a range of events within the XML, and within any Frame.

In the case of our clock here, we will define one single function to be executed on these events: OnLoad, OnUpdate, OnDragStart, OnDragStop and OnMouseUp. We do this via the <Scripts> Tag that goes between the <Frame> Tag just like the Anchors, Backdrop and Size. Our example, looks like this:

<Scripts>
<OnLoad>
Clock_OnLoad();
</OnLoad>
<OnUpdate>
Clock_OnUpdate(arg1);
</OnUpdate>
<OnDragStart>
Clock_OnDragStart();
</OnDragStart>
<OnDragStop>
Clock_OnDragStop();
</OnDragStop>
<OnMouseUp>
Clock_OnDragStop();
</OnMouseUp>
</Scripts>

I think this is pretty self-explanatory, every Tag inside the <Scripts> Tag represents the respective event, text inside it has to be LUA - which is going to be executed upon the event happening.

This means, whenever a user Clicks with his mouse on your Frame and then releases his Mousekey, the OnMouseUp event will happen and the function "Clock_OnDragStop();" will be executed. Some of these events also have arguments that are available to the LUA code within, as you can see on the OnUpdate. Arguments available range from arg1 to argXX, arg1 on the OnUpdate event will be the time since the last update has happened.

Let's go on though, and define the functions that we have bound to be executed here.

6. The Real Deal: LUA関数を書く


If you are new to LUA, or to programming entirely, I recommend that you first read through some simple LUA HowTos that are easily found around the Net. Lua-users.org has a whole Directory of Tutorials on their Wiki that should be read from top to bottom, increasing complexity as you progress. If you want to dive in right now, I will give short tips on what we do here, but I won't explain all of what LUA can do.

First in line is the OnLoad event, which will call the Clock_OnLoad() function. This is how the function looks:

function Clock_OnLoad()
this:RegisterForDrag("LeftButton");
ClockFrame.TimeSinceLastUpdate = 0;
end

Pretty short, pretty easy. The only thing it does, is registering our frame for dragging - via the left mouse button, and initializes the variable TimeSinceLastUpdate to zero.

Notice how we use "this" on RegisterForDrag and "ClockFrame" for the TimeSinceLastUpdate variable. This is the exact same thing, "this" translates to "ClockFrame" in our example, it represents the Frame it is called in. You could also use "ClockFrame:RegisterForDrag" here. Using "this" is recommended, because you won't have to change the code when you change the "name" attribute of your Frame.

The TimeSinceLastUpdate variable is stored within your Clock Frame.

Also, as you can see, the general syntax for defining functions in LUA is "function [Function Name](<List of Arguments seperated by comma, or "..." for any number of arguments>) [Function Code] end".

Let's go on with the slightly more complex OnUpdate event, calling the Clock_OnUpdate() function with "arg1" as argument. arg1 is a variable, variables in LUA are not prepended by a "$" like in PHP or in the WoW XML, they are just plain alphanumeric strings.

This is how our Clock_OnUpdate() looks:

function Clock_OnUpdate(arg1)
ClockFrame.TimeSinceLastUpdate = ClockFrame.TimeSinceLastUpdate + arg1;
if( ClockFrame.TimeSinceLastUpdate > CLOCK_UPDATE_RATE ) then
local hour, minute = GetGameTime();
local TimeString = format(TEXT(TIME_TWENTYFOURHOURS), hour, minute);
ClockText:SetText(TimeString);
ClockFrame.TimeSinceLastUpdate = 0;
end
end

The only thing this does, even though it might look more complicated than that, is that it increases the TimeSinceLastUpdate variable with the time since the last update has happened and if this number reaches an amount higher than what we have defined in the global CLOCK_UPDATE_RATE variable - it takes the current time, and writes it onto the clock! It also zeroes the TimeSinceLastUpdate to start over the cycle.

Speaking of which, we have to define the CLOCK_UPDATE_RATE variable to be globally available in our script, we do this at the very top of the LUA file, adding this:

CLOCK_UPDATE_RATE = 0.1;

Now for the last thing to do: making the Frame draggable.

In order to initiate or stop the dragging, we only need to call one function for each event. Here is how our two functions look that we have defined for the OnDragStart, OnDragStop and OnMouseUp events:

function Clock_OnDragStart()
ClockFrame:StartMoving()
end

function Clock_OnDragStop()
ClockFrame:StopMovingOrSizing()
end

I don't think these need any explanation, they simply call "StartMoving()" on the ClockFrame when the user has pressed his left mouse button on the Frame and started moving his mouse and "StopMovingOrSizing()" when the user lifts his mouse button. These two functions simply hook the Frame to the mouse cursor and it magically begins to move!

7.完成!


Save your files, and look at it! You're done now, and should have gathered enough new information in order to start producing some hopefully nice addons for the community :)

This is how your final Window should look, it should be draggable and should display the time in it:



Since you haven't been here to learn how to make a clock, you should of course play around with it at will. Don't be afraid do break anything - you can't. The only thing that might happen is that World of Warcraft spews an error at you. If you use wrong textures, it might happen that WoW crashes away, but that's not bad either. AddOns will never delete your characters or make your computer explode.

A few things you could play with:

Textures:
Extract the Blizzard UI, like described in my Interface Modification Beginners Guide. Then use BLP2TGA or the BLP2Viewer to go through the textures available and see if you find cool borders or backgrounds for any Frames you might create in the future.

If you want to convert all textures to TGA, you could use a batch script together with BLP2TGA, throw it in one directory with all of the .blp files and keep pressing enter a thousand times (that is how I did it, hehe).

For your convenience, here's a zip with a batch script and BLP2TGA that does it: BLP2TGA and Batch. Simply run it like "convert.bat *" in the directory you have all the .blps in, and keep pressing your enter key. BLP2TGA might crash on some of the images, so you'll also have to deal with that from time to time.

Resizing:
Since we've used a Backdrop, you could make the Frame resizable too. Try to find out how :)

AM/PM Time:
If you look at Telo's Code, he has used a function to convert the 24h time that GetGameTime() gives you to AM/PM times - try to adapt/rewrite his function for some basic LUA training. It's rather simple, even without looking at his code, so try to do it on your own! Other examples of how to do this can be found in the GameTime.lua that also resides within the FrameXML directory of the Standard Interface.

That is it for now, watch out for a few other HowTos I'm going to write in the coming days!

If you have any questions, feel free to register and comment or mail me at fyrn_AT_mmhell.com.

Download the Source of this Howto here: hellClock.zip.


  
添付ファイル