Построение редактора графического пользовательского интерфейса в C#

В этой статье я покажу, как построить простой "редактор графического пользовательского интерфейса". Для начала давайте обсудим, что означает "редактор графического пользовательского интерфейса".

Редактор графического пользовательского интерфейса

"Редактор графического пользовательского интерфейса" или "построитель графического пользовательского интерфейса" — это средство разработки программного обеспечения. Он имеет разновидность структуры WYSIWYG и помогает пользователям построить структуру без кодирования или с минимальным кодированием. Без графического пользовательского интерфейса нам пришлось бы писать код для всего.

Давайте приступим...

ПОШАГОВОЕ ПОСТРОЕНИЕ РЕДАКТОРА ГРАФИЧЕСКОГО ПОЛЬЗОВАТЕЛЬСКОГО ИНТЕРФЕЙСА

Сначала создадим новый игровой проект XNA 3.1.

Он находится здесь.

Теперь поговорим обо всем, что мы собираемся делать.

  1. Добавить файл ресурсов, включающий изображения обложек для элементов управления.
  2. Создать структуру, которая поможет экспортировать список элементов управления в виде XML-файла.
  3. Создать папку "Screens", которая поможет читать эти элементы управления.
  4. Для обмена данными Windows и XNA создать класс, в котором будут объявлены "общедоступные статические" переменные.
  5. Создать "панель свойств", где можно будет изменять свойства выбранных элементов управления.
  6. Создать "панель элементов", где можно будет добавлять элементы управления.
  7. Создать наши настраиваемые элементы управления.

1. Добавление файла ресурсов, включающего изображения обложек для элементов управления

Мы добавляем 3-4 изображения обложек для нашего элемента управления "Кнопка".

Прежде всего создаем файл ресурсов, который поможет нам хранить обложки:

Теперь откроем файл ресурсов и последовательно выберем в меню пункты "Add Resource (Добавить ресурс)->Add Existing File... (Добавить существующий файл...)"

Затем добавим 4 демонстрационные обложки (можно создать собственные обложки с названиями "disabled", "down", "over" и "up"):

Здесь они добавляются в ресурсы.

2. Структура, которая поможет экспортировать список элементов управления в виде XML-файла

Сначала создадим новый XML-файл:

Теперь включим в него код, аналогичный приведенному ниже:

<?xml version="1.0" encoding="utf-8" ?>
<GUI>
  <Control Name="">
    <Type></Type>
    <AllowDrop></AllowDrop>
    <Enabled></Enabled>
    <ForeColor></ForeColor>
    <LocationX></LocationX>
    <LocationY></LocationY>
    <SizeW></SizeW>
    <SizeH></SizeH>
    <Text></Text>
  </Control>
</GUI>

Мы получаем преимущества XML для структуры, которую мы построим в редакторе графического пользовательского интерфейса, и как можно видеть, мы добавили элементы, поскольку они уже являются свойствами элементов управления. Фактически будет большой ошибкой не использовать XML в таком виде приложений.

3. Папка "Screens", которая поможет читать эти элементы управления

Просто создайте новую папку в проекте и назовите ее Screens.

4. Создание класса, в котором будут объявлены "общедоступные статические" переменные, для обмена данными Windows и XNA

Создайте новый класс и назовите его Infos.cs.

Он может выглядеть следующим образом:

В этой точке мы не создаем никакой код.

5. "Панель свойств", где можно изменять свойства выбранных элементов управления

Нам необходимо добавить панель свойств. Сначала нужно создать форму Windows Forms:

Затем следует установить свойства, как показано ниже.

Backcolor =White
Size
Width=219
Height=600
Text=Properties Panel

Создадим новую папку и пользовательский элемент управления с именем Control_Properties.

Установим его свойства, как показано ниже:

BackColor = White
Size
Width=175
Height=400

Он должен выглядеть, как показано выше. Теперь добавим элемент управления "Таймер" в пользовательский элемент управления.

Установим для приведенных выше элементов управления следующие свойства:

// label1
            Text = "Name";
            // textBox1
            Name = "textBox1";
            // Label2
            Name = "Label2";
            Text = "AllowDrop";
            // comboBox1
            Items = "True","False"
            Name = "comboBox1";           
            // label3
            Name = "label3";
            Text = "Enabled";
            // comboBox2
            Items = "True","False"
            Name = "comboBox2";
            // label4
            Name = "label4";
            Text = "ForeColor";
            // comboBox3
            Name = "comboBox3";
            // label5
            Name = "label5";
            Text = "LocationX";
            // textBox2
            Name = "textBox2";
            // label6
            Name = "label6";
            Text = "LocationY";
            // textBox3
            Name = "textBox3";
            // label7
            Name = "label7";
            Text = "SizeW";
            // textBox4
            Name = "textBox4";
            // label8
            Name = "label8";
            Text = "SizeH";
            // textBox5
            Name = "textBox5";
            // textBox6
            Name = "textBox6";
            // label9
            Name = "label9";
            Text = "Text";
            // timer1
            Interval = 2;

Добавим GroupBox и установим его свойство Text в значение "Properties".

Добавим этот пользовательский элемент управления в ранее построенную форму Windows Forms "Properties_Panel".

Теперь форма Properties_Panel должна выглядеть следующим образом:

6. "Панель элементов", где можно добавлять элементы управления

Теперь следует создать форму Windows Forms для "панели элементов" и добавить изображения, которые будут использоваться в этой панели элементов.

Добавьте новую форму и назовите ее Toolbox.cs.

Установите свойства, как показано ниже:

BackColor= White
Size
Width=190
Height=562

Добавьте элемент управления GroupBox, а затем установите его свойство Text в значение "Toolbox" и свойство Dock в значение "Fill".

Теперь добавьте изображения элементов управления, которые будут использоваться в панели элементов:

последовательно выберите в меню пункты "Add Resource (Добавить ресурс)->Add Existing Item (Добавить существующий элемент)";

таким образом изображения элементов управления будут добавлены.

Добавьте 9 элементов управления PictureBox и назначьте им изображения, которые только что были добавлены в ресурс. Получится следующий вид:

7. Наши настраиваемые элементы управления

Теперь создадим наши собственные элементы управления, перечисленные ниже:

XButton
XCheckBox
XComboBox
XLabel
XListBox
XPictureBox
XProgressBar
XRadioButton
XTextBox

Создайте новый класс и назовите его XButton.cs.

Обновите этот класс следующим образом:

XButton

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace GuiEditor
{
    class XButton:Button
    {
        public XButton()
        {
        }
    }
}

Аналогичным образом создайте классы для остальных элементов управления.

Теперь давайте обсудим наш класс INFOS.

В этом классе хранятся все сведения, необходимые для взаимодействия между XNA и Windows Forms (окно свойств и панель элементов).

Отлично, давайте взглянем на код и попробуем его объяснить:

public static Control kontrool;

Эта статическая управляющая переменная является выбранным элементом управления в окне XNA. При выборе элемента управления эта переменная будет хранить его имя.

public static List<Control> kontroller = new List<Control>();

Эта переменная хранит все элементы управления (повторяющиеся) в окне XNA.

public static List<Control> strunq = new List<Control>();

Эта переменная хранит все элементы управления (уникальные) в окне XNA.

public static Control selectedcontrol;

Эта статическая управляющая переменная является выбранным элементом управления в окне XNA. При выборе элемента управления эта переменная будет хранить его имя.

public static bool xmlbuild;

В случае значения true мы будем создавать XML-файл.

//Button Variables
        public static bool varpub;    
        public static int a;
        public static bool close;       
        public static bool atleastone;

Переменная "varpub" контролирует, добавляется ли заданный элемент управления или нет. Переменная "a" прибавляет 1 к свойствам name и text элемента управления. Переменная "close" предотвращает повторное добавление указанного элемента управления. Можно рассматривать ее как блокировку. Переменная "atleastonce" контролирует, чтобы указанный элемент управления был добавлен хотя бы один раз.

//Button Events
        public void Button_Added(bool varb)
        {
           varpub = varb;
           close = true;          
           ButtonAdd_Num();        
        }     
        public int ButtonAdd_Num()
        {
            a++;
            return a;
        }

Функция Button_Added — это ключ, который управляет тем, где кнопка добавляется в игровое окно. ButtonAdd_Num помогает увеличить переменную "a".

public static void CreateUniqueList(List<Control> oDup, ref List<Control> oUniq)
        {
            for (int x = 0; x < oDup.Count; x++)
            {
                bool bDuplicate = false;
                foreach (object oItem in oUniq)
                {
                    if (oItem == oDup[x])
                    {
                        bDuplicate = true;
                        oDup.RemoveAt(x);
                        break;
                    }
                }
                if (!bDuplicate)
                {
                    oUniq.Add(oDup[x]);
                }
            }
        }

Эта функция принимает все повторяющиеся элементы управления и делает их уникальными в списке элементов управления strunq по ссылке.

Ее можно вызвать следующим образом: CreateUniqueList(Infos.kontroller,ref Infos.strunq);

public static void XMLBuild()
{
    FileStream fs = new FileStream("controls.xml", FileMode.Create);
    XmlWriter w = XmlWriter.Create(fs);
    w.WriteStartDocument();
    w.WriteStartElement("GUI");
    foreach (Control v in Infos.strunq)
    {
        w.WriteStartElement("Control");
        w.WriteAttributeString("Name", v.Name);
        w.WriteElementString("Type", v.GetType().ToString());
        w.WriteElementString("AllowDrop", v.AllowDrop.ToString());
        w.WriteElementString("Enabled", v.Enabled.ToString());
        w.WriteElementString("ForeColor", v.ForeColor.ToKnownColor().ToString());
        w.WriteElementString("LocationX", v.Location.X.ToString());
        w.WriteElementString("LocationY", v.Location.Y.ToString());
        w.WriteElementString("SizeW", v.Size.Width.ToString());
        w.WriteElementString("SizeH", v.Size.Height.ToString());
        w.WriteElementString("Text", v.Text);
        w.WriteEndElement();
    }
    w.WriteEndElement();
    w.WriteEndDocument();
    w.Flush();
    fs.Close();
}

В этой функции создания XML мы запрашиваем все уникальные элементы управления в strunq и записываем их в XML-файл.

Структура элементов управления

Давайте обсудим структуру кода элементов управления и попробуем объяснить ее.

Как уже говорилось выше, мы создали 9 элементов управления, начинающихся с "X". Теперь мы приступим к поэтапному объяснению кода элементов управления XButton.

private Boolean dragInProgress = false;
int MouseDownX = 0;
int MouseDownY = 0;

Переменная "dragInProgress" дает нам значение, указывающее, продолжается ли процесс Drag.

Переменные "MouseDownX" и "MouseDownY" хранят координаты X и Y выбранного элемента управления.

public XButton()
{
    this.BackgroundImage = Resource1.Button_overSkin;
    this.FlatStyle = FlatStyle.Flat;
    this.BackColor = Color.CornflowerBlue;
    this.FlatAppearance.BorderColor = Color.CornflowerBlue;
    this.FlatAppearance.BorderSize = 0;
    this.FlatAppearance.CheckedBackColor = Color.CornflowerBlue;
    this.FlatAppearance.MouseDownBackColor = Color.CornflowerBlue;
    this.FlatAppearance.MouseOverBackColor = Color.CornflowerBlue;
    this.BackgroundImageLayout = ImageLayout.Stretch;
    this.MouseDown += new MouseEventHandler(MDown);
    this.MouseUp += new MouseEventHandler(MUp);
    this.MouseMove += new MouseEventHandler(MMove);
    this.Click += new EventHandler(BClick);
    this.MouseEnter += new EventHandler(MEnter);
    this.MouseLeave += new EventHandler(MLeave);
}

Когда мы создавали новый элемент управления XButton, это свойство имело значение по умолчанию.

protected override bool ShowFocusCues
{
    get
    {
        return false;
    }
}

Это логическое свойство по умолчанию предназначено только для чтения, но мы его переопределяем. При выборе элемента управления автоматически рисуется прямоугольник со строками. Чтобы предотвратить это, мы устанавливаем это свойство в значение false.

private void MUp(Object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        this.dragInProgress = false;
        this.BackgroundImage = Resource1.Button_downSkin;              
    }
    else if (e.Button == MouseButtons.Right)
    {               
        Infos.kontroller.Clear();
        foreach (Control c in Infos.strunq)
        {
            Infos.kontroller.Add(c);
        }
        Infos.strunq.Remove(Infos.secilikontrol);
        this.Dispose(true);               
    }          
    return;
}

Эта функция обрабатывает наше положение в элементе управления.

if (e.Button == MouseButtons.Left)
{
    this.dragInProgress = false;
    this.BackgroundImage = Resource1.Button_downSkin;              
}

Если мы щелкаем левой кнопкой мыши, то функция меняет фон, и поскольку процесс перетаскивания отсутствует, устанавливает для dragInProgress значение false.

else if (e.Button == MouseButtons.Right)
{
 Infos.kontroller.Clear();
 foreach (Control c in Infos.strunq)
 {
 Infos.kontroller.Add(c);
 }
 Infos.strunq.Remove(Infos.selectedcontrol);
 this.Dispose(true); 
}

Если мы, находясь в элементе управления, щелкнем его правой кнопкой мыши, то мы его удалим и перезагрузим список элементов управления.

private void MMove(Object sender, MouseEventArgs e)
{
    if (dragInProgress)
    {
        Point temp = new Point();
        temp.X = this.Location.X + (e.X - MouseDownX);
        temp.Y = this.Location.Y + (e.Y - MouseDownY);
        this.Location = temp;
        this.BackgroundImage = Resource1.Button_upSkin;
    }
    return;
}

Это функция, с помощью которой "перетаскивается" элемент управления.

private void MEnter(Object sender, EventArgs e)
{
    this.BackgroundImage = Resource1.Button_upSkin;
}
private void MLeave(Object sender, EventArgs e)
{
    this.BackgroundImage = Resource1.Button_overSkin;
}

Эти функции изменяют обложку элемента управления "Кнопка", когда текущая обложка исчезает в данном элементе управления.

Структура пользовательских элементов управления

Теперь давайте обсудим пользовательский элемент управления Control_Properties:

string[] colorNames = System.Enum.GetNames(typeof(KnownColor));

Мы извлекаем все системные цвета в строковый массив:

private void Control_Properties_Load(object sender, EventArgs e)
{           
    comboBox3.Items.AddRange(colorNames);
    timer1.Enabled = true;
}

Таким образом в поле со списком добавляются системные цвета, сохраненные в colorNames.

private void timer1_Tick(object sender, EventArgs e)
{
    if (Infos.kontrool == null)
    {
    }
    else
    {
        textBox1.Text = Infos.kontrool.Name;
        comboBox1.Text = Infos.kontrool.AllowDrop.ToString();
        comboBox2.Text = Infos.kontrool.Enabled.ToString();
        comboBox3.Text = Infos.kontrool.ForeColor.ToKnownColor().ToString();
        textBox2.Text = Infos.kontrool.Location.X.ToString();
        textBox3.Text = Infos.kontrool.Location.Y.ToString();
        textBox4.Text = Infos.kontrool.Size.Width.ToString();
        textBox5.Text = Infos.kontrool.Size.Height.ToString();
        textBox6.Text = Infos.kontrool.Text;                             
    }
}

Таймер проверяет, выбран ли элемент управления. Если элемент управления выбран, то он добавляется в управляющую переменную "kontrool".

private void textBox1_TextChanged(object sender, EventArgs e)
{
    Infos.kontrool.Name = textBox1.Text;
}

Это помогает нам изменить имя выбранного элемента управления.

private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
    if (comboBox1.SelectedIndex == 0)
    {
        Infos.kontrool.AllowDrop = true;
    }
    else
    {
        Infos.kontrool.AllowDrop = false;
    }          
}

Это помогает нам изменить свойство AllowDrop выбранного элемента управления.

private void comboBox2_SelectedValueChanged(object sender, EventArgs e)
{
    if (comboBox2.SelectedIndex == 0)
    {
        Infos.kontrool.Enabled  = true;
    }
    else
    {
        Infos.kontrool.Enabled = false;
    }
}

С помощью этого кода можно включать или отключать указанный элемент управления.

private void comboBox3_SelectedValueChanged(object sender, EventArgs e)
{
    if (comboBox3.Text == null)
    {
    }
    else
    {
        Infos.kontrool.ForeColor = Color.FromName(comboBox3.Text);
    }
}

В comboBox3 хранятся системные цвета, которые были добавлены выше. Можно изменить свойство ForeColor элемента управления, выбрав значение из comboBox3.

private void textBox2_TextChanged(object sender, EventArgs e)
{
    if (textBox2.Text == null)
    {
    }
    else
    {
        int xdeger = Infos.kontrool.Location.X;
        int ydeger = Infos.kontrool.Location.Y;             
        xdeger = Int32.Parse(textBox2.Text);
        Infos.kontrool.Location = new Point(xdeger, ydeger);
     }          
}

Этот код помогает изменить значение Location.X выбранного элемента управления.

private void textBox3_TextChanged(object sender, EventArgs e)
{
    if (textBox3.Text == null)
    {
    }
    else
    {
        int xdeger = Infos.kontrool.Location.X;
        int ydeger = Infos.kontrool.Location.Y;
        ydeger = Int32.Parse(textBox3.Text);
        Infos.kontrool.Location = new Point(xdeger, ydeger);
    }           
}

Этот код помогает изменить значение Location.Y выбранного элемента управления.

private void textBox4_TextChanged(object sender, EventArgs e)
{
   if (textBox4.Text == null)
   {
   }
   else
   {
       int wdeger = Infos.kontrool.Size.Width;
       int hdeger = Infos.kontrool.Size.Height;
       wdeger = Int32.Parse(textBox4.Text);
       Infos.kontrool.Size = new Size(wdeger, hdeger);
   }
}

Этот код помогает изменить значение Size.Width выбранного элемента управления.

private void textBox5_TextChanged(object sender, EventArgs e)
{
    if (textBox5.Text == null)
    {
    }
    else
    {
        int wdeger = Infos.kontrool.Size.Width;
        int hdeger = Infos.kontrool.Size.Height;
        hdeger = Int32.Parse(textBox5.Text);
        Infos.kontrool.Size = new Size(wdeger, hdeger);
    }
}

Этот код помогает изменить значение Size.Height выбранного элемента управления.

private void textBox6_TextChanged(object sender, EventArgs e)
{
    Infos.kontrool.Text = textBox6.Text;
}

Этот код помогает изменить значение Text выбранного элемента управления. Однако, как вам известно, в некоторых элементах управления отсутствует значение Text.

Теперь давайте обсудим панель свойств.

Панель свойств

private const int SC_CLOSE = 0xF060;
private const int MF_GRAYED = 0x1;
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
private static extern int EnableMenuItem(IntPtr hMenu, int wIDEnableItem, int wEnable);

Эти коды представляют вызовы API Win32. Они только отключают кнопку закрытия в форме.

private void Ozellikler_Load(object sender, EventArgs e)
{
    this.ShowInTaskbar = false;
    EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_GRAYED);
}

И мы выполняем эти вызовы, отключая кнопку закрытия.

private void Ozellikler_Resize(object sender, EventArgs e)
{
    this.Size = new Size(219, 600);
}

По умолчанию возможность изменения размера форм должна отсутствовать, поэтому мы предоставляем эти значения.

private void Ozellikler_Move(object sender, EventArgs e)
{
    this.DesktopLocation = new System.Drawing.Point(949, 109);
}

По умолчанию возможность перемещения форм должна отсутствовать, поэтому мы предоставляем эти значения.

private void button1_Click(object sender, EventArgs e)
{
    Infos.xmlbuild = true;
}

Мы отправляем логическое значение в класс Infos, где можно построить XML-файл.

Панель элементов

private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
    pictureBox1.BorderStyle = BorderStyle.None;
}

Мы изменяем BorderStyle, чтобы вид этого элемента соответствовал тому, что мы в нем не находимся.

private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
    pictureBox1.BorderStyle = BorderStyle.FixedSingle;
}

Мы изменяем BorderStyle, чтобы вид этого элемента соответствовал тому, что мы в нем находимся.

private void pictureBox1_Click(object sender, EventArgs e)
{
   Infos inf = new Infos();
   inf.Button_Added(true);
   Infos.close = false;
   Infos.atleastonce = true;
}

С помощью Button_Added мы добавляем в проект элемент управления "Кнопка".

GAME1.CS

Прежде всего мы добавляем ссылку на Windows.Forms в System.

using System.Windows.Forms;

Создание экземпляров форм Properties_Panel и Toolbox:

Properties_Panel pp = new Properties_Panel();
Toolbox tool = new Toolbox();

В конструкторе Game1:

graphics.PreferredBackBufferWidth = 600;  //Width  of XNA Window
graphics.PreferredBackBufferHeight = 600; //Height of XNA Window

Теперь добавляем заголовок окна XNA и включаем курсор мыши:

Window.Title = "Simple GUI Editor";
this.IsMouseVisible = true;

После этого мы устанавливаем нужные расположения окон XNA, панели свойств и панели элементов.

Control.FromHandle(Window.Handle).Location = new System.Drawing.Point(337, 86);

pp.Show();
pp.DesktopLocation = new System.Drawing.Point(949, 109);
tool.Show();
tool.DesktopLocation = new System.Drawing.Point(141, 109);

Создаем таймер, который поможет нам показывать элементы управления в форме и динамически изменять значения в Properties_Panel.

Timer tim = new Timer();
int oldvar;
Infos inf = new Infos();

В функции конструктора Game1():

tim.Enabled = true;

Включаем таймер, чтобы он немедленно начал работать.

Inside Initialize() function add;

//Timer Object
tim.Interval = 1;
tim.Tick += new EventHandler(tim_Tick);

Этот таймер имеет значение интервала 1 (очень быстрый), и добавление события таймера мы обсудим прямо сейчас.

private void tim_Tick(object sender, EventArgs e)
{
    //Adding XBUTTON
    if (Infos.varpub == true)
    {
        if (Infos.close == true)
        {
        }
        else if (Infos.close == false)
        {
            XButton btn = new XButton();
            btn.Name = "button" + Infos.a;
            btn.Text = "button" + Infos.a;
            btn.Location = new System.Drawing.Point(50, 50);
            Control.FromHandle(Window.Handle).Controls.Add(btn);
            Infos.strunq.Add(btn);
            Infos.close = true;
        }
    }
    foreach (Control v in Control.FromHandle(Window.Handle).Controls)
    {
        Infos.kontroller.Add(v);
        if (v.Focused)
        {
            Infos.selectedcontrol = v;
            Infos.kontrool = v;
        }
    }
    if (Infos.xmlbuild == true)
    {
       Infos.XMLBuild();
       Infos.xmlbuild = false;
    }           
}

Давайте обсудим то, что происходит после добавления элемента управления "Кнопка".

foreach (Control v in Control.FromHandle(Window.Handle).Controls)
{
     Infos.kontroller.Add(v);
     if (v.Focused)
    {
        Infos.selectedcontrol = v;
        Infos.kontrool = v;
    }
}
if (Infos.xmlbuild == true)
{
    Infos.XMLBuild();
    Infos.xmlbuild = false;
}

Мы динамически запрашиваем, добавлен ли какой-либо элемент управления, и если добавлен, то активен ли он.

Также, если нажимается кнопка сохранения в панели свойств, мы вызываем функцию XMLBuild() из класса Infos.

Кроме конструктора Game1():

Control.FromHandle(Window.Handle).Move += new EventHandler(XNAWindowsMove);

мы создаем обработчик событий, который будет отключать перемещение окна XNA.

public void XNAWindowsMove(object sender, EventArgs e)
{
    Control.FromHandle(Window.Handle).Location = new System.Drawing.Point(337, 86);
}

Давайте запустим наше приложение и попробуем что-нибудь сделать.

Создадим интерфейс, аналогичный показанному ниже.

Нажмем кнопку "Save" ("Сохранить") и повнимательнее рассмотрим файл controls.xml, который находится по пути x86->bin->debug.

<?xml version="1.0" encoding="utf-8"?>
<GUI>
  <Control Name="button1">
    <Type>GUIEditor.XButton</Type>
    <AllowDrop>False</AllowDrop>
    <Enabled>True</Enabled>
    <ForeColor>ControlText</ForeColor>
    <LocationX>324</LocationX>
    <LocationY>42</LocationY>
    <SizeW>75</SizeW>
    <SizeH>23</SizeH>
    <Text>New Game</Text>
  </Control>
  ......
</GUI>

Да, это означает, что мы успешно сделали все, что хотели. Теперь список элементов управления может использоваться в наших экранах.

Во второй части я буду говорить о том, как загружать этот XML-файл, добавлять события и создавать экраны. После чего мы успешно закончим процесс создания редактора графического пользовательского интерфейса.

Встретимся в следующих статьях!