playing cards images display problem

hi, I'm writing a simple bridge(cards) application using Windows Forms C++ (VS2008)
Dealing hands, sorting within hands work fine. To display the images i'm using a dynamic array of PictureBox'es, but when im trying to display it it displays only ONCE (like the second, third display would have been "shadowed" by the first display...
Here are the main parts of my code...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//function to display the shuffled deck
array<String^>^ cards = gcnew array<String^> {"2","3","4","5","6","7","8","9","D","J","Q","Y","Z",
//4x 2,3,4,...Y,Z to represent 2 of clubs, 3 of clubs....king of spade, ace of //spade
Random^ random = gcnew Random();

for(int i=0;i<player->Length;i++)
{
  number = random->Next(0,52);  
  if(valid[number]==false)     //bool'ean array to check if number was already picked
  {
    player[i]=cards[number];
    gracz[i]=number;           //this will help me later, to display images
    valid[number]=true;
    if(number<13)
     tempClub[i]=player[i];   //temp arrays to display cards as strings
    else if(number>=13 && number<26)
     tempDiamond[i]=player[i];
    else if(number>=26 && number<39)
     tempHeart[i]=player[i];
    else
    tempSpade[i]=player[i];
  }
  else
  {
    do{
	number = random->Next(0,52);
      }while(valid[number]==true);

    player[i]=cards[number];
    gracz[i]=number;
    valid[number]=true;
    if(number<13)
     tempClub[i]=player[i];
    else if(number>=13 && number<26)
     tempDiamond[i]=player[i];
    else if(number>=26 && number<39)
     tempHeart[i]=player[i];
    else
    tempSpade[i]=player[i];
  }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
//function:displaying cards(as strings) in labels
Array::Sort(temp);
Array::Reverse(temp);
for(int i=0;i<temp->Length;i++)
 {
  if(temp[i]=="Z")
   temp[i]="A";
  if(temp[i]=="Y")
   temp[i]="K";
  if(temp[i]=="D")
   temp[i]="10";
  label->Text = label->Text + temp[i] + " ";
  }
//everything works fine till now... 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//and now the problem with displaying the cards as images
//notice in the 1st code part -> gracz[i]=number (look above)
Array::Sort(gracz);
for(int i=0;i<gracz->Length;i++)
{
   //im creating a dynamic array of PictureBox'es
   //like array<PictureBox^>^ PB = gcnew etc
   PB[i] = gcnew System::Windows::Forms::PictureBox();
   PB[i]->Location = System::Drawing::Point(400-(i*15), 250)
   PB[i]->Size = System::Drawing::Size(71, 96);
   PB[i]->Tag = Convert::ToString(gracz[i]);
   PB[i]->Image = (cli::safe_cast<System::Drawing::Image^   >(this->imageList->Images[gracz[i]] ));
   this->Controls->Add(PB[i]);
}



So everything works fine except that 3rd part, hands are being generated
after button click, on first click cards (as strings in labels) are being
displayed + one hand is being displayed as images...
Then after next(and next) click only the strings are changing(new deal) but
the image representation doesnt change...

Note: the image representation is the same as string representation (so it seems to be working), only doesnt change during button click

I hope my msg wasnt really confusing,
thx for any remarks,
John Kravetzki

P.S.
if some1 felt confused with that what i wrote here i post a link with
exe file of my app:
http://www.dajeciala.strefa.pl/i/bridgeGenerator.exe
I hope posting links with exe's isnt bannable here? (i need to read the forum regulations:()
Last edited on
OK we see what you mean.
Can you post a link to the project CPP and Header files?
Ok, here it is:
http://www.dajeciala.strefa.pl/i/bridgeGenerator.rar

btw, I deleted some minor functions and features (which werent the issue)

thx in advance,
JK
Last edited on
Your code is works and it doesn't work at the same time.
What is happening is that each time the generate button is clicked, you do get new cards.
These new cards are displayed UNDERNEATH the previous cards! because they are
lower in the Z-order.

If you change the Display_Images function to this you will see what I mean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Display_images(array<PictureBox^>^ PB, array<int>^ gracz, int modyfikator)
{        
    static int pos = 1100; //added by guestgulkan

    Array::Sort(gracz);
    for(int i=0;i<gracz->Length;i++)
    {
				     
    PB[i] = gcnew System::Windows::Forms::PictureBox();
    PB[i]->Location = System::Drawing::Point(pos -(i*modyfikator), 259+modyfikator);//amended by Guestgulkan
    PB[i]->Size = System::Drawing::Size(71, 96);
    PB[i]->Tag = Convert::ToString(gracz[i]);
    PB[i]->Image = (cli::safe_cast<System::Drawing::Image^  >(this->imageList->Images[gracz[i]] ));        
    this->Controls->Add(PB[i]);
    pos-= 20; //added by Guestgulkan

    /textBox to display the "numbers" after "button click"
    textBox1->Text = textBox1->Text + Convert::ToString(gracz[i]) +",";
}
}


So we need to get rid of the old images first.
Last edited on
that's right, I even placed that textBox
 
textBox1->Text = textBox1->Text + Convert::ToString(gracz[i]) +",";

to make sure these images are displayed under the previous ones....
atm im working out how to erase those previous images...
thx very much for your latest advice Guestgulkan
JK

P.S. I need to learn about Dispose() method .... it may help to work it out
Last edited on
Your problem is really a simple one.
The array<PictureBox^>^ PB variable is created in the function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private: System::Void Generate_Click(System::Object^  sender, System::EventArgs^  e)
{
.
.
.
array<PictureBox^>^ PBW = gcnew array<PictureBox^>(13);//<<< Doing this here is a problem
.
.
Generate_cards(playerW, tempW_spade, tempW_heart, tempW_diamond, tempW_club, IsValid, graczW);
Display_images(PBW,graczW,modyfikatorW);
Display_cards(tempW_spade, WEST_SPADE);
.
.
}

This means that after you call Display_Images and return and the Generate_Click function finishes, then the pointer is lost and you will have a bit of a hard time to get rid of the previous images.


The solution is simple:
Make the array<PictureBox^>^ PBW array last for the life time of the Form by making it
a property of the form and initialise it in the constructor.
So we remove one line of code and add 3 lines like this.

1. get rid of the array from the Generate_Click function.
2. Amend the Form like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public ref class Form1 : public System::Windows::Forms::Form
{
    public:
		
  array<PictureBox^>^ PBW; //Add this line - I show it as public but may be better as protected or private.

    
    Form1(void)
   {
      
      InitializeComponent();
       //
       //TODO: Add the constructor code here
      //
      PBW = gcnew array<PictureBox^>(13);//Add this line in the constructor
      }

     protected:
/// <summary>
.
.

// 



3. Add one line to the Display_Images function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Display_images(array<PictureBox^>^ PB, array<int>^ gracz, int modyfikator)
{
     Array::Sort(gracz);
     
     for(int i=0;i<gracz->Length;i++)
			{        
        //remove old pic
        this->Controls->Remove(PB[i]); //Add this line
        //create/show new one
        PB[i] = gcnew System::Windows::Forms::PictureBox();
       PB[i]->Location = System::Drawing::Point(1100 -(i*modyfikator), 259+modyfikator);
       PB[i]->Size = System::Drawing::Size(71, 96);
       PB[i]->Tag = Convert::ToString(gracz[i]);
       PB[i]->Image = (cli::safe_cast<System::Drawing::Image^  >(this->imageList->Images[gracz[i]] ));

        this->Controls->Add(PB[i]);

         //textBox to display the "numbers" after "button click"
       textBox1->Text = textBox1->Text + Convert::ToString(gracz[i]) +",";
     }
}
wow I'm blind - you opened my eyes :)
Now it works fine, great thx Guestgulkan...
btw... I dont't know if you are familiar in cards stuff, but surely you are in cpp.
What do you think... is my shuffling alghoritm effective ? (talking about displaying the cards within the labels)...
The only problem is that I'm picking the cards for one player, the others wait for its turn till his hand is filled...
In real life we are assigning only one card to each player every turn...

I think that the card layout probability distibution is a bit other in my alghoritm, but still very similar (4432 distribution come out mostly, then 4333, 5332, 5422, 5521 etc)

Anyway, thx again
JK
it has to be equal, i ran a test for 100,000 different distributions...
e.g. 4333 appearance probability on 1 hand is 10,4% (100k loops)
and "by book" (or you can just count it using combinatory formulas) it is 10,52%
I remember there being a card deck shuffling routine somewhere on the web.
I'll see if I can find it again.
I've been told by my friend (math student) that both ways of picking the cards return the same probability distribution for card layouts...

Im dealing now with event handlers attached to those images (mouseenter, mouseleave)

I was wondering if there is any trick to do it effectively rather than making 52 separate functions for each card image (picturebox from pb array)

something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PB_WEST[0]->MouseEnter += gcnew System::EventHandler(this, &Form1::PB_WEST_ENTER);
PB_WEST[0]->MouseLeave += gcnew System::EventHandler(this, &Form1::PB_WEST_LEAVE);

//etc EAST,NORTH till PB_SOUTH[12]

//...

private: System::Void PB_WEST_ENTER(System::Object^  sender, System::EventArgs^  e)
		 {
			 PB_WEST[0]->Location = System::Drawing::Point(700,290);
		 }
private: System::Void PB_WEST_LEAVE(System::Object^  sender, System::EventArgs^  e)
		 {
			 PB_WESTW[0]->Location = System::Drawing::Point(700,300);
		 }
//etc
Sorry that I didn't answer your question, but in the array cards, why use an array of strings when you can represent each card with a single character?
Last edited on
ok i've done it... first i initialize handlers for each picturebox in P-box array
1
2
3
4
5
6
7
8
void ImagesEventHandler(array<PictureBox^>^ PB)
                {       
                        for(int i=0;i<13;i++)
                        {
                                PB[i]->MouseEnter += gcnew System::EventHandler(this, &Form1::PB_ENTER);
                                PB[i]->MouseLeave += gcnew System::EventHandler(this, &Form1::PB_LEAVE);
                        }               
                }

Then i'm "attaching" these handlers to those P-Box array elements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private: System::Void PB_ENTER(System::Object^  sender, System::EventArgs^  e)
                 {                       
                         for(int i=0;i<13;i++)
                         {
                                 if(sender==PBW[i])
                                        PBW[i]->Location = System::Drawing::Point(700-(i*15),290);
                         }

                 }
private: System::Void PB_LEAVE(System::Object^  sender, System::EventArgs^  e)
                 {
                         for(int i=0;i<13;i++)
                         {
                                 if(sender==PBW[i])
                                        PBW[i]->Location = System::Drawing::Point(700-(i*15),300);
                         }
                 }


@Kiana - yes, you're right - i'm not used to cpp/cli yet, anyway its only several bytes waste or so...
Topic archived. No new replies allowed.