Часть третья
(Окончание. Начало в №20)
Итак, наш с вами многострадальный твикер вышел на финишную прямую. На самом-то деле, конечно, не такой уж он и многострадальный, но, если пострадать над ним подольше, может получиться весьма толковая утилита... Впрочем, давайте обо всём последовательно.
Для начала, как водится, краткое содержание предыдущих частей - наверняка читатели успели их порядком подзабыть. В первой мы с вами занимались тем, что изобретали переменные и проверяли реестр. Дело, что и говорить, полезное, а потому это всё заняло у нас довольно много времени (то есть, газетного пространства). Во второй части мы тоже не ленились, а занимались тем, что загружали список "твиков" из текстового файла, имевшего довольно-таки экзотический формат, и вносили их содержимое непосредственно в системный реестр. Сегодня мы будем доделывать то, что не доделали в первых двух частях - то есть, связывать всё это вместе и придавать ему телесность путём создания пользовательского графического интерфейса. А в завершение немного поговорим о том, как это всё можно развить дальше собственными силами.
Применение всех "твиков"
Способ работы нашего с вами твикера таков: пользователь сначала отмечает все "твики", которые нужно применить (или же, напротив, отменить), а после нажимает кнопку "Apply", и все изменения сами записываются в соответствующие разделы реестра. Как говорится, "по щучьему велению, по моему хотению, твикайся, система!". Мне кажется, что это более удобно для пользователя, чем мгновенное внесение информации о "твике" в реестр сразу после того, как пользователь щёлкнул по флажку, который этот "твик" применяет или отменяет. Это хорошо ещё и потому, что многие "твики" требуют перезагрузки для того, чтобы изменения вступили в силу.
Традиционно сначала рассмотрим код, который вносит все поправки в реестр, пробегая последовательно по списку всех доступных "твиков" и применяя метод WriteChanges() только для тех из них, которые отмечены как изменённые.
private void ApplyChanges() { if (IsSomethingChanged == false){ return; }; System.Windows.Forms.DialogResult dr = MessageBox.Show("Apply changes?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question); switch (dr) { case DialogResult.Yes: foreach (FireTweakerOption Opt_ in lst){ Opt_.WriteChanges(); }; IsSomethingChanged = false; break; default: break; } }
Хотя этот метод и предельно прост, я всё же позволю себе прокомментировать его работу. Во-первых, мы сначала проверяем глобальную переменную, чьё говорящее название лучше всего сообщает о том, для чего она была введена в код нашей с вами программы. После этого не сильно, я бы сказал, сложного действия, мы запрашиваем у пользователя подтверждение нажатия на кнопку - он ведь мог на неё и случайно нажать, не так ли? Метод Show класса MessageBox (он находится в том же пространстве имён, что и тип DialogResult, полное имя которого я указал для наглядности), как видите, почти что полностью аналогичен стандартной функции MessageBox из старого доброго Win32 API. Только выглядит всё ещё прозрачнее за счёт более прозрачного именования констант. Дальше мы, как легко заметить, подчиняемся выбору пользователя: если он нажал в MessageBox'е "Yes", то мы последовательно перебираем все элементы списка "твиков" и вносим соответствующие изменения в реестр. Если же пользователь раздумал что-то менять, то и твикер наш, соответственно, продолжает наслаждаться бездельем.
Обратите внимание на переменную IsSomethingChanged. Конечно, это далеко не самое изящное решение проблемы, но, надеюсь, эта неизящность будет только лишним поводом поэкспериментировать с текстом программы и внести в него улучшения и дополнения. Эта переменная обязательно должна устанавливаться в true тогда, когда мы изменяем хоть один "твик" из всего нашего списка. После применения всех "твиков" она, как видите, специально устанавливается в false, так что даже если пользователь кликнет по кнопке применения "твиков" два раза, всё равно нашему с вами хитрому и ленивому твикеру не придётся пахать дважды. Кстати, при изменении состояния "твика" нужно будет поменять у него самого и поле IsChanged, поскольку оно, как вы наверняка помните, используется в методе WriteChanges() нашего твикового класса.
Пользовательский интерфейс
Привести полный код пользовательского интерфейса в этой статье было бы очень и очень заманчиво. Особенность C# состоит в том, что, в отличие от многих других RAD-решений код инициализации интерфейса помещается любой средой разработки для этого языка непосредственно в программу. За счёт этого файл с одним только исходным текстом главного окна может быть в несколько раз больше, чем все файлы с кодом, реализующим бизнес-логику программы. И если бы я решил всё-таки опубликовать весь текст твикера в "КВ", то сериал бы наш с вами затянулся, как минимум, до осени, а то и до следующей весны. Впрочем, я не думаю, что вам было бы интересно читать из номера в номер полотнища газетных страниц, на которых были бы только однообразные операторы вроде "this.button6.Text = "Help";" или "this.pictureBox1.Click += new System.EventHandler(this.PictureBox1Click);". Поэтому о пользовательском интерфейсе мы поговорим кратко и в общих чертах - я бы даже сказал, в самых общих.
Реализовать пользовательский интерфейс с использованием C# вам будет несложно даже в том случае, если визуальное редактирование интерфейсов Windows-приложений для вас в диковинку. Но, думаю, что подавляющая часть наших читателей сталкивалась хотя бы с Visual Basic или, лучше, Delphi (почему лучше? Потому что C# придумал тот же человек, который разработал в своё время и Delphi). А в #Develop, Visual Studio и C# Builder'е работа с пользовательским интерфейсом выглядит точно так же, как и в упомянутых выше средах разработки: вы выбираете на палитре компонентов элементы пользовательского интерфейса, размещаете на окне (форме) в соответствии с собственными эстетическими взглядами и вкусами, а затем программируете с помощью назначения компонентам обработчиков событий. Обработчик события - это метод формы, на который размещён компонент, запускающийся при каком-либо событии, произошедшем с этим самым компонентом - например, событием будет клик по нему мышью.
Ограничивать вашу фантазию приведением примеров придуманного мной пользовательского интерфейса не буду (ну да, вы угадали - позориться просто не хочется). Укажу только на некоторые его детали, которые будут нужны. Это, во-первых, список всех доступных пользователю в настоящий момент "твиков" - я реализовывал его с помощью компонента listBox. Также пригодится нам и поле, в котором будет выводиться описание твика - не зря же мы зарезервировали под него место в нашем твиковом файле? Ещё, само собой, нужен какой-нибудь checkBox, на который пользователь будет щёлкать, желая применить или отменить какой-нибудь "твик", а также что-нибудь (тоже, вероятно, checkBox, только без возможности изменить его состояния), что будет отображать необходимость перезагрузки для внесения изменений в реестр.
Я ещё не удержался и добавил в нижнюю часть окна программы небольшую надпись, содержащую URL сайта твикера. Вы тоже можете это сделать, повесив на неё вот такой обработчик:
void LinkLabel1Click (object sender, System.EventArgs e) { Process Browser = new Process(); Browser.StartInfo.FileName = "http://www.my-super-cool-mega-advanced-tweaker-professional.com"; Browser.StartInfo.Arguments = ""; Browser.StartInfo.UseShellExecute = true; Browser.StartInfo.Verb = "open"; Browser.StartInfo.ErrorDialog = false; Browser.Start(); }
Поясню, что мы здесь делаем. Для запуска браузера обычно используется функция ShellExecute из состава Windows Shell API. Однако, поскольку мы имеем дело с C#, то таким простым приёмом обойтись не удастся - нужны классы, классы и ещё раз классы. Поэтому мы используем класс Process (думаю, для вас не будет открытием тот факт, что этот класс нужен для работы с процессами) и просто устанавливаем флаг UseShellExecute в состояние true. Думаю, где-то внутри Microsoft .NET Framework'а всё оборачивается, в конечном итоге, именно обращением к функции ShellExecute, но напрямую её использовать здесь было бы сложнее. Естественно, адрес http://www.my-super-cool-mega-advanced-tweaker-professional.com нужно поменять на реальный (можете зарегистрировать и этот домен - я не жадный, и, думаю, никто другой на него тоже до сих пор не позарился).
Ура, товарищи!
Мы сделали свой собственный твикер! Его можно дать на тестирование друзьям (лучше врагам, конечно), можно разместить на каком-нибудь download-архиве (например, download.ru), можно подарить на День рождения любимой девушке (думаю, такого ей точно никто ещё не дарил). Только сначала, пожалуйста, всё-таки сделайте какой-нибудь нормальный для простого пользователя интерфейс и напихайте в наш текстовый файл хотя бы десяток-другой "твиков".
Перспективы развития для программного продукта подобного класса такие, что аж дух захватывает. Можно, во-первых, сделать функцию резервного копирования данных, которые изменяет программа в реестре - думаю, пользователи от такого не откажутся. Было бы также неплохо как-нибудь зашифровать файл с "твиками", чтобы конкуренты не узнали, как это вы так хитро систему настраиваете (хотя те, кому надо, всё равно узнают с помощью Registry Monitor'а). Можно также добавить к этому всему "твики", которые уже не укладываются в простую бинарную схему включён/выключен, а требуют к себе более тонкого подхода.
Твикеры сейчас популярны, и, я бы сказал, даже очень. Они, впрочем, всегда популярны. Если желаете использовать код, приведённый в статье, для собственных коммерческих разработок, я не против - всё равно основной работой будет не программировать, а собирать "твики". Если сумеете на этом твикере хорошо заработать, то хотя бы сообщите по e-mail'у, договорились?
Теперь о грустном. Немножко не "ура" получилось вот с XML'ем, использование которого я легкомысленно обещал продемонстрировать. Приношу свои извинения: чтобы не затягивать эту серию статей (их достаточно и три: известно ведь, что три - число магическое, а четыре - всего лишь два во второй степени), я решил вынести рассмотрение C# и XML в связке в отдельную статью. Может, она появится и не очень скоро, но постараюсь о ней не забыть. А забуду - так напомните.
Что ж, надеюсь, рассмотрение собственного твикера на C# оказалось для вас полезным. Если нет, буду рад услышать (точнее, увидеть) ваши предложения по поводу того, о чём написать на страницах "Компьютерных вестей".
Вадим СТАНКЕВИЧ,
dreamdrusch@tut.by