[ TATATA @ 30.11.2012. 09:06 ] @
Ćao,


nova sam na forumu, pa ako nisam postavila pitanje na pravom mestu ili na pravi način, reagujte.

Pravim formu u C# koja sadrži 3 kockice u razlicitim bojama (crvena, žuta, zelena), ime svake kockice, dva TextBox-a i button OK.

Na pocetku je zadato ime kockice i njena boja. Npr:
"prva" Green
"druga" Red
"treca" Yellow

Ovi podaci se čuvaju u Dictionary u formi:

public Dictionary<string, LightValue> Lights = new Dictionary<string, LightValue>();

Kockice, u stvari, simuliraju lampice, tj, ako korisnik unese "druga" Green i stisne OK, kockica pored druge treba da promeni boju u onu koju je korisnik uneo (Green). U formi će biti samo ove tri boje. Pri svakom unosu, radiće se UPDATE boje u Dictionary:

switch (args.Light.ToString())
{

case "Red":
Lights.Add(args.Name, Semafor.LightValue.Red); break;
case "Green":
Lights.Add(args.Name, Semafor.LightValue.Green); break;
.
.
.
}
Kad izvršim program, LightValue dobije novu vrednost, ali ne znam kako da promenim boju u formi.
Ako treba još neki podatak, tu sam.

Hvala unapred.



[ Mihajlo Cvetanović @ 30.11.2012. 10:23 ] @
Malo su nejasno postavljeni uslovi. Ne znam šta od ovog napisanog može, a šta ne može da se menja. Ne znam šta je poenta ovog zadatka, šta tačno želiš da postigneš, ili šta tačno neko drugi očekuje od tebe. Ne znam ni odakle ova promenljiva args, ni kako je ona povezana sa dva text boxa.

Ako prosto samo želiš da menjaš boje u tri kvadrata, a nije uopšte bitno kako ćeš to da uradiš onda ti nikakav Dictionary ni ne treba. Imaš dva TextBox-a, recimo da se zovu textBoxName i textBoxLight. Imaš tri labele koje treba bojiti, recimo da se zovu labelFirst, labelSecond, labelThird. U hendleru za klik na OK dugme treba ti kod nalik ovome:

Code:
System.Windows.Forms.Label target;

if (textBoxName.Text == "prva")
  target = labelFirst;
else if (textBoxName.Text == "druga")
  target = labelSecond;
else if (textBoxName.Text == "treca")
  target = labelThird;

System.Drawing.Color color;

if (textBoxLight.Text == "Red")
  color = Color.Red;
else if (textBoxLight.Text == "Yellow")
  color = Color.Yellow;
else if (textBoxLight.Text == "Green")
  color = Color.Green;

target.BackColor = color;


I to je to. Ali, ako baš potrebno da se koristi Dictionary onda umesto ovih if-else-if kobasica možeš da imaš dva rečnika koja se jednom inicijalizuju i više ne diraju. Jedan koji mapira string u Label, i drugi koji mapira string u Color, i onda bi u hendleru stajala samo jedna linija:

Code:
Targets[textBoxName.Text].BackColor = Colors[textBoxLight.Text];


Ili nešto slično. Ali, ako baš potrebno da se koristi Dictionary kojem će tokom rada da se menjaju podaci, može i to ali to je glupo, i to mi miriše da školske zadatke.
[ TATATA @ 30.11.2012. 11:54 ] @
Evo screenshot, možda bude malo jasnije.

Kada pokrenem formu, kocka pored labela jupi je narandžasta.
Ako korisnik klikne OK, boja bi trebala da se izvrši Update u Dictionary i da se boja promeni u zelenu (TextBox2).
Label se ponaša kao primarni ključ, znači ne može da se menja. Moram da koristim Dictionary.

A args služi da primi podatke:
Code:

public class StisnuoEventArgs : EventArgs
    {
        public string Name { get; set; }
        public string Light { get; set; }
        
        public StisnuoEventArgs(string n, string l)
        { 
            Name = n;
            Light = l;
           
         }


public void Update(StisnuoEventArgs args)
        {
            foreach (KeyValuePair<string, LightValue> kvp in Lights)
            {
                if (args.Name == kvp.Key)
                {
                     switch (args.Light.ToString())
                    {
                        case "Red":
                            Lights.Add(args.Name, Semafor.LightValue.Red); break;
                        case "Green":
                            Lights.Add(args.Name, Semafor.LightValue.Green); break;
                        case "Orange":
                            Lights.Add(args.Name, Semafor.LightValue.Orange); break;
                    }
                    break;
                }



Nije školski zadatak, pokušavam da se zaposlim, a ovo je jedan od zadataka koje treba da rešim.
[ Mihajlo Cvetanović @ 30.11.2012. 12:19 ] @
Navedi tačno, od reči do reči, uslov u kome se spominje Dictionary. Želim da znam kako Dictionary mora da se koristi.

U međuvremenu bih da primetim da je foreach petlja ovde višak. Ako samo želiš da proveriš da li se args.Name nalazi u rečniku onda skloni foreach, a if uslov stavi da bude "if (Lights.Values.Contains(args.Name))". I dalje mislim da je ovaj rečnik ovde ubačen na silu, ali da bih znao kako bolje iskoristiti uslov "mora da se koristi Dictionary", moram da znam kako tačno uslov glasi.

Takođe ne treba ti ToString() za args.Light, jer je to već samo po sebi string.

Još nešto, trenutno ne preterano bitno. Postoje razna mišljenja u vezi sa ne-engleskim rečima za imena klasa i promenljivih. Moje mišljenje je da treba koristiti isključivo engleski jezik za bilo šta u kodu. Srpski pišem samo u komentarima. Engleski nema padeže, ima više korisnih kratkih reči od srpskog, i kod se prosto lakše čita ako je samo na jednom jeziku.
[ ravni @ 30.11.2012. 12:56 ] @
Citat:
Mihajlo Cvetanović: Moje mišljenje je da treba koristiti isključivo engleski jezik za bilo šta u kodu. Srpski pišem samo u komentarima. Engleski nema padeže, ima više korisnih kratkih reči od srpskog, i kod se prosto lakše čita ako je samo na jednom jeziku.
Problem su domain specific termini. Na primer ako pravis program za klanicu pilica, ti odmah znas da pile ima batak, krilo, karabatak i mozes tako i da nazoves promenljivu ili klasu. Tih termina nekada ima izuzetno mnogo i tesko bi bilo naci odgovarajuce prevode na engleski.

Naravno, tu onda ima smesnih situacija kao GetPileWithoutBatak() :)
[ TATATA @ 30.11.2012. 13:10 ] @
Obzirom da sam na probnom radu, usmeno su mi rekli sta treba da uradim.
Ovo je inicijalizacija:

Sem = new Semafor();
Sem.Dock = DockStyle.Top;
Sem.Lights.Add("jupi", Semafor.LightValue.Orange);
Sem.Lights.Add("ipuj", Semafor.LightValue.Red);
Sem.Lights.Add("piju", Semafor.LightValue.Green);
Stisnuo += new StisnuoDelegate(Sem.Update);
Controls.Add(Sem);
.
.
.
Sto se tice imena klasa i promenljivih, ovo je samo za test, a kad pisem glavni program, podrazumevaju se engleski izrazi.
Moza zvucim nepovezano, ali c# ucim tek dva meseca.

Hvala ti na dosadasnjim savetima.

Pozdrav.
[ Mihajlo Cvetanović @ 30.11.2012. 13:20 ] @
Ravni, slažem se da u opštem slučaju može da se desi da neki pojmovi nemaju prevod, ali što se tiče jestivih delova piletine to bar postoji, čak ima i članak na vikipediji, sa sve slikom :)

[ Mihajlo Cvetanović @ 30.11.2012. 13:48 ] @
Aha sad imamo nove informacije. Postoji već gotova klasa Semafor, koja je nekakva kontrola, i ima property Lights koji je Dictionary. E pa, odgovor na sva tvoja pitanja se nalaze u toj klasi. Ta klasa mora da ima neke metode za menjanje boje, ili propertije za pristup kontrolama od kojih je klasa sačinjena. Bez definicije klase teško da možemo da ti pomognemo.

EDIT: možda je upotreba jednostavna. Vidi da li ovo menja boju: Sem.Lights["jupi"] = Semafor.LightValue.Green;

[Ovu poruku je menjao Mihajlo Cvetanović dana 30.11.2012. u 15:00 GMT+1]
[ TATATA @ 30.11.2012. 14:11 ] @
Code:


 public class Semafor : Panel
    {
        public enum LightValue { Red, Orange, Green }
        public Dictionary<string, LightValue> Lights = new Dictionary<string, LightValue>();

        public int NumLights
        {
            get
            {return Lights.Count;}

        }

        public Semafor()
        {

        }
        private delegate void UpdateDelegate();

        public void Update(StisnuoEventArgs args)
      {
        .
        .
        .
       }
  SolidBrush blueBrush = new SolidBrush(Color.Cyan); //za crtanje forme
           

            W0 = (width - L * 2) / Lights.Count;
            W2 = W0 - W1 - B - D;

            Graphics G = e.Graphics;
            e.Graphics.FillRectangle(blueBrush, X, Y, width, height);

            foreach (KeyValuePair<string, LightValue> kvp in Lights)
            {                
                switch (kvp.Key)
                {
                    case "jupi":
                        {
                            SolidBrush orangeBrush = new SolidBrush(Color.Orange);
                            e.Graphics.FillRectangle(orangeBrush, X1, Y1, H1, W1);
                            X += space;

                             G.DrawString(kvp.Key, Font, new SolidBrush(ForeColor), new PointF(Left, Top));
                              // X += L;
                               X1 += W0;
                               Left += W0;
                               break;
                        }
                 
                        .
                        .        



Hvala jos jednom.



[ Mihajlo Cvetanović @ 30.11.2012. 14:40 ] @
Vidi da li ovo menja boju:

Code:
Sem.Lights["jupi"] = Semafor.LightValue.Green;
Sem.Invalidate();
[ TATATA @ 30.11.2012. 15:09 ] @
Ne menja :(
[ Mihajlo Cvetanović @ 30.11.2012. 15:29 ] @
Pitaj onog ko je napravio Semafor klasu da ti kaže kako se menja boja.
[ ravni @ 30.11.2012. 15:48 ] @
Citat:
Mihajlo Cvetanović:
Ravni, slažem se da u opštem slučaju može da se desi da neki pojmovi nemaju prevod, ali što se tiče jestivih delova piletine to bar postoji, čak ima i članak na vikipediji, sa sve slikom :)
Pa da, ali tu se Pandorina kutija tek otvorila. Sledece sto ce biti potrebno su imena procesne opreme, tipa onih pokretnih stvari sa kukama, pa razni nozevi i ostraci, pa zastitna odela.. Hocu da kazem da se retko kada isplati biti iskljuciv :)
[ plague @ 30.11.2012. 16:33 ] @
Mislim da ovaj deo menja boju:
Code (csharp):

                    case "jupi":
                        {
                            SolidBrush orangeBrush = new SolidBrush(Color.Orange);
                            e.Graphics.FillRectangle(orangeBrush, X1, Y1, H1, W1);
                            X += space;

                             G.DrawString(kvp.Key, Font, new SolidBrush(ForeColor), new PointF(Left, Top));
                              // X += L;
                               X1 += W0;
                               Left += W0;
                               break;
                        }
 

Hajde postavi ceo projekat, posto taj drugi deo koda koji si kopirala "visi" van funkcije, a sigurno nije tako.
[ TATATA @ 30.11.2012. 16:54 ] @
Taj kod se izvršava kada se pokrene forma.

Ne mogu na ovaj način da menjam boju (mogu, ali nema smisla) jer ću onda morati "peške" da unesem sve varijante , zato što u metodi FillRectangle moram da dam koordinate kvadrata. Kako imam 3 kvadrata sa po tri moguće boje, to je baš mnogo koda.
Ili, možda postoji neko jednostavnije rešenje?
[ plague @ 30.11.2012. 17:45 ] @
Ako je to zadatak, mozda zele da napises funkciju koja ce menjati boju?

U onom delu je napisano kako se inicijalizuje na te pocetne boje, iskoristi to da napises funkciju. Ili nam posalji ceo projekat da vidimo ima li takve funkcije vec ili ne.
[ Mare_TS @ 03.12.2012. 10:04 ] @
Prvo treba da setuješ novu vrednost u Dictionary Lights a potom da izvršiš explicitni update kontrole i to istom metodom kojom se i iscrtava grafik (Sem.Update())

Tako da probaj:
Citat:
Mihajlo Cvetanović: Vidi da li ovo menja boju:

Code:
Sem.Lights["jupi"] = Semafor.LightValue.Green;
Sem.Update()

Eventualno trebaš da se pozoveš Refresh na panelu (sem.Refresh()) da bi se ponovo iscrtao. Malo je nejasno definisana Update metoda u gornjem postu. ;)
[ Boyka @ 04.12.2012. 14:44 ] @
Vrhunac off-a je kad se tema o C#-u pretvori u temu o pilicima. lol

Najbolje bi bilo da okačiš taj projekat ovde...
[ TATATA @ 04.12.2012. 16:15 ] @
Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Semafor
{
    public partial class Form1 : Form
    {
        private Panel panel1;
        private TextBox LightBox;
        private TextBox NameBox;
        private Button GoBox;
        private Semafor Sem;

        public Form1()
        {
            InitializeComponent();
            Sem = new Semafor();
            Sem.Dock = DockStyle.Top;
            Sem.Lights.Add("jupi", Semafor.LightValue.Orange);
            Sem.Lights.Add("ipuj", Semafor.LightValue.Red);
            Sem.Lights.Add("piju", Semafor.LightValue.Green);           
            Push += new PushDelegate(Sem.Update);
            Controls.Add(Sem);

           
        }

        private void InitializeComponent()
        {
            this.panel1 = new System.Windows.Forms.Panel();
            this.GoBox = new System.Windows.Forms.Button();
            this.NameBox = new System.Windows.Forms.TextBox();
            this.LightBox = new System.Windows.Forms.TextBox();
            this.panel1.SuspendLayout();
            this.SuspendLayout();
            .
            .
            .

        }     

        public delegate void PushDelegate(PushEventArgs args);
        public event PushDelegate Push;

        private void OnPush(PushEventArgs args)
        {
            Console.WriteLine(args.ToString());
            if (Push != null)
            {
                Push(args);
            }
        }

        private void GoBox_Click(object sender, EventArgs e)
        {
            OnPush(new PushEventArgs(NameBox.Text, LightBox.Text));
        }

    }

    public class PushEventArgs : EventArgs
    {
        public string Name { get; set; }
        public string Light { get; set; }
        
        public PushEventArgs(string n, string l)
        { 
            Name = n;
            Light = l;
           
         }
        public override string ToString()
        {
            return "Name = " + Name + ", Light = " + Light;
        }
    }
}



namespace Semafor
{

    public class Semafor : Panel
    {
        public enum LightValue { Red, Orange, Green }
        public Dictionary<string, LightValue> Lights = new Dictionary<string, LightValue>();

        public int NumLights
        {
            get
            {return Lights.Count;}

        }

        public Semafor()
        {

        }
       
        private delegate void UpdateDelegate();
 
        public void Update(PushEventArgs args)
        {
            foreach (KeyValuePair<string, LightValue> kvp in Lights)
            {
                if (args.Name == kvp.Key)
                {                 
                   switch (args.Light)
                    {
                        case "Red":                            
                            Lights.Add(args.Name, Semafor.LightValue.Red);                                                   
                            break;
                        case "Green":
                            Lights.Add(args.Name, Semafor.LightValue.Green);                           
                            break;
                        case "Orange":
                            Lights.Add(args.Name, Semafor.LightValue.Orange); break;
                    }
                    break;
                }
                                                   
            }             
               if (InvokeRequired)
                    BeginInvoke(new UpdateDelegate(Invalidate));
                else
                    Invalidate();
                  
            }

        float X0 = 0.0F;
        float X = 0.0F;
        float Y = 0.0F;
        int width = 165;
        float height = 26.0F;
        int L = 3;
        float D = 3.0F;
        float B = 3.0F;
        int W0 = 0;
        float W2 = 0F;
        int space = 23;

        protected override void OnPaint(PaintEventArgs e)
        {

            float X1 = 3.0F;
            float Y1 = 3.0F;
            float W1 = 20.0F;
            float H1 = 20.0F;
            int Left = 24;
            int Top = 5;

            SolidBrush blueBrush = new SolidBrush(Color.Cyan);
           

                W0 = (width - L * 2) / Lights.Count;
            W2 = W0 - W1 - B - D;
            Graphics G = e.Graphics;
            e.Graphics.FillRectangle(blueBrush, X0, Y, width, height);

            foreach (KeyValuePair<string, LightValue> kvp in Lights)
            {                
                switch (kvp.Key)
                {
                    case "jupi":
                        {
                            SolidBrush orangeBrush = new SolidBrush(Color.Orange);
                            e.Graphics.FillRectangle(orangeBrush, X1, Y1, H1, W1);
                            X += space;

                             G.DrawString(kvp.Key, Font, new SolidBrush(ForeColor), new PointF(Left, Top));
                               X += L;
                               X1 += W0;
                               Left += W0;
                               break;
                        }
                    case "ipuj":
                       {
                        .
                        .
                        .
                        }
                    default:                        
                        {
                            SolidBrush orangeBrush = new SolidBrush(Color.Blue);
                            e.Graphics.FillRectangle(blueBrush, X1, Y1, H1, W1);
                            X += space;

                            G.DrawString("Error", Font, new SolidBrush(ForeColor), new PointF(Left, Top));
                            X += L;
                            X1 += W0;
                            Left += W0;
                            break;
                        }
                    }
            }
        }
    }
}

[ Mihajlo Cvetanović @ 05.12.2012. 09:53 ] @
Čudna mi je funkcija Semafor.Update: ako postoji ključ u rečniku onda dodaj još jedan taj ključ u rečnik. To će da baca exception. Umesto Lights.Add(x, y) u toj funkciji treba da stoji Lights[x] = y. Da li si ti pisala tu funkciju, ili ti je data? Šta se tačno desi kad klikneš na Go?
[ Mihajlo Cvetanović @ 05.12.2012. 10:06 ] @
E, da, glavna stvar, i verovatno rešenje za tvoje pitanje. Kada u Semafor.OnPaint treba da se iscrtaju svetla i stringovi ti imaš switch koji ispituje ključeve (stringove), i za svaki od tri hardkodovana stringa ti tu radiš odlučuvanje u kojoj boji svetla treba da budu. Za string koji nije jupi/piju biće prikazano plavo svetlo. Ti ne želiš to. Ti želiš da se boja svetla utvrdi na osnovu kvp.Value, i to treba da bude uslov switcha.
[ TATATA @ 05.12.2012. 10:14 ] @
Proveriću, pa ću javiti šta sam uradila.
[ Mihajlo Cvetanović @ 05.12.2012. 10:14 ] @
E, da, još jedna primedba. Ovu klasu Semafor po svemu sudeći ti praviš, a nije ti data. U klasi trenutno ne postoji način da se kontroliše redosled svetala. Foreach petlja nad rečnikom će ti dati sadržaj u nekom svom internom redosledu. Nekad će biti (jupi,ipuj,piju), nekad može biti nešto drugo. Možda će biti uvek isto, bilo kojim redosledom da popunjavaš rečnik. Prosto nemaš nekakve garancije u vezi sa redosledom. Ako želiš da kontrolišeš redosled prikaza svetala onda moraš prvo da skontaš kako to omogućiti u interfejsu, to jest šta korisnik klase treba da uradi da bi kontrolisao redosled svetala. Kad to skontaš onda ćeš morati i da prilagodiš kod u klasi.
[ Mare_TS @ 05.12.2012. 11:10 ] @
Izmeni Update, da kod dodavanja u kolekciju ispituje da li vec postoji key-value par i da radi add odnosno update tog para:
Code:
public void Update(PushEventArgs args)
        {
            foreach (KeyValuePair<string, LightValue> kvp in Lights)
            {
                if (args.Name == kvp.Key)
                {
                    switch (args.Light)
                    {
                        case "Red":
                            if (Lights[args.Name] == null)
                                Lights.Add(args.Name, Semafor.LightValue.Red);
                            else
                                Lights[args.Name] = Semafor.LightValue.Red;
                            break;
                        case "Green":
                            if (Lights[args.Name] == null)
                                Lights.Add(args.Name, Semafor.LightValue.Green);
                            else
                                Lights[args.Name] = Semafor.LightValue.Green;
                            break;
                        case "Orange":
                            if (Lights[args.Name] == null)
                                Lights.Add(args.Name, Semafor.LightValue.Orange);
                            else
                                Lights[args.Name] = Semafor.LightValue.Orange;                            
                            break;
                    }
                    break;
                }
            }
...


i ovo u OnPaint:
Code:
protected override void OnPaint(PaintEventArgs e)
        {

            ...

            foreach (KeyValuePair<string, LightValue> kvp in Lights)
            {                
                switch (kvp.Key)
                {
                    case "jupi":
                        {
                            SolidBrush orangeBrush = new SolidBrush(boja("jupi"));
                            ...
                        }
                    case "ipuj":
                        {
                            SolidBrush orangeBrush = new SolidBrush(boja("ipuj"));
                            ...
                        }
                    case "piju":
                        {
                            SolidBrush orangeBrush = new SolidBrush(boja("piju"));
                            ...
                        }

i dodaj u Semafor.cs na dnu:
Code:
private Color boja(string imeKvadratica)
        {
            Color b = Color.Black;
            switch (Lights[imeKvadratica])
            {
                case LightValue.Red:
                    b = Color.Red;
                    break;
                case LightValue.Green:
                    b = Color.Green;
                    break;
                case LightValue.Orange:
                    b = Color.Orange;
                    break;
            }
            return b;
        }


Trebalo bi da radi ;)
[ Mihajlo Cvetanović @ 05.12.2012. 11:36 ] @
Ne bih rekao da je to rešenje. Jupi i piju nisu boje nego samo neki stringovi, koje samo treba prikazati, i korisnik može da bira te stringove. Jupi stringovi ne smeju da postoje u kodu klase Semafor. Takođe, ovaj kod u funkciji Update može da bude elegantiji i kraći, i bez potrebe za petljom i svičem.

Code:
public void Update(PushEventArgs args)
{
  if (!Lights.ContainsKey(args.Name))
    return;

  if (!Enum.IsDefined(typeof(LightValue), args.Light)
    return;

  Lights[args.Name] = (LightValue)Enum.Parse(typeof(LightValue), args.Light);
}
[ TATATA @ 05.12.2012. 11:52 ] @
Mihajlo, Mare je rešio problem. Funkcioniše baš onako kako treba.
U pravu si, jupi i piju nisu boje, već labele pored kockica. Ali pomoću njih korisnik bira kojoj kockici će da promeni boju.

Hvala na savetima.
Pozdrav
[ Mare_TS @ 05.12.2012. 11:53 ] @
Ako ti tako kažeš, da ne kačim ceo projekat. :)

Evo samo da te podsetim šta piše u prvom postu
Citat:
Pravim formu u C# koja sadrži 3 kockice u razlicitim bojama (crvena, žuta, zelena), ime svake kockice, dva TextBox-a i button OK.

Na pocetku je zadato ime kockice i njena boja. Npr:
"prva" Green
"druga" Red
"treca" Yellow

ja ovde nigde ne vidim da piše da jupi i piju bira korisnik, ili možda grešim. Koliko sam ja skontao nije poenta da se napravi multifunkcionalna aplikacija već da ona pokaže da svoje poznavanje tehnologije (delegata, eventargova ...).

Ja sam postavio izmene NJENOG KODA koje treba da primeni, ja bi radio na neki drugi način sve ovo.
Skoro uvek može elegantnije, ali ovde nije to poenta. :)
[ Mihajlo Cvetanović @ 05.12.2012. 12:12 ] @
Tatata, trenutno ti radi, ali ako bi promenila jupi/piju stringove u konstruktoru od Form1 onda bi prestalo da radi. Treba samo da ukloniš switch(kvp.Key), jer je kod u svakoj case grani postao isti, a poziv funkcije boja trabe da bude boja(kvp.Key).