$$ \newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} \newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} \renewcommand{\mod}{\,\mathrm{mod}\,} \renewcommand{\div}{\,\mathrm{div}\,} \newcommand{\metar}{\,\mathrm{m}} \newcommand{\cm}{\,\mathrm{cm}} \newcommand{\dm}{\,\mathrm{dm}} \newcommand{\litar}{\,\mathrm{l}} \newcommand{\km}{\,\mathrm{km}} \newcommand{\s}{\,\mathrm{s}} \newcommand{\h}{\,\mathrm{h}} \newcommand{\minut}{\,\mathrm{min}} \newcommand{\kmh}{\,\mathrm{\frac{km}{h}}} \newcommand{\ms}{\,\mathrm{\frac{m}{s}}} \newcommand{\mss}{\,\mathrm{\frac{m}{s^2}}} \newcommand{\mmin}{\,\mathrm{\frac{m}{min}}} \newcommand{\smin}{\,\mathrm{\frac{s}{min}}} $$

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

О догађајима

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

Апликације добијају обавештења о догађајима попут „притиснит је леви тастер миша при положају миша (235, 147)”. Захваљујући .NET библиотеци, Windows Forms апликација на основу овакви „сирових” података, израчунава шта такав догађај значи за графичке контроле које смо поставили на формулар. Тиме је посао апликативних програмера знатно олакшан, јер је довољно да задају како ће да реагују када се одређеној контроли нешто догоди.

На пример, у нашем првом примеру смо задали да желимо да реагујемо на догађај клика на дугме. Окружење Visual Studio нам је на захтев креирало празну функцију која ће се извршавати сваки пут када корисник кликне на дугме, а наш део посла је био да у ту функцију убацимо одговарајуће наредбе.

Свака Windows Forms апликација у суштини само чека на догађај, а затим покреће функцију која се бави тим догађајем (таква функција се на енглеском зове event handler). За овакве апликације се каже да су вођене догађајима (event driven applications).

Свакој од контрола које стављамо на формулар, а и самом формулару могу се придружити разни догађаји на које желимо да наша апликација реагује. У наставку ћемо упознати различите контроле и кроз примере видети различите начине реаговања на догађаје.

Контрола поље за потврду

Поље за потврду је једна од најчешће коришћених контрола у апликацијама, па је врло вероватно да сте је већ много пута видели и употребили као корисник разних програма. Ова контрола се на енглеском зове checkbox и изгледа овако: ☑ , а налази се у кутији за алат, у групи уобичајених контрола (Toolbox \(\to\) Common Controls), исто као и лабела, текстуално поље и дугме, које смо користили у нашем првом примеру.

Најважније својство поља за потврду је својство Checked (потврђено). Ово својство је логичког типа и као такво може имати вредност true или false. Вредност true значи да је корисник дао потврдан одговор, односно да је „чекирао” поље, а вредност false значи да је одговор корисника одречан.

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

Пример - jагоде

Креирати Windows Forms апликацију која омогућава кориснику да одговори да ли воли јагоде, а ако воли, одговор може да прецизира тако што одговори да ли их воли са шлагом.

Ставићемо на формулар два поља за потврду, једну за основно питање (волиш ли јагоде?), а другу за додатно питање (са шлагом?). За подешавање свих својстава користићемо помоћни прозор Properties, као у примеру „Старост”.

Својство Name контроле за основно питање поставимо на cbJagode, а за додатно питање на cbSlag. Ово подешавање имена ће нам касније учинити програм јаснијим (да ово нисмо урадили, контроле би се у програму звале checkBox1 и checkBox2 и било би теже разумети програм).

Својство Text ових контрола ћемо да подесимо тако да садржи одговарајуће питање. Контролу за додатно питање постављамо испод и мало увучено (померено удесно) да би кориснику било јасније да ово питање зависи од претходног. Пошто изјашњавање о шлагу нема смисла ако корисник не воли јагоде, можемо и да онемогућимо клик на контролу cbSlag ако на основно питање није одговорено потврдно. То се ради подешавањем својства Enabled (Enabled значи омогућено) контроле cbSlag на false.

Постоји још једна корисна могућност поља за потврду, а то је неодређено стање. Да кориснику не бисмо сугерисали одговор на основно питање, можемо да подесимо да поље за потврду на почетку не садржи ни одговор „да” ни „не”. То ћемо постићи постављањем својства CheckState на вредност Indeterminate (неодређено).

Коментар на избор корисника можемо да упишемо у лабелу. Додајмо једну лабелу на дно формулара и назовимо је (поставимо својство Name на) lblKomentar.

На крају фазе дизајна подесимо и нека својства формулара (што није пресудно за рад програма, али чини апликацију лепшом). Најпре уместо генеричког наслова Form1, можемо да поставимо својство Text формулара на вредност „Јагоде”, што се одмах види и у наслову формулара. Даље, пошто за овај формулар нема смисла допуштати кориснику да мења његову величину, можемо да на формулару да подесимо својство FormBorderStyle на Fixed3D, а својство MaximizeBox на false. Овим смо онемогућили промену величине прозора повлачењем његових ивица (својство FormBorderStyle) и кликом на дугме Maximize у насловној линији прозора (својство MaximizeBox). На сличан начин ћемо и убудуће подешавати својства формулара (име увек, а најчешће и онемогућавање промене величине прозора) и нећемо посебно истицати у наредним примерима.

Подешавањем својстава формулара смо довршили дизајнирање и формулар сада изгледа овако:

../_images/Jagode_Form.png

Пређимо на фазу програмирања. Из прозора који нам приказује дизајн формулара можемо да пређемо да прозор са програмским кодом притиском на тастер F7. Други начин је да користимо прозор који се зове Solution Explorer. Овај прозор је обично већ отворен и налази се са десне стране, изнад прозора Properties (ако није отворен, можете га отворити из менија View \(\to\) Solution Explorer). У овом прозору можете да кликнете десним тастером миша на фајл Form1.cs и у контекстном искачућем менију изаберете View Code.

../_images/Jagode_Kod.png

На прозор са дизајном се враћамо притиском на Shift+F7, или простим кликом на фајл Form1.cs у прозору Solution Explorer.

У прозору са кодом требало би да видимо отприлике овакав код:

using System;
using System.Windows.Forms;

namespace Jagode
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

    }
}

Додајмо најпре функцију која поставља одговарајући текст лабеле lblKomentar. Та функција би могла на пример да се напише овако:

using System;
using System.Windows.Forms;

namespace Jagode
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Komentarisi()
        {
            if (cbJagode.Checked)
                if (cbSlag.Checked)
                    lblKomentar.Text = "Pa da, i ja najviše volim sa šlagom";
                else
                    lblKomentar.Text = "I ja volim jagode, ali sa šlagom";
            else
                lblKomentar.Text = "A ja baš volim jagode, i to sa šlagom";
        }
    }
}

У овој функцији задајемо текст који желимо да прикажемо кориснику на основу вредности својстава cbJagode.Checked и cbSlag.Checked, то јест на основу изјашњења корисника.

Остаје да још испрограмирамо функције за обраду догађаја, које ће позивати управо написану функцију Komentarisi. Након клика на контролу cbJagode, у прозору Properties видимо својства ове контроле. Да бисмо уместо својстава контроле видели догађаје које можемо да програмирамо (и функције које смо тим догађајима евентуално већ придружили), потребно је кликнути на сличицу у облику муње, на коју показује стрелица на слици доле.

Да бисмо се вратили на приказ својстава,треба да кликнемо да сличицу француског кључа (лево од сличице муње). Задржавањем миша изнад ових сличица појваљује се савет о алатки (енгл. tool tip) - малецки текстуални прозор са описом алатке.

За контролу cbJagode ћемо одабрати догађај CheckedChanged. Овај догађај се дешава сваки пут када се својство Checked контроле промени.

../_images/Jagode_CheckedChanged.png

Двокликом у листи на тај догађај, добијамо функцију cbJagode_CheckedChanged, која ће се на тај догађај извршавати. Додајмо у функцију следеће две наредбе:

private void cbJagode_CheckedChanged(object sender, EventArgs e)
{
    cbSlag.Enabled = cbJagode.Checked;
    Komentarisi();
}

Првом наредбом постижемо да на конторлу cbSlag може да се кликне само ако је корисник одговорио да воли јагоде (својство Checked контроле cbJagode има вредност true. Другом наредбом покрећемо раније написану функцију за задавање одговарајућег текста у лабели.

Потребно је још контролисати и догађај промене стања контроле cbSlag. Ради тога кликнимо прво на контролу cbSlag, затим међу њеним догађајима одаберимо CheckedChanged, чиме добијамо функцију cbSlag_CheckedChanged. У овој функцији ћемо само да позовемо функцију Komentarisi:

private void cbSlag_CheckedChanged(object sender, EventArgs e)
{
    Komentarisi();
}

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

Поље за потврду са три стања

Видели смо да корисник кликовима на поље за потврду наизменично мења њено стање у „потврђено” и „непотврђено”. Након што једном промени почетно неодређено стање, корисник се више не може вратити на њега. Понекад је међутим потребно кориснику оставимо могућност да постави поље за потврду у неодређено стање. Ради тога треба прво подесити логичко својство ThreeState ове контроле на true. Након тога стање контроле постављамо и очитавамо користећи својство CheckState. Ово својство је набројивог типа (Enum), и његове вредности су CheckState.Checked, CheckState.Unchecked и CheckState.Indeterminate.

Да бисмо илустровали употребу поља за потврду у случају да омогућавамо кориснику сва три стања, изменићемо мало претходни програм.

Пример - jагоде са да, не и можда

Изменити претходни пример, тако да корисник који је неодлучан може да постави контролу у неодређено стање.

У фази дизајнирања формулара потребно је само да променимо својство ThreeState контроле cbJagode на true. Тиме и кориснику допуштамо постављање сва три стања (ми смо из програма могли да постављамо сва три стања и до сада, мењањем својства CheckState).

У фази програмирања ће бити нешто више промена. Прво ћемо да изменимо функцију Komentarisi, тако да узима у обзир сва три стања контроле cbJagode. Уместо својства cbJagode.Checked провераваћемо вредност својства cbJagode.CheckState:

using System;
using System.Windows.Forms;

namespace Jagode
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Komentarisi()
        {
            switch (cbJagode.CheckState)
            {
                case CheckState.Checked:
                    if (cbSlag.Checked)
                        lblKomentar.Text = "Pa da, i ja najviše volim sa šlagom";
                    else
                        lblKomentar.Text = "I ja volim jagode, ali sa šlagom";
                    break;
                case CheckState.Indeterminate:
                    lblKomentar.Text = "Kako ne znaš da li voliš jagode?";
                    break;
                case CheckState.Unchecked:
                    lblKomentar.Text = "A ja baš volim jagode, i to sa šlagom";
                    break;
            }
        }
    }
}

Следећа измена је избор догађаја које ослушкујемо. За контролу cbJagode, коју сада користимо са три стања, уместо догађаја CheckedChanged ћемо одабрати догађај CheckStateChanged, који се дешава када се промени својство CheckState. Прво ћемо двокликом у листи на овај догађај додати и функцију за обраду догађаја CheckStateChanged:

../_images/Jagode_CheckStateChanged.png

затим ћемо додати одговарајуће наредбе у нову функцију, а обрисати наредбе из старе функције:

private void cbJagode_CheckedChanged(object sender, EventArgs e)
{

}

private void cbJagode_CheckStateChanged(object sender, EventArgs e)
{
    cbSlag.Enabled = (cbJagode.CheckState == CheckState.Checked);
    Komentarisi();
}

Приметите да је услов да допустимо кориснику да кликне на контролу cbSlag сада нешто другачији (својство Checked више није довољно, можете се поиграти и проверити зашто).

На крају, у прозору Properties треба да обришемо текст cbJagode_CheckedChanged поред догађаја CheckedChanged. Тиме одустајемо од контролисања овог догађаја, који нам више није битан јер контролишемо догађај CheckStateChanged.

Функцију cbSlag_CheckedChanged за контролу догађаја CheckedChanged контроле cbSlag не треба мењати.

Испробајте и ову верзију програма да бисте проверили и њену функционалност и потврдили да разумете понашање поља за потврду када је оно подешено да има три стања. Прођите кроз разне комбинације стања ова два поља за потврду и добијте сва четири могућа одговора.

Заједничка обрада догађаја

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

Пример - одреди децу

Аница, Божидар, Вера, Горан, Дуња, Ђорђе, Ема и Живан живе у истом насељу и често се друже. О њима знамо да су Аница, Божидар, Вера и Горан добри програмери, а Аница, Божидар, Дуња и Ђорђе се активно баве спортом.

Креирати Windows Forms апликацију која нуди кориснику да зада неке или све од три могуће особине (да ли је програмер, да ли је спортиста, да ли је девојчица), а затим на основу одговора корисника приказује имена која задовољавају постављене услове. На пример, ако корисник тражи дечаке спортисте (а о знању програмирања се није изјаснио), треба да добије имена Божидар и Ђорђе.

Ставићемо на формулар три поља за потврду која имају по три стања, по једно поље за сваку особину. За особину коју не жели да прецизира, корисник може да остави одговарајуће поље у неодређеном стању. Неодређено стање ћемо тумачити као „свеједно”. Испод поља за подтврду ћемо додати и лабелу за одговор.

Постављањем примерених имена контролама (својство Name сваке контроле, на пример cbDevojcica, cbProgramer и cbSportista као имена поља за потврду, а lblOdgovor као ме лабеле), као и текстова који се виде на формулару (својство Text формулара и сваке контроле) завршавамо дизајнирање изгледа формулара и он сада изгледа овако:

../_images/OdrediDecu_Form.png

За свако од поља за потврду треба да контролишемо догађај CheckStateChanged. Ради тога можемо свакој од ове три контроле да за поменути догађај доделмо по једну функцију, као што семо радили у примеру „Јагоде”. У нашем примеру контроле се зову cbProgramer, cbSportista и cbDevojcica, па би функције добиле имена cbProgramer_CheckStateChanged, cbSportista_CheckStateChanged и cbDevojcica_CheckStateChanged. Из сваке од ових функција бисмо могли да позовемо једну те исту функцију, која би израчунала и приказала одговор, слично као што у примеру Јагоде функција Komentarisi одређује и приказује одговарајући коментар.

У овом примеру можемо и да поједноставимо програм, тако што свакој од контрола доделимо исту функцију за обраду догађаја. Када кликнемо на прву од контрола (cbProgramer) и пронађемо њен догађај CheckStateChanged, уместо двоклика на догађај у листи, можемо са десне стране да упишемо име функције какво желимо. Упишимо на пример, реч Odgovori као име функције која ће обрадити овај догађај:

../_images/OdrediDecu_Dogadjaji1.png

Након тога, када за следећу контролу (cbSportista) пронађемо исти догађај у исти, у пољу за име придружене функције можемо да отворимо падајућу листу са именима постојећих функција и изаберемо функцију Odgovori.

../_images/OdrediDecu_Dogadjaji2.png

Поновимо последњи корак и за контролу cbDevojcica. Тиме смо поставили једну функцију да обрађује догађај промене стања за сва три поља за потврду. Сада још треба да убацимо одгварајуће наредбе у функцију Odgovori.

Размотримо при којим стањима трију поља за потврду треба да ипишемо на пример име Аница. Аница је програмер, спортиста и девојчица, па да би се њено име нашло у одговору, потребно је да свако од поља за потврду буде или у стању „потврђено” или у стању „неодређено”, то јест да ни једно од поља не буде у стању „непотврђено”.

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

Да би програм био прегледнији, уместо да услов за појављивање Анице у одговору пишемо овако:

if (cbProgramer.CheckState != CheckState.Unchecked
    && cbSportista.CheckState != CheckState.Unchecked
    && cbDevojcica.CheckState != CheckState.Unchecked) ...

можемо прво да именујемо сваки од подуслова

bool programira = (cbProgramer.CheckState != CheckState.Unchecked);
bool sportista = (cbSportista.CheckState != CheckState.Unchecked);
bool devojcica = (cbDevojcica.CheckState != CheckState.Unchecked);

чиме услов за Аницу постаје лакше читљив:

if (programira && sportista && devojcica) ...

Када ово урадимо за свако од осморо деце, долазимо до следећег облика функције Odgovori:

private void Odgovori(object sender, EventArgs e)
{
    StringBuilder odgovor = new StringBuilder();
    odgovor.Append("Uslov ispunjavaju:\n");
    bool programira = (cbProgramer.CheckState != CheckState.Unchecked);
    bool neprogramira = (cbProgramer.CheckState != CheckState.Checked);
    bool sportista = (cbSportista.CheckState != CheckState.Unchecked);
    bool nijesportista = (cbSportista.CheckState != CheckState.Checked);
    bool devojcica = (cbDevojcica.CheckState != CheckState.Unchecked);
    bool decak = (cbDevojcica.CheckState != CheckState.Checked);

    if (programira && sportista && devojcica) odgovor.Append("    Anica\n");
    if (programira && sportista && decak) odgovor.Append("    Božidar\n");
    if (programira && nijesportista && devojcica) odgovor.Append("    Vera\n");
    if (programira && nijesportista && decak) odgovor.Append("    Goran\n");
    if (neprogramira && sportista && devojcica) odgovor.Append("    Dunja\n");
    if (neprogramira && sportista && decak) odgovor.Append("    Đorđe\n");
    if (neprogramira && nijesportista && devojcica) odgovor.Append("    Ema\n");
    if (neprogramira && nijesportista && decak) odgovor.Append("    Živan\n");

    lblOdgovor.Text = odgovor.ToString();
}

Примери за самостално проучавање

Погледајте пројекат OdrediDete, који је врло сличан примеру кроз који смо управо прошли. Разлика је у томе што поља за потврду имају само два стања па корисник за сваку особину мора да изабере „да” или „не”. Због тога у овом случају задате услове увек испуњава само једно дете. Обратите пажњу на то која својства и који догађај ових контрола се користе у пројекту OdrediDete.

Компајлирајте и извршите пројекат NalazenjeFajlova. Размислите како бисте подесили својства свих поља за потврду и контролисали догађаје промене стања тих контрола (овај пример је детаљније објашњен касније).