Садржај
2 Класе и објекти
2.1 Основни појмови о класама и објектима
3 Генеричке класе
4 Наслеђивање и полиморфизам
5 Примери пројеката са решењима
5.1 Различита кретања
5.2 Квиз
5.4 Приказ рада алгоритама сортирања

Прилог – графичка апликација

Као допуну примера са игром Асоцијације, креираћемо и графичку апликацију која омогућава играње исте игре, користећи исту библиотеку. Поред тога што вежбамо сáмо прављење оваквих програма, па и формално повезивање програма са библиотеком, тј. подешавање зависности, овим постижемо још једну важну ствар. Прављењем апликације другачијег типа која користи исту класу, проверавамо да ли је класа погодна за такву употребу, односно да ли је направљена тако да се уклапа у два различита програма.

Чак и када правимо само једну апликацију (нпр. графичку), свакако је пожељно да логику игре издвојимо у посебну класу, а ту класу сместимо у посебан фајл (или библиотеку). На тај начин разлажемо проблем који је пред нама на мање делове и лакше савладавамо његову сложеност.


Употребу исте класе из више програма различитог типа можемо да схватимо као завршни тест, којим потврђујемо да је класа заиста направљена онако како смо желели.


У овом случају, то је провера да смо на прави начин раздвојили логику игре од корисничког интерфејса. На пример:

  • уколико нам се делови кода понављају у различитим апликацијама, треба да размислимо да ли ти делови можда спадају у логику игре, а не у кориснички интерфејс,

  • уколико у класи која садржи логику игре имамо делове који се користе у једној, али не и у другој апликацији, треба да размислимо да ли ти делови можда спадају у кориснички интерфејс, а не у логику игре.

Кораци за креирање графичке апликације су слични као и за креирање конзолне апликације:

  • из менија изаберемо опцију File / Add / New project (или после десног клика на решење у прозору Solution Explorer изаберемо опцију Add / New project у контекстном менију),

  • за тип пројекта бирамо Windows Forms App,

  • у дијалогу који се отвара, можемо као име пројекта (Project name) да упишемо AsocijacijeWin.

Најбоље је да одмах подесимо и зависност новог програма од библиотеке, као што смо то учинили и за конзолну апликацију. Такође, на почетак програма треба да додамо ред using AsocijacijeLib;, којим омогућавамо програму да користи име класе и њених делова, дефинисаних у именском простору AsocijacijeLib.

У програму ће нам бити потребан један објекат класе Asocijacije (назовимо га igra), као и целобројна променљива за бројање поена (променљива ukupnoPoena). У случају да желимо игру за више играча, потребан је целобројни низ, у коме би се чували поени сваког играча. После ових почетних подешавања, програм изгледа овако и може да се покрене (мада програм још увек ништа не ради, могућност покретања потврђује да је до сада све урађено како треба):

using System.Windows.Forms;
using AsocijacijeLib;

namespace AsocijacijeWin
{
    public partial class Form1 : Form
    {
        Asocijacije igra;
        int ukupnoPoena = 0;

        public Form1()
        {
            InitializeComponent();
        }

    }
}

Позабавимо се сада и дизајном и садржајем ове графичке апликације. Двокликом на форму, добијамо метод Form1_Load који ћемо касније да искористимо за све потребне иницијализације, када будемо видели шта све треба да се иницијализује.

За учитавање фајла са појмовима и решењима уобичајено је да се креира мени са опцијом File / Open. Уколико нисте сигурни како да то урадите, додавање менија и дијалога за отварање фајла је објашњено у Петљином приручнику „C# програмирање графичког корисничког интерфејса”, у примеру Едитор текста.

Као следећи корак, можемо да додамо дугмад за отварање поља. Да би кôд програма био прегледнији, самим објектима класе Button можемо да доделимо редом имена btnA1, btnA2, btnA3, btnA4, btnB1, btnB2, btnB3, btnB4, btnC1, btnC2, btnC3, btnC4, btnD1, btnD2, btnD3 и btnD4. Један начин да то урадимо је да селектујемо једно по једно дугме и да за свако селектовано дугме у прозору Properties међу својствима нађемо својство (Name) и упишемо име објекта. Натписе на дугмади, односно вредност поља Text не морамо да подешавамо, јер ће ти натписи свакако бити стално ажурирани током игре, користећи индексер класе Asocijacije са два индекса.

Кликом на свако дугме треба да се изврши суштински исти поступак, а то је отварање једног поља у игри. Било би добро да избегнемо писање кода за свако дугме посебно и да направимо један метод који се извршава када кликнемо на било које дугме. Метод који реагује на клик на дугме можемо да направимо нпр. двокликом на дугме A1. Метод аутоматски добија име btnA1_Click. Пошто желимо да то буде метод који се извршава кликом на свако дугме, можемо да му прво променимо име у btn_Click. Ово треба да урадимо користећи прозор Properties, тако што међу догађајима нађемо догађај Click, а затим променимо име метода на десној страни.

Даље, потребно је да осталих 15 дугмади повежемо са овим догађајем. Ово радимо тако што селектујемо једно по једно дугме и међу догађајима у прозору Properties подесимо да на догађај Click одговара метод btn_Click. У изворном коду за сада празног метода видимо да је он декларисан као btn_Click(object sender, EventArgs e). Први параметар овог метода је објекат на коме се догађај десио, тј. дугме на које је кликнуто. Захваљујући томе, метод зна за које дугме је позван и може да закључи које параметре да проследи методу игре igra.Otvori(kol, polje). Ипак, пошто упоређивање објекта sender са сваким од 16 дугмади није нарочито елегантно решење, можемо да искористимо поље Tag дугмета, и по том тагу једноставније одредимо који параметри су нам потребни. За поље Tag може да се веже било који објекат, а ми ћемо у то поље да упишемо неки текст из кога лако могу да се одреде редни број колоне и поља у колони. На пример, можемо за свако дугме редом као вредност поља Tag да упишемо A1, A2, A3, A4, B1, B2, B3, B4, C1, C2, C3, C4, D1, D2, D3 и D4. Сам метод за сада можемо да напишемо овако:

private void btn_Click(object sender, System.EventArgs e)
{
    Button b = sender as Button;
    string tag = (string)b.Tag;
    int kol = tag[0] - 'A';
    int polje = tag[1] - '1';
    if (igra.Otvori(kol, polje))
    {
        b.Text = igra[kol, polje];
    }
}

…а касније ћемо по потреби да га изменимо или допунимо.


На сличан начин треба да припремимо и текстуална поља за унос решења колона, као и поље за унос коначног решења. Додаћемо пет објекта типа TextBox на форму и даћемо им имена tbA, tbB, tbC, tbD и tbKonacno. Размислимо које би било жељено понашање ових текстуалних поља.

  • Када корисник кликне на неко поље да би погађао решење, претходни текст (реч Konacno или назив колоне) треба да нестане. Ово можемо да постигнемо ако реагујемо на догађај Enter, који се дешава када пребацимо фокус на текстуално поље (нпр. кликом на њега).

  • Када корисник напусти поље, треба да се врати претходни текст, тј. име поља. Ово можемо да постигнемо ако реагујемо на догађај Leave, који се дешава приликом преласка са овог текстуалног поља на неку другу контролу (нпр. друго текстуално поље).

  • Када корисник притисне тастер Enter док је текстуално поље у фокусу, требало би да се провери да ли је до тада унети текст решење за то поље. За ово можемо да искористимо догађај PreviewKeyDown, који нам омогућава да додатно обрадимо притиске на тастере тастатуре, док се текст уноси.

Повезаћемо свих пет поља са догађајима Enter, Leave и PreviewKeyDown. Нека се методи који реагују на ове догађаје за свих пет поља зову редом tbABCD_Enter, tbABCD_Leave и tbABCD_PreviewKeyDown. Да бисмо из ових метода могли удобно да установимо на ком пољу се догађај десио, можемо да поставимо тагове ових пет текстуалних поља редом на A, B, C, D, односно Konacno. То ће нам поједноставити писање припремљених метода.

У оквиру корисничког интерфејса желимо још да кориснику негде приказујемо број освојених поена, као и да му на неки начин саопштавамо шта се од њега очекује (да учита игру, да отвори поље, или да погађа решење). За то ћемо да употребимо две лабеле, lblPoeni и lblPoruka. Тиме смо довршили дизајнирање форме, односно избор и подешавање контрола.

Преостаје још да попунимо припремљене методе tbABCD_Enter, tbABCD_Leave и tbABCD_PreviewKeyDown. Осим ових метода који реагују на одговарајуће догађаје, згодно је да имамо и два помоћна метода, јер се поступци садржани у њима користе на више места у коду.

  • Метод Osvezi() ће после акције корисника да ажурира натписе на дугмади и текстуалним пољима, тако што поставља појмове и решења уместо имена поља свуда где је то потребно.

  • Метод DozvoliUnos(bool dozvoli) омогућава или онемогућава погађање, према томе да ли корисник има право да погађа или треба прво да отвори поље.

У наставку је комплетан изворни кôд фајла Form1.cs. Напомињемо да није довољно да се овај кôд ископира у истоимени фајл ваше апликације, већ је потребно да се обаве све претходно описане радње: постављање елемената корисничког интерфејса (контрола), њихово именовање као у коду, повезивање контрола са одговарајућим догађајима, именовање догађаја као у коду и постављање тагова за дугмад и текстуална поља.

(Created using Swinx, RunestoneComponents and PetljaDoc)
© 2022 Petlja
A- A+