创建 WoW 插件 - 第 10 部分:创建设置界面

Part 10: Developing a Separate Interface for Settings
第 10 部分:为设置开发单独的界面

Difficulty: ?? Medium  难度: ?? 中等

This isn't terribly difficult, but we will be implementing some things into this tutorial that aren't 100% necessary just to re-cover some things, like .toc file updating, creating a new file, etc. Let's do it!
这并不是很困难,但我们将在本教程中实现一些并非 100% 必要的内容,只是为了重新涵盖某些内容,例如 .toc 文件更新、创建新文件等。让我们开始吧!

First, take a breath if you haven't yet. This is a lot to take in. Especially Part 8 and 9. Once you're ready, we can move on!
首先,如果你还没有,请深呼吸。这需要接受很多东西。尤其是第 8 部分和第 9 部分。一旦您准备好了,我们就可以继续了!


Step 1: Creating Another File
第 1 步:创建另一个文件

To start, we will be creating a new file for all of our settings code to live in. This is not necessary, but will keep things cleaner and more organized for you in the future.
首先,我们将为所有设置代码创建一个新文件。这不是必需的,但将来会让您的生活更整洁、更有条理。

To start, let's create a new file in your addon folder called Settings.lua. Remember, this should be in the same folder as your main addon file, which is probably named MyAddon.lua.
首先,让我们在你的插件文件夹中创建一个名为 Settings.lua 的新文件。请记住,这应该与你的主插件文件位于同一文件夹中,该文件可能名为 MyAddon.lua

Now, in your .toc file, make sure to add Settings.lua to the bottom of the file, right under your first .lua file.
现在,在您的 .toc 文件中,确保将 Settings.lua 添加到文件底部,在您的第一个 .lua 文件正下方。

After you've added the new file to your .toc file, let's re-open Settings.lua and make our settings frame!
将新文件添加到 .toc 文件后,让我们重新打开 Settings.lua 并创建设置框架!


Step 2: Creating a Settings Frame
第 2 步:创建设置框架

First, we'll start again by making a new frame. We can call this frame settingsFrame and it should be a local variable.
首先,我们将重新开始制作一个新框架。我们可以将这个帧称为 settingsFrame,它应该是一个局部变量。

local settingsFrame = CreateFrame("Frame", "MyAddonSettingsFrame", UIParent, "BasicFrameTemplateWithInset")
settingsFrame:SetSize(400, 300)
settingsFrame:SetPoint("CENTER")
settingsFrame.TitleBg:SetHeight(30)
settingsFrame.title = settingsFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
settingsFrame.title:SetPoint("CENTER", settingsFrame.TitleBg, "CENTER", 0, -3)
settingsFrame.title:SetText("MyAddon Settings")
settingsFrame:Hide()
settingsFrame:EnableMouse(true)
settingsFrame:SetMovable(true)
settingsFrame:RegisterForDrag("LeftButton")
settingsFrame:SetScript("OnDragStart", function(self)
	self:StartMoving()
end)

settingsFrame:SetScript("OnDragStop", function(self)
	self:StopMovingOrSizing()
end)

The above code creates a settings frame and a title for the frame. Once again, this frame will come with a close button. The frame will also be moveable!
上面的代码创建了一个 settings 框架和框架的标题。再一次,这个框架将带有一个关闭按钮。框架也将是可移动的!

By default, this frame will be hidden. It will only show when we press a button to show it. This is also going to be the file we create our minimap button in.
默认情况下,此帧将被隐藏。只有当我们按下按钮来显示它时,它才会显示出来。这也将成为我们在其中创建小地图按钮的文件。

Once you have your settings frame created, save your file and log in or /reload your game. You shouldn't see anything show up, but feel free to remove the settingsFrame:Hide() line or add a slash command yourself to view the settings frame.
创建设置帧后,保存文件并登录或 /reload 游戏。您应该不会看到任何内容显示,但请随意删除 settingsFrame:Hide() 行或自己添加斜杠命令来查看设置框架。


Step 3: Creating Our Checkboxes
第 3 步:创建我们的复选框

If all is good in settingsFrame land, let's move on to create two settings!
如果 settingsFrame land 一切正常,让我们继续创建两个设置!

These settings are going to be Checkbox settings. If the checkbox is checked they equal true. If it is unchecked it equals false.
这些设置将是 Checkbox 设置。如果选中该复选框,则它们等于 true如果未选中,则等于 false

For this, we are actually going to be making a new function to create our checkboxes dynamically from a table. But first, we'll need a table to hold all of our settings.
为此,我们实际上将创建一个新函数来从表中动态创建我们的复选框。但首先,我们需要一个表格来保存我们的所有设置。

In your Settings.lua file, at the very top, create a table called settings. We're making it local to the addon.
在 Settings.lua 文件的最顶部,创建一个名为 settings 的表。我们正在将其设为插件的本地。

local settings = {}

This is how a table looks in Lua. Tables are defined by using {}'s. Currently, it is a blank table. Let's add a setting to it. Change settings to this:
这是 Lua 中表格的样子。表是使用 {} 定义的。目前,它是一个空白表。让我们为其添加一个设置。将设置更改为以下内容:

local settings = {
    {
        settingText = "Enable tracking of Kills",
        settingKey = "enableKillTracking",
        settingTooltip = "While enabled, your kills will be tracked.",
    },
}

Once again we have {} that defines a table, and inside of those we have another set of {}'s. This means we have nested another table inside of our original table.
我们再次有了定义一个表的 {},在这些表里面我们有另一组 {}。这意味着我们在原始表内嵌套了另一个表。

Let's make a second one so you can see how this table keeps expanding as we add to it.
让我们创建第二个 URL,以便您可以看到此表如何随着我们的添加而不断扩展。

local settings = {
    {
        settingText = "Enable tracking of Kills",
        settingKey = "enableKillTracking",
        settingTooltip = "While enabled, your kills will be tracked.",
    },
    {
        settingText = "Enable tracking of Currency",
        settingKey = "enableCurrencyTracking",
        settingTooltip = "While enabled, your currency gained will be tracked.",
    },
}

Hopefully, with the above code laid out, you can see a pattern in how these tables are formed. Now, we'll need to make a function that will loop over these settings, set their default value, create a checkbox and lay them out on the settings frame accordingly.
希望通过上面的代码,您可以看到这些表的形成方式的模式。现在,我们需要创建一个函数来循环这些设置,设置它们的默认值,创建一个复选框并相应地将它们布置在设置框架上。

To handle the display of these settings, let's create a variable above this table called checkboxes and we'll also make this local. Give it an initial value of 0.
为了处理这些设置的显示,让我们在此表上方创建一个名为 checkboxes 的变量,我们还将其设为本地变量。为其指定初始值 0

local checkboxes = 0

Step 4: Creating Our Checkbox Creation Function
第 4 步:创建我们的复选框创建函数

Let's start our local function and name it CreateCheckbox. We're also going to give it a few arguments.
让我们启动本地函数并将其命名为 CreateCheckbox。我们还将给它一些论点。

  • checkboxText  复选框文本

  • key  钥匙

  • checkboxTooltip  checkbox工具提示

local function CreateCheckbox(checkboxText, key, checkboxTooltip)
    -- Code to go here soon...
end

Inside of this function, we need to create the Checkbox frame, put text to the right of it, make it interactable and place it correctly onto the settings frame.
在这个函数中,我们需要创建 Checkbox 框架,将文本放在它的右侧,使其可交互并将其正确放置在设置框架上。

This function will also be our method of giving a default value to our settings. In our case, the default value will be true (checked).
此函数也将是我们为设置提供默认值的方法。在本例中,默认值将为 true(选中)。

Let's do this now.  现在让我们开始吧。

local function CreateCheckbox(checkboxText, key, checkboxTooltip)
    local checkbox = CreateFrame("CheckButton", "MyAddonCheckboxID" .. checkboxes, settingsFrame, "UICheckButtonTemplate")
    checkbox.Text:SetText(checkboxText)
    checkbox:SetPoint("TOPLEFT", settingsFrame, "TOPLEFT", 10, -30 + (checkboxes * -30))
end

The above code is a simple function that creates a new Checkbox anytime it is called. It will position it correctly on the settings frame as well.
上面的代码是一个简单的函数,每当调用它时都会创建一个新的Checkbox。它也会将其正确放置在设置框架上。

In our CreateCheckbox function, we're going to make sure our Checkbox equals the state of the database key when it's created. If the setting is true (checked), we want the Checkbox to be checked as well.
在我们的 CreateCheckbox 函数中,我们将确保 Checkbox 等于创建数据库键时的状态。如果设置为 true (选中),则我们也希望选中 Checkbox

We will do that by adding this into our CreateCheckbox function.
我们将通过将其添加到 CreateCheckbox 函数中来实现此目的。

if MyAddonDB.settingsKeys[key] == nil then
    MyAddonDB.settingsKeys[key] = true
end

checkbox:SetChecked(MyAddonDB.settingsKeys[key])

Above, we check for the key in our settingsKeys table of MyAddonDB to see if it's nil. If it is, we will set it to the default value of true. If it is not nil, we will leave it alone.
在上面,我们检查 MyAddonDB 的 settingsKeys 表中的键,看看它是否为 nil。如果是,我们会将其设置为默认值 true。如果它不是 nil,我们将不理会它。

We don't want to login to the game just yet, because we still have to create the event that will set MyAddonDB.settingsKeys to nil or empty before we use it.
我们现在还不想登录游戏,因为我们仍然必须创建一个事件,该事件在使用它之前将 MyAddonDB.settingsKeys 设置为 nil 或

Next, we're going to add our checkbox functionality and tooltip text that tells the player what exactly the setting does!
接下来,我们将添加复选框功能和工具提示文本,告诉玩家设置的具体用途!

We'll also be increasing the checkboxes variable we put at the top of the file by 1. Add the below code to your CreateCheckbox function.
我们还会将放在文件顶部的 checkboxes 变量增加 1。将以下代码添加到您的 CreateCheckbox 函数中。

checkbox:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText(checkboxTooltip, nil, nil, nil, nil, true)
end)

checkbox:SetScript("OnLeave", function(self)
    GameTooltip:Hide()
end)

checkbox:SetScript("OnClick", function(self)
    MyAddonDB.settingsKeys[key] = self:GetChecked()
end)

checkboxes = checkboxes + 1

return checkbox

Step 5: Code Review 第 5 步:代码审查

Now that we've gotten this far, our entire Settings.lua file should be as such:
现在我们已经走到了这一步,我们的整个 Settings.lua 文件应该是这样的:

local checkboxes = 0

local settings = {
    {
        settingText = "Enable tracking of Kills",
        settingKey = "enableKillTracking",
        settingTooltip = "While enabled, your kills will be tracked.",
    },
    {
        settingText = "Enable tracking of Currency",
        settingKey = "enableCurrencyTracking",
        settingTooltip = "While enabled, your currency gained will be tracked.",
    },
}

local settingsFrame = CreateFrame("Frame", "MyAddonSettingsFrame", UIParent, "BasicFrameTemplateWithInset")
settingsFrame:SetSize(400, 300)
settingsFrame:SetPoint("CENTER")
settingsFrame.TitleBg:SetHeight(30)
settingsFrame.title = settingsFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
settingsFrame.title:SetPoint("TOP", settingsFrame.TitleBg, "TOP", 0, -3)
settingsFrame.title:SetText("MyAddon Settings")
settingsFrame:EnableMouse(true)
settingsFrame:SetMovable(true)
settingsFrame:RegisterForDrag("LeftButton")
settingsFrame:SetScript("OnDragStart", function(self)
	self:StartMoving()
end)

settingsFrame:SetScript("OnDragStop", function(self)
	self:StopMovingOrSizing()
end)

local function CreateCheckbox(checkboxText, key, checkboxTooltip)
    local checkbox = CreateFrame("CheckButton", "MyAddonCheckboxID" .. checkboxes, settingsFrame, "UICheckButtonTemplate")
    checkbox.Text:SetText(checkboxText)
    checkbox:SetPoint("TOPLEFT", settingsFrame, "TOPLEFT", 10, -30 + (checkboxes * -30))

    if MyAddonDB.settingsKeys[key] == nil then
        MyAddonDB.settingsKeys[key] = true
    end

    checkbox:SetChecked(MyAddonDB.settingsKeys[key])

    checkbox:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(checkboxTooltip, nil, nil, nil, nil, true)
    end)

    checkbox:SetScript("OnLeave", function(self)
        GameTooltip:Hide()
    end)

    checkbox:SetScript("OnClick", function(self)
        MyAddonDB.settingsKeys[key] = self:GetChecked()
    end)

    checkboxes = checkboxes + 1

    return checkbox
end

We're not quite done yet, and we won't yet notice any difference when pulling up our settings frame, if you can get to it without an error that is.

Next, we need to tell our addon to loop through and create these settings when the player logs in based on the entries we have in our settings table. We also need to define our settingsKeys table as blank so we can use it.
接下来,我们需要告诉我们的插件在播放器登录时循环访问并根据我们在设置表中的条目创建这些设置。我们还需要将 settingsKeys 表定义为空白,以便我们可以使用它。