Postato originariamente da Sal47:
Ciao, ho scaricato il Carte2 e letto i tuoi commenti.
Ho capito che con Form1_Load vengono memorizzate le corrette posizioni finali delle 40 carte
(1^ riga denari, 2^ coppe, 3^ bastoni e 4^ spade). Dopo mescolo le carte e sposto una
x volta le carte e se (PB_OnMouseUp) vengono rimesse in posizione giusta (+/- margine)
(es. 3 coppe nella 3^ colonna della 2^ riga) lo spostamento va a buon fine altrimenti
il 3 di coppe ritorna automaticamente nella posizione iniziale e ListBox1.backcolor>red.
OK per il mescolamento delle carte e per la Verifica.
Bene
Postato originariamente da Sal47:
Ora però, a carte mischiate, devo farle apparire coperte e con 4 righe da 9 e 4 carte in basso
e procedere così nel solitario.
Esatto, è il tuo programma e con le info a disposizione dovresti riuscire a farlo appena avrai digerito l'esempio.
Postato originariamente da Sal47:
Sto provando a digerire il tuo codice. Ho bisogno di tempo.
Tra le tante istruzion/Sub riportate nel tuo codice vorrei capire in particolare:
- come si fa ad ottenere una istruzione valida ad es. per ciascuno dei 40 controlli tipo Label o Button
del mio caso senza ripetere l'istruzione stessa 40 volte come hai visto che ho fatto nel mio codice.
Da una dritta trovata on line mi sembrava che con istruzioni come quelle sotto
Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click,...,
Label3.Click, ... , Label40.Ckick
........
End Sub
e idem per le Sub tipo
Public Sub PictureBox1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown,
PictureBox2.MouseDown,..., PictureBox40.MouseDown,
.........
End Sub
E' un'altro sistema, ma comunque non adatto per 40 PictureBox con tre eventi...
Si può fare anche con Linq e non solo...
Postato originariamente da Sal47:
la cosa dovesse funzionare ma non è così e vedo che tu utilizzi "Sender" e una sola istruzione
Il metodo che ti ho proposto è il più adatto per scrivere un codice compatto per il tipo di programma che vuoi fare.
Stai programmando e sai che nelle variabili si possono inserire dei valori, dovresti anche sapere che ci sono gli Array (matrici), una matrice è una variabile con un indice:
Dim Matrice(3) as integer
Matrice(0) = 20
Matrice(1) = 32
Matrice(2) = 54
Matrice(3) = 99
l'indice è un numero e permette di esplorare tutti i valori della matrice usando i cicli for, ma non solo, l'indice può essere calcolato per raggiungere un valore con una logica matematica... Facile da capire e sicuramente lo sai.
Quello che potrebbe esserti sfuggito è che in VB.Net le matrici possono essere dichiarate per contenere qualsiasi oggetto, non solo numeri e lettere.
Nell'esempio che ti ho postato, ho dichiarato una matrice PB di PictureBox:
Dim PB(nColonne * nRighe) As PictureBox
cosa significa questo? Che in PB posso inserire 41 PictureBox distinte ognuna dal suo indice.
PB(1) (che contiene l'asso di denari) ha tutte le proprietà che hai gia usato in progettazione, quando hai inserito le PictureBox a mano una per una.
Dopo questa spiegazione dovrebbe esserti facile capire il frammento di codice che crea la PictureBox(0) (la carta coperta)
Option Explicit On
' creazione e posizionamento della carta coperta ID = 0
PB(ID) = New PictureBox ' una nuova picturebox
' dimensione picturebox in accordo con le immagini in imagelist
PB(ID).Size = ImageList1.ImageSize
' nel nome il nome della carta
PB(ID).Name = System.IO.Path.GetFileNameWithoutExtension(ImageList1.Images.Keys(0))
' immagine in accordo con l'indice, carta coperta in questo caso
PB(ID).Image = ImageList1.Images(ID)
' left calcolato e immesso in inf.L
inf.L = setL + gapL + ImageList1.ImageSize.Width
' top calcolato e immesso in inf.T (in fondo)
inf.T = setT + (gapT + ImageList1.ImageSize.Height) * (nRighe + 1)
' l'indice, zero per la carta coperta
inf.ID = ID
' uso i parametri per posizionare la picturebox
PB(ID).Top = inf.T
' uso i parametri per posizionare la picturebox
PB(ID).Left = inf.L
' NEL TAG TUTTI I PARAMETRI DI INTERESSE, servirà per recuperare i dati
PB(ID).Tag = inf
' al click del mouse viene eseguito il codice in PB_OnMouseDown
AddHandler PB(ID).MouseDown, AddressOf PB_OnMouseDown
' mentre si muove il mouse viene eseguito il codice in PB_OnMouseMove
AddHandler PB(ID).MouseMove, AddressOf PB_OnMouseMove
' quando si rilascia il mouse viene eseguito il codice in PB_OnMouseUp
AddHandler PB(ID).MouseUp, AddressOf PB_OnMouseUp
' Aggiungo la picturebox creata, nel Form
Me.Controls.Add(PB(ID))
PB(ID) = New PictureBox ' una nuova picturebox
è l'istruzione che crea la Picturebox e la immette all'indice ID, zero per la carta coperta.
Le proprietà: Size, Name, Image, Top, Left ti dovrebbero essere chiare, e ora sai che si possono leggere o scrivere anche da codice, non solo da progettazione.
Postato originariamente da Sal47:
- anche l'utilizzo di PB(ID).Tag = inf ' NET TAG TUTTI I PARAMETRI DI INTERESSE, ...
per PB(ID).Tag forse una spiegazione aggiuntiva è d'obbligo.
Il .Tag è una proprietà comune a tutti gli oggetti, ce l'ha il Form, le textbox , le label insomma tutto comprese le PictureBox. E' molto utile per parcheggiare informazioni utili riferite a quell'oggetto.
Se da progettazione nella PictureBox3 vai nella finestra delle proprietà e alla voce Tag scrivi ciao poi da codice scrivi:
Dim a as String = PictureBox3.Tag.ToString() ' in a trovi ciao
La particolarirà del Tag è che può contenere un oggetto non solo una stringa, un oggetto come detto prima può contenere qualsiasi cosa anche un form intero carico di strumenti.
nel nostro caso, nel Tag di ogni PictureBox ho inserito una Struct (inf). La Struct è composta da tre valori L, T, ID, quello che basta per portare a termine il tuo programma.
l' istruzione AddHandler crea l'evento
Me.Controls.Add(PB(ID)) aggiunge al Form la picturebox appena creata con tutte le proprietà impostate
nel ciclo dove creo le 40 PictureBox:
ID += 1
For r = 1 To nRighe
For c = 1 To nColonne
PB(ID) = New PictureBox
PB(ID).Size = ImageList1.ImageSize
PB(ID).Name = System.IO.Path.GetFileNameWithoutExtension(ImageList1.Images.Keys(ID))
PB(ID).Image = ImageList1.Images(ID)
inf.L = setL + (gapL + ImageList1.ImageSize.Width) * c
inf.T = setT + (gapT + ImageList1.ImageSize.Height) * r
inf.ID = ID
PB(ID).Top = inf.T
PB(ID).Left = inf.L
PB(ID).Tag = inf
AddHandler PB(ID).MouseDown, AddressOf PB_OnMouseDown
AddHandler PB(ID).MouseMove, AddressOf PB_OnMouseMove
AddHandler PB(ID).MouseUp, AddressOf PB_OnMouseUp
Me.Controls.Add(PB(ID))
ID += 1
Next
Next
calcolo la coordinata di colonna Left e quella di riga Top con due somme e una moltiplicazione le immetto in inf.L e inf.T insieme a inf.ID e poi nel Tag per poterle recuperare quando serve.
Con questo approcio non mi devo segnare a mano tutte le coordinate delle PictureBox e immetterle in una tabella per confrontarle con la posizione della carta quando si muove per vedere se è in posizione.
Infatti quando creo le coordinate le copio anche nel tag, in modo che ogni volta che clicco la carta so dove deve stare, e confrontando con dove sta, so se sta a posto.
Per il sender credo che hai capito, per esempio nel ciclo for abbiamo attivato 40 eventi MouseDown, significa che se clicco una PictureBox qualsiasi, il codice relativo si attiva e in
Object sender mi ritrovo tutta la PictureBox cliccata, la conversione da Object a PictureBox è consigliata anche se VB.Net lo farebbe d'ufficio.
Come hai visto, usando il sender si usa sempre lo stesso codice invece di riscriverlo.
Se ancora non riesci, a carte mischiate a farle apparire coperte e con 4 righe e 9 colonne con 4 carte in basso, fammelo sapere.