Introduzione.
Nel primo articolo si è visto come disegnare una tabella e si è realizzato un semplice gioco ossia quello del campo fiorito, in questa seconda parte verrà affrontata la creazione di un semplice foglio di calcolo.
Nell'articolo precedente, si è vista una funzione che disegnava una semplice tabella nel cntrolo PictureBox, la riporto qui per comodità
Public Sub disegnatabella()
Dim x As Integer
Dim y As Integer
Dim stepx As Integer
Dim stepy As Integer
Dim maxx As Integer
Dim maxy As Integer
stepx = 250
stepy = 600
maxx = miapic.Width
maxy = miapic.Height
'disegna linee verticali e orizzontali
For x = 0 To maxx Step stepx
miapic.Line (0, x)-(maxx, x)
Next x
For y = 0 To maxx Step stepy
miapic.Line (y, 0)-(y, maxy)
Next y
End Sub
Come si puo vedere nella funzione, vengono disegnate delle righe in orizzontale e verticale in modo tale da far sembrare che la nostra applicazioni abbia una griglia.
Per la creazione di un semplice foglio di calcolo pero occorre un metodo con il quale l'utente possa orientarsi nella tanella per cui la prima modifica alla nostra funzione è quella di scrivere in concomitanza delle righe dei numeri e delle colonne delle lettere, in maniera da identificare una cella in modo univoco da parte dell'applicazione e dell'utente del programma.
Per fare questo si utilizza la funzione DrawText già vista nel primo articolo.
La funzione modificata è la eguente:
Public Sub disegnatabella()
Dim x As Integer
Dim y As Integer
Dim stepx As Integer
Dim startx As Integer
Dim stepy As Integer
Dim starty As Integer
Dim maxx As Integer
Dim maxy As Integer
Dim crighe As Integer
Dim r As RECT
stepx = 600
stepy = 250
maxx = miapic.Width
maxy = miapic.Height
'disegna linee verticali
For x = 0 To maxx Step stepy
miapic.Line (0, x)-(maxx, x)
Next x
For y = 0 To maxx Step stepx
miapic.Line (y, 0)-(y, maxy)
Next y
starty = stepy
'disegna numeri righe
crighe = 1
For y = starty To maxy Step stepy
r.Top = ScaleY(y, vbTwips, vbPixels)
r.Bottom = r.Top + ScaleY(stepy, vbTwips, vbPixels)
r.Left = ScaleX(0, vbTwips, vbPixels)
r.Right = r.Left + ScaleX(stepx, vbTwips, vbPixels)
DrawText miapic.hdc, Str$(crighe), Len(Str$(crighe)), r, 0
crighe = crighe + 1
Next y
crighe = 1
startx = stepx
For x = startx To maxx Step stepx
r.Top = 0
r.Bottom = ScaleX(stepx, vbTwips, vbPixels)
r.Left = ScaleX(x, vbTwips, vbPixels) + 20
r.Right = r.Left + ScaleX(x, vbTwips, vbPixels)
DrawText miapic.hdc, Chr$(crighe + 64), Len(Chr$(crighe + 64)), r, 0
crighe = crighe + 1
Next x
End Sub
Adesso abbiamo una tabella molto semplice che identifica ogni cella.
Ora bisogna naturalmente creare un struttura adatta a contenere i dati e ad identificare una cella in maniera univoca.
Nei programmi di foglio di calcolo piu conosciuti come Exel della Microsoft o come Calc di OpenOffice, lo scorrimento in orizzontale e in verticale dell' interfaccia sembra non abbia limite, ma senzadubbio la struttura degli stessi che serve al programma per contenere i dati non è sicuramente dimensionata in base alle operazioni di scorrimento orizzontali e verticale fatte dall'utente che li utilizza è più probabile pensare che la struttura interna di un programma di questo tipo sia dinamica e che contenga soltanto i dati delle celle che vengono realmente utilizzati dall'utente.
Proviamo ad aprie per esempio Calc di OpenOffice e scorriamo la nostra finestra in basso,

come si puo vedere dall'immagine man mano che l'utente scorre in basso la finestra di lavoro il programma continua ad aumentare il numero che corrisponde alle righe, cio non significa che il programma gestisca maggiore memoria o meglio riservi memoria aggiuntiva quando l'utente scorre in basso o orizzontalmente la griglia.
E' molto più probabile che Calc ed Exel riservino memoria soltanto quando l'utente inserisce in una o piu celle i propri dati.
Quindi bisogna creare una struttura gestita in maniera dinamica in cui un elemento è inserito in conseguenza dell'azione di inserimento in una cella e eliminato in corrispondenza dell'azione di cancellazione dell'utente di una cella.
Per fare in modo di effettuare l'operazione di un programma come Calc di OpenOffice occorre sostanzialmente una variabile che viene aumentata ogni qual volta che l'utente scorri la finestra di lavoro in basso e in orizzontale, per quanto riguarda l'identificazione delle colonne si puo osservare nell'mmagine sottostante come OpenOffice fermi lo scorrimento orizzontale verso destra con il valore AMJ, cio significa che una volta finito l'alfabeto inglese, il programma per indentificare la successiva colonna disegni una doppia lettera "AA" e le successive attraverso la combinazione dell'alfabeto ossia "AB" , "AC" , "AD" , "AE" etc.. ed una volta che si sono esaurite le combinazioni dell'alfabeto di due lettere inizi a stampare le combinazione in tre lettere, e infine termini la visualizzazione dell'interfaccia come si puo osservare in figura.
Per identificare l'ultima cella del programma AMJ in corrispondenza della prima riga quindi, il programma Calc dovra contenere nella struttura dei dati l'identificazione della colonna AMJ della riga 1 ossia "AMJ-1".
Prima di tutto modifichiamo la funzione che stampa la nosta finestra in modo tale da dare l'impressione all'utente che l'area di lavoro sia scorrevole.
La struttura del nostro esempio quindi dovrà anch'essa contenere l'identificativo delle righe in numeri, quello delle colonne come combinazione dell'alfabeto inglese e una stringa che contenga i dati inseriti all'interno della cella dall'utente.
Visto che la nostra applicazione è soltanto un esempio, per comodità daremo un limite al numero i righe e un limite al numero delle colonne in modo tale da concentrare l'attenzione su altri aspetti come quello dell'inserimento di dati nel nostro semplice foglio di calcolo.
Prima di tutto identifichiamo la struttura che contiene i dati immessi dall'utente:
Type cella
nriga As Integer
ncolonna As Integer
valore As String
End Type
Dim foglio() As cella
Global ncelle as Integer
La struttura cella contiene la descrizione della riga e della colonna di tipo integer mentre la variabile valore contiene la
stringa immessa all'interno dell'applicazione.
la variabile foglio invece identifica l'intero foglio e non è dimensionata.
Quando verrà inserito un dato dall'utente infatti, la variabile foglio verrà ridimensionata preservando i dati finora inseriti attraverso un'istruzione redim preserve, l'indice globale all'applicazione serve a questo ossia a tenere traccia del numero delle celle che l'utente ha occupato inserendo o modificando il foglio di lavoro.
Nauralmente per identificare una cella si utilizza la seguente sintassi:
foglio().nriga=
foglio().ncolonna=
foglio().valore=
dove indice rappresenta il numero della cella in memoria e ncolonna e nriga identifica una cella il cui valore sotto forma di stringa è cotenuto nella variabile valore.
All'interno del nostro esempio non vi è la possibilità di lavorare con piu fogli di lavoro ma nei normali programmi come Exel vi sono già quando si apre un nuovo progetto più fogli , se volessimo anche noi in questo esempio utilizzare piu fogli di calcolo allora dovremmo modificare la struttura creata in questa maniera:
Type cella
nriga As Integer
ncolonna As Integer
valore As String
End Type
Type foglio
celle() As cella
End Type
Dim fogli() As foglio
Global nfolgi As Integer
Nel codice sopra vi è una struttura aggiunta chiamata foglio che identifica un singolo foglio di lavoro i cui campi sono ncelle di tipo Integer che tiene traccia del numero delle celle del foglio e il campo celle non dimensionato che contiene la posizione in righe e colonne delle celle e la stringa della cella inserita.
La variabile fogli identifica un array non dimensionato di tipo foglio in modo tale da poter lavorare con piu fogli anche se lo scopo dell'esempio non necessita di una struttura di questo tipo, manterro questo codice nell'applicazione.
Il codice della struttura è stato inserito all'interno di un modulo in modo tale da essere visibile a tutta l'applicazione.
Nell'immagine sottostante si puo vedere come ho strutturato l'applicazione del mio foglio di calcolo:

Modifichiamo di nuovo la funzione che disegna la tabella in modo da far partire il disegno delle righe e delle colonne da una posizione iniziale:
Public Sub disegnatabella(ByVal righe As Integer, ByVal colonne As Integer)
Dim x As Integer
Dim y As Integer
Dim stepx As Integer
Dim startx As Integer
Dim stepy As Integer
Dim starty As Integer
Dim maxx As Integer
Dim maxy As Integer
Dim crighe As Integer
Dim r As RECT
stepx = 600
stepy = 250
maxx = miapic.Width
maxy = miapic.Height
'disegna linee verticali
For x = 0 To maxx Step stepy
miapic.Line (0, x)-(maxx, x)
Next x
For y = 0 To maxx Step stepx
miapic.Line (y, 0)-(y, maxy)
Next y
starty = stepy
'disegna numeri righe
crighe = righe
For y = starty To maxy Step stepy
r.Top = ScaleY(y, vbTwips, vbPixels)
r.Bottom = r.Top + ScaleY(stepy, vbTwips, vbPixels)
r.Left = ScaleX(0, vbTwips, vbPixels)
r.Right = r.Left + ScaleX(stepx, vbTwips, vbPixels)
DrawText miapic.hdc, Str$(crighe), Len(Str$(crighe)), r, 0
crighe = crighe + 1
Next y
crighe = colonne
startx = stepx
For x = startx To maxx Step stepx
r.Top = 0
r.Bottom = ScaleX(stepx, vbTwips, vbPixels)
r.Left = ScaleX(x, vbTwips, vbPixels) + 20
r.Right = r.Left + ScaleX(x, vbTwips, vbPixels)
DrawText miapic.hdc, Chr$(crighe + 64), Len(Chr$(crighe + 64)), r, 0
crighe = crighe + 1
Next x
End Sub
la funzione adesso si deve associare all'evento delle barre orizzontali e verticali nel modo seguente:
Private Sub miascrollo_Change()
disegnatabella miascrollv.Value, miascrollo.Value
End Sub
Private Sub miascrollv_Change()
disegnatabella miascrollv.Value, miascrollo.Value
End Sub
A questo punto si avrà l'impressione che la nostra tabella si muova verticalmente ed orrizzontalmente.
Identificare una cella in base al click del mouse.Adesso che la nostra applicazione sembra scorrere anche se in efetti vien soltanto ridisegnata attraverso un indice che si incrementa e decrementa,passiamo ad identificare una casella o cella quando l'utente clicca sul controllo PictureBox.
La funzione da utilizzare è la seguente:
Private Sub miapic_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
Dim px As Integer
Dim py As Integer
Dim X1 As Integer
Dim Y1 As Integer
If (Button = 1) Then
If (nfinestra = 1) Then 'prato fiorito
px = x / 250
py = y / 250
If (prato(px, py) = 10) Then
MsgBox "spiacebte gioco finito hai trovato un fiore", vbExclamation, "miocampofiorito",
finegioco
Else
coperto(px, py) = False
For X1 = 0 To 10
For Y1 = 0 To 10
visitato(X1, Y1) = False
Next Y1
Next X1
If (prato(px, py) = 0) Then
mossa px, py
End If
disegnacampo
f (vinto) Then
MsgBox "complimenti hai vinto...";, vbExclamation,"miocampofiorito";
End If
End If
End If
If (nfinestra = 2) Then 'foglio di calcolo
px = x / 600
py = y / 250
cellax = x / 600 + miascrollo.Value - 1
cellay = y / 250 + miascrollv.Value - 1
disegnacella px, py
End If
End If
End Sub
Qusta funzione come si puo vedere contiene giù del codice che serviva ad intercettare la pressione del tasto del mouse per il programma del campo fiorito visto nel primo articolo.
La funzione contiene una semplice variabile che ci indica se stiamo giocando al campo fiorito o se stiamo utilizzando il nostro piccolo foglio di calcolo . Nel caso in cui stiamo utilizzando il foglio di calcolo,nfinestra è = a 2 e px e py contiene il numero della cella in base allo spostamento attuale della finestra.
Adesso non ci resta che creare la funzione che disegna la tabella in modo da evidenziare la cella cliccata dall'utente.
Public Sub disegnacella(ByVal x As Integer, ByVal y As Integer)
Dim startx As Integer
Dim starty As Integer
startx = x * 600
starty = y * 250
Rectangle miapic.hdc, ScaleX(startx, vbTwips, vbPixels) + 2, ScaleY(starty, vbTwips, vbPixels) + 2, ScaleX(startx + 600 - 2, vbTwips, vbPixels), ScaleY(starty + 250 - 2, vbTwips, vbPixels)
End Sub
Ogni volta che andro a cliccare su una cella, la stessa verrà evidenziata.
Inserimento dati in una cella.Adesso dobbiamo inserire i dati di una cella e visualizzarli.
Per fare questo in maniera semplice creiamo un form e lo utilizziamo quando l'utente esegue un doppio click del mouse all'interno di una cella in modo tale da lanciare il form per l'inserimento del dato.
il codice del doppio click è il seguente:
Private Sub miapic_DblClick()
frminsert.Show vbModal
inserisci cellax, cellay, frminsert.getval
End Sub
La funzione inserisci andrà a modificare la struttura del nostro foglio di lavoro e ad inserire la stringa inserita dall'utente.
Public Sub inserisci(ByVal x As Integer, ByVal y As Integer, ByVal val As String)
If (val = "") Then
Exit Sub
End If
fogli(1).ncelle = fogli(1).ncelle + 1
ReDim Preserve fogli(1).celle(fogli(1).ncelle)
'inserimento dati
fogli(1).celle(fogli(1).ncelle).nriga = y
fogli(1).celle(fogli(1).ncelle).ncolonna = x
fogli(1).celle(fogli(1).ncelle).valore = val
End Sub
A questo punto modifichiamo ulteriormente la nostra funzione disegnatabella in modo tale da visualizzare in ogni cella il valore inserito se presente.
La funzione modificata è la seguente:
Public Sub disegnatabella(ByVal righe As Integer, ByVal colonne As Integer)
Dim x As Integer
Dim y As Integer
Dim stepx As Integer
Dim startx As Integer
Dim stepy As Integer
Dim starty As Integer
Dim maxx As Integer
Dim maxy As Integer
Dim crighe As Integer
Dim r As RECT
miapic.Cls
stepx = 600
stepy = 250
maxx = miapic.Width
maxy = miapic.Height
'disegna linee verticali
For x = 0 To maxx Step stepy
miapic.Line (0, x)-(maxx, x)
Next x
For y = 0 To maxx Step stepx
miapic.Line (y, 0)-(y, maxy)
Next y
starty = stepy
'disegna numeri righe
crighe = righe
For y = starty To maxy Step stepy
r.Top = ScaleY(y, vbTwips, vbPixels)
r.Bottom = r.Top + ScaleY(stepy, vbTwips, vbPixels)
r.Left = ScaleX(0, vbTwips, vbPixels)
r.Right = r.Left + ScaleX(stepx, vbTwips, vbPixels)
DrawText miapic.hdc, Str$(crighe), Len(Str$(crighe)), r, 0
crighe = crighe + 1
Next y
crighe = colonne
startx = stepx
For x = startx To maxx Step stepx
r.Top = 0
r.Bottom = ScaleX(stepx, vbTwips, vbPixels)
r.Left = ScaleX(x, vbTwips, vbPixels) + 20
r.Right = r.Left + ScaleX(x, vbTwips, vbPixels)
DrawText miapic.hdc, Chr$(crighe + 64), Len(Chr$(crighe + 64)), r, 0
crighe = crighe + 1
Next x
'disegna il valore di una cella se presente
For x = 1 To fogli(1).ncelle
If (fogli(1).celle(x).ncolonna >= colonne And fogli(1).celle(x).nriga >= righe) Then
startx = fogli(1).celle(x).ncolonna * stepx - colonne * stepx + stepx
starty = fogli(1).celle(x).nriga * stepy - righe * stepy + stepy
r.Top = ScaleY(starty, vbTwips, vbPixels)
r.Bottom = r.Top + ScaleY(stepy, vbTwips, vbPixels)
r.Left = ScaleX(startx, vbTwips, vbPixels)
r.Right = r.Left + ScaleX(stepx, vbTwips, vbPixels)
DrawText miapic.hdc, fogli(1).celle(x).valore, Len(fogli(1).celle(x).valore), r, 0
End If
Next x
End Sub
Quando l'utente inserisce con il doppio click un valore di una cella lo stesso verrà visualizzato in corrispondenza della medesima dando maggiormente l'impressione che la nostra finestra sia dinamica.
La seconda parte dell'articlo si conclude qui.