JavascriptProva

giovedì 30 agosto 2012

Soluzione per il fatto che la procedura template accetta solo il costruttore di default

Bene... per i miei scopi, non devo fare in modo che il testo della mia casella venga definito nel costruttore, perchè la creazione della nuova istanza, e quindi la chiamata del costruttore, è immediata, e definendo nell'ambito del costruttore che il testo debba essere uguale alla proprietà Dati, questa proprietà è ancora pari a una stringa vuota, in quanto la procedura template la "riempie" dopo che l'istanza è stata creata, e quindi solo dopo che il costruttore è entrato in azione.

Lascio quindi il costruttore di default sottinteso (ossia non specifico costruttori nella classe), e creo un metodo che viene chiamato dopo.
Ci provo...Creo due classi, la prima "casella" che eredita da Label, la seconda "calendario", in cui voglio che il testo rispecchi il valore della proprietà Dati, che eredita da "casella".
Class casella
    Inherits Label
    Protected Dati As Date
    Sub New()
        BorderStyle = BorderStyle.FixedSingle
    End Sub
    Overridable Sub scriviDati(ByVal dato As String)
        Dati = dato
    End Sub
End Class

Class calendario
    Inherits casella
    Overrides Sub scrividati(ByVal dato As String)
        Dati = dato
        Text = Dati
    End Sub
End Class
Il metodo scriviDati è overridable, in modo che nella classe genitrice compila solo il valore della proprietà, mentre nella classe derivata compila anche il testo con il valore della proprietà.

Ecco la procedura template:
    Sub popola(Of oggetto As New)(ByVal frm As Form, ByVal dt As Object)
        Dim obj As Object
        For n = 0 To dt.Length - 1
            obj = New oggetto
            With obj
                .left = 0
                .top = obj.height * (n Mod dt.Length)
                .scriviDati(dt(n))

            End With
            frm.Controls.Add(obj)
        Next
    End Sub
...che esegue sempre la funzione scriviDati, la quale, se il tipo di oggetto fornito alla procedura template è "casella" compila soltanto il valore della proprietà Dati, mentre se il tipo di oggetto fornito alla procedura template è "calendario", fa apparire anche questo valore come testo.

Funziona!

Mi sbizzarrisco un po', traendo le conclusioni logiche più tardi...
Class casella
    Inherits Label
    Protected Dati As Date
    Sub New()
        BorderStyle = BorderStyle.FixedSingle
    End Sub
    Overridable Sub scriviDati(ByVal dato As String)
        Dati = dato
    End Sub
End Class

Class calendario
    Inherits casella
    Sub New()
        BorderStyle = BorderStyle.Fixed3D
        BackColor = Color.Green
    End Sub
    Overrides Sub scrividati(ByVal dato As String)
        Dati = dato
        Text = Dati
    End Sub
End Class
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        popola(Of calendario)(0, Me, giorniDelMese(8, 2012))
        popola(Of casella)(100, Me, giorniDelMese(8, 2012))
    End Sub
    Sub popola(Of oggetto As New)(ByVal sinistra As Integer, ByVal frm As Form, ByVal dt As Object)
        Dim obj As Object
        For n = 0 To dt.Length - 1

            obj = New oggetto
            With obj
                .left = sinistra
                .top = obj.height * (n Mod dt.Length)
                .scriviDati(dt(n))

            End With
            frm.Controls.Add(obj)
        Next
    End Sub
Ed ecco cosa ottengo:

Procedure template che usano costruttori non di default?... Boh?

Adesso utilizzo una procedura template per istanziare un oggetto di classe classe derivata da Label
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        procedura(Of classe)()
    End Sub
    Sub procedura(Of T As New)()
        Dim a As Object
        a = New T
        Me.Controls.Add(a)
        a.Left = 0
    End Sub
All'evento Load del form viene chiamata la procedura template (chiamata, con molta fantasia, procedura), che usa il costruttore di default, e la cosa funziona: ottengo un'etichetta rossa a left=0.
Ora vediamo se è possibile usare il secondo costruttore...

Credo che sia impossibile! Ho googlato come un matto ma sembra che le procedure generiche, o template, non possano chiamare se non il costruttore di default...

Preparazione alla creazione di una procedura template che istanzi una classe con più costruttori

Voglio costruire una procedura template fatta bene, che utilizzi più costruttori di una classe.
Creo un nuovo programmino di sana pianta per esercitarmi...

Costruisco una classe che eredita da Label:
Class classe
    Inherits Label
    Sub New()
        BackColor = Color.Red
    End Sub
    Sub New(ByVal stringa As String)
        BackColor = Color.Cyan
    End Sub
End Class
Questa classe possiede due costruttori (overloading dei costruttori, ricordiamo dal C++): uno senza parametri, che dà alla casella un colore rosso, e uno con un parametro stringa che dà alla casella un colore celeste.
Istanzio la classe con i due costruttori e aggiungo i controlli al Form, con una diversa proprietà left perchè non si sovrappongano:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim cl As Object

        cl = New classe()
        Me.Controls.Add(cl)
        cl.left = 0

        cl = New classe("uh")
        Me.Controls.Add(cl)
        cl.left = 300
    End Sub
Funziona perfettamente: ottengo due etichette una di colore rosso a left=0 e una di color celeste a left=300. E finora, bene. Non ho usato alcuna funzione template...

mercoledì 29 agosto 2012

Uso della procedura template per creare un calendario

Ora posso creare un calendario, con una serie di labels in colonna, che mostrino la data.
Torno a usare la procedura template (speriamo di ricordare come si fa)...
La metto nel modulo Funzioni:
    Sub popola(Of oggetto)(ByVal frm As Form)
        Dim obj As Object
        For n = 0 To giorniDelMese(8, 2012).Length - 1
            obj = New Label
            With obj
                .left = 0
                .top = obj.height * (n Mod giorniDelMese(8, 2012).Length)
                .borderstyle = BorderStyle.FixedSingle
                .text = giorniDelMese(8, 2012)(n)
            End With
            frm.Controls.Add(obj)
        Next
    End Sub
Sì! Sono riuscito a creare a memoria una procedura template, che popola il form di labels in quanto specificato nella chiamata della procedura:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        popola(Of Label)(Me)
    End Sub
Ecco un pezzetto di calendario

...Che non è vero niente!
Mi rendo conto a posteriori che la procedura template non è stata costruita bene e il fatto che funzioni è illusorio!

Una miglioria del codice precedente, con una funzione che restituisce una matrice come risultato.

Che idiota! Ma era proprio necessario creare una matrice e poi una procedura che la compili?
Molto più intelligente creare una funzione che dia come risultato una matrice di date prendendo sempre come parametri il mese e l'anno.
Eccola:
Module Funzioni
    Function giorniDelMese(ByVal mese As Integer, ByVal anno As Integer) As Date()
        Dim data As Date = CDate("01/" & mese & "/" & anno)
        Dim dataStart As Date = data
        Dim contatore As Integer = 0
        Dim matrice As Date()
        Do
            ReDim Preserve matrice(contatore)
            matrice(contatore) = data
            data = data.AddDays(1)
            If data.Month <> dataStart.Month Then Exit Do
            contatore += 1
        Loop
        Return matrice
    End Function
End Module
...e chiamarla dal form iniziale in questo modo:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For n = 0 To giorniDelMese(8, 2012).Length - 1
            Debug.Print(giorniDelMese(8, 2012)(n))
        Next
    End Sub
...ottenendo il medesimo risultato:
01/08/2012
02/08/2012
03/08/2012
04/08/2012
05/08/2012
06/08/2012
07/08/2012
08/08/2012
09/08/2012
10/08/2012
11/08/2012
12/08/2012
13/08/2012
14/08/2012
15/08/2012
16/08/2012
17/08/2012
18/08/2012
19/08/2012
20/08/2012
21/08/2012
22/08/2012
23/08/2012
24/08/2012
25/08/2012
26/08/2012
27/08/2012
28/08/2012
29/08/2012
30/08/2012
31/08/2012
Perfetto!

Una matrice con i giorni del mese e la procedura per compilarla

Ora mi serve una procedura (ossia un metodo) che mi compili un array di date con tutti i giorni di un mese.
La metto in un modulo. Potrei provare ad "esporre" l'array come proprietà del modulo stesso...
Rimetto in pratica i concetti che ho elaborato recentemente...
Module Funzioni
    Public giorniDelMese As Date()
    Sub compilaMese(ByVal mese As Integer, ByVal anno As Integer)
        Dim data As Date = CDate("01/" & mese & "/" & anno)
        Dim dataStart As Date = data
        Dim contatore As Integer = 0
        Do
            ReDim Preserve giorniDelMese(contatore)
            giorniDelMese(contatore) = data
            data = data.AddDays(1)
            If data.Month <> dataStart.Month Then Exit Do
            contatore += 1
        Loop
    End Sub
End Module
Questa procedura compila la matrice giorniDelMese che è una proprietà del modulo Funzioni
Ora uso questa procedura dal form di inizio, dall'evento Load del form:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        compilaMese(8, 2012)
        For n = 0 To giorniDelMese.Length - 1
            Debug.Print(giorniDelMese(n))
        Next
    End Sub
Questo codice dovrebbe scrivermi sulla finestra immediata tutte le date del mese di agosto del 2012 (che la procedura compilaMese del modulo Funzioni accetta come parametri).
Ecco copiato e incollato il contenuto della finestra di debug dopo l'esecuzione del programma:
01/08/2012
02/08/2012
03/08/2012
04/08/2012
05/08/2012
06/08/2012
07/08/2012
08/08/2012
09/08/2012
10/08/2012
11/08/2012
12/08/2012
13/08/2012
14/08/2012
15/08/2012
16/08/2012
17/08/2012
18/08/2012
19/08/2012
20/08/2012
21/08/2012
22/08/2012
23/08/2012
24/08/2012
25/08/2012
26/08/2012
27/08/2012
28/08/2012
29/08/2012
30/08/2012
31/08/2012


Riuscito!

Definizione di una variabile del tipo base e sua istanziazione del tipo derivato

Mi annoto qui il metodo template che ho imparato a creare in VB.NET
Module Funzioni
    Sub popola(Of T As New)(ByVal frm As Form, ByVal sinistra As Integer, ByVal alto As Integer, ByVal numero As Integer)
        Dim ogg As Object
        For n = 1 To numero
            ogg = New T
            With ogg
                .left = sinistra
                .top = alto + .height * (n Mod numero)
                If ogg.GetType().Name = "casella" Then .backcolor = Color.Cyan
            End With
            frm.Controls.Add(ogg)
        Next
    End Sub
End Module
Bene. Ricordo una regola del C++, secondo la quale un puntatore si può definire di un tipo e si può istanziare di un tipo derivato... o qualcosa del genere.
Proviamo qualcosa del genere in VB.

Creo una classe casella che eredita da Label
Class casella
    Inherits Label
    Sub New()
        Text = "Ciao, ciccio"
        BorderStyle = Windows.Forms.BorderStyle.FixedSingle
    End Sub
End Class
Nel suo costruttore, questa classe inizializza il testo della casella e lo stile del bordo.
Quindi definisco la variabile come Label e la istanzio come casella
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim a As Label
        a = New casella
        Me.Controls.Add(a)

End Sub
E funziona. Ecco il risultato, in cui al form viene aggiunta una casella con le proprietà Text e BorderStyle inizializzate secondo le direttive del costruttore:



Dunque questa regola vale anche in vb.
Devo rivederla compiutamente in C++ perchè ne ho una reminiscenza un po' vaga...

domenica 19 agosto 2012

Primo tentativo riuscito di accesso al filesystem con VB.NET

Ecco anche i primi rudimenti di esplorazione del filesystem mediante VB.NET: Cerco tutti i files che stanno in una determinata directory e li stampo nella finestra di debug.
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each fl In My.Computer.FileSystem.GetFiles("c:\users\antonello\desktop")
            Debug.Print(CType(fl, String))
        Next
    End Sub

End Class
Risultato:
c:\users\antonello\Desktop\BUDINO (2).jpg
c:\users\antonello\Desktop\BUDINO.jpg
c:\users\antonello\Desktop\budino.wav
c:\users\antonello\Desktop\codice di registrazione di vb express.txt
c:\users\antonello\Desktop\converti.exe
c:\users\antonello\Desktop\desktop.ini
c:\users\antonello\Desktop\dest.txt
c:\users\antonello\Desktop\div.js
c:\users\antonello\Desktop\FLV Player.lnk
c:\users\antonello\Desktop\img012.jpg
c:\users\antonello\Desktop\lab.html
c:\users\antonello\Desktop\lecca lecca.jpg
c:\users\antonello\Desktop\lecca lecca.wav
c:\users\antonello\Desktop\Microsoft Office Word 2003.lnk
c:\users\antonello\Desktop\Microsoft Visual Basic 2010 Express.lnk
c:\users\antonello\Desktop\NomeDelFile.jac
c:\users\antonello\Desktop\pagina.html
c:\users\antonello\Desktop\succo con la cannuccia.jpg
c:\users\antonello\Desktop\succo con la cannuccia.wav
c:\users\antonello\Desktop\succo di frutta.bmp
c:\users\antonello\Desktop\succo di frutta.wav
c:\users\antonello\Desktop\testo.czz
Che sono tutti i files che stanno in desktop (i nomi strani sono files fatti per i bambini)

Creare un file con VB.NET

Creare un file con un'estensione qualunque, e salvarlo in desktop

Si dichiara una variabile come FileStream.
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream

    End Sub

End Class
Si dichiara una matrice di Bytes:
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte

    End Sub

End Class
In questa matrice si raccolgono i bytes corrispondenti a una stringa, o a qualunque altra cosa:
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte
        dati = Encoding.ASCII.GetBytes("Questa è una stringa")

    End Sub

End Class
Si inizializza la variabile di tipo FileStream, con il nome del file e la parola FileMode, che dovrebbe essere la modalità di scrittura, che vedrò in seguito
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte
        dati = Encoding.ASCII.GetBytes("Questa è una stringa")
        fs = New FileStream("C:\users\antonello\desktop\NomeDelFile.jac", FileMode.Append)
    End Sub

End Class
Si scrive sul file. con il metodo Write dell'oggetto FileStream, specificando la matrice da cui attingere i dati, l'offset e la quantità di bytes da scrivere.
Quindi si chiude il FileStream
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte
        dati = Encoding.ASCII.GetBytes("Questa è una stringa")
        fs = New FileStream("C:\users\antonello\desktop\NomeDelFile.jac", FileMode.Append)
        fs.Write(dati, 0, dati.Length)
        fs.Close()
    End Sub

End Class


Facciamo partire il codice e vediamo se funziona.

Funziona! Ho in desktop un nuovo file chiamato NomeDelFile.jac.
L'unica cosa strana è che nel testo non mi ha riconosciuto la "è" e me l'ha sostituita con un punto interrogativo. Credo che sia un problema relativo a Encoding, da affrontare successivamente.

sabato 18 agosto 2012

Maneggiare files con VB.NET, primi approcci

E adesso, vogliamo vedere come si può fare a salvare e aprire files di testo in VB.NET?

Ho trovato un codice e l'ho riprodotto a modo mio
Public Class Form2

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As System.IO.FileStream
        Dim byteData As Byte()
        byteData = System.Text.Encoding.ASCII.GetBytes("Antonello")
        fs = New System.IO.FileStream("C:\users\antonello\desktop\testo.czz", IO.FileMode.Append)
        fs.Write(byteData, 0, byteData.Length)
        fs.Close()


    End Sub
End Class
Questo può servire per salvare i files della mia applicazione.

mercoledì 15 agosto 2012

Passare come parametro una istanza di una struttura

Una routine da usare innumerevoli volte per definire diverse proprietà di diverse labels. Bene, ma dato che le proprietà sono tante, è scomodo passarle una per una come parametri: ci troviamo poi con una routine avente innumerevoli parametri.
Ecco invece come l'uso delle strutture può risolvere egregiamente il problema, anzi è l'unica soluzione possibile.
Si istanzia diverse volte, con diversi valori, la struttura avente per membri le varie proprietà delle labels, e quindi si passa alla routine come parametro una diversa istanza della struttura a seconda della "combinazione" di proprietà da dare alla label.
Public Class Form1
    Structure Struttura
        Dim colore As Color
        Dim altezza As Integer
    End Structure
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim lblStruc As Struttura
        lblStruc.altezza = 500
        lblStruc.colore = Color.Cyan

        Dim lblstruc2 As Struttura
        With lblstruc2
            .altezza = 300
            .colore = Color.Red
        End With

        routine(Label1, lblStruc)
        routine(Label2, lblstruc2)
    End Sub
    Sub routine(ByRef casella As Label, ByVal strut As Struttura)
        With casella
            .BackColor = strut.colore
            .Height = strut.altezza
        End With
    End Sub
End Class
E funziona egregiamente!!!

Drag drop con più controlli

Ecco come un singolo evento può essere usato per più controlli grazie alla flessibilità degli eventi in VB.NET.
Ho aggiunto un'altra label destinazione, e mi è bastato rimaneggiare un paio di eventi per ottenere lo stesso comportamento della label già presente.

Public Class Form1
    Private Sub evento(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles lblMario.MouseDown, lblPippo.MouseDown, lblCiccio.MouseDown
        sender.DoDragDrop(sender.Text, DragDropEffects.Copy)
    End Sub

    Private Sub Label1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragDrop
        Label1.Text = e.Data.GetData(DataFormats.Text)
    End Sub

    Private Sub Label1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragEnter
        e.Effect = DragDropEffects.Copy
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub
End Class

Primo tentativo riuscito di drag drop in VB.NET

Facciamo dei passi graduali per riuscire a creare un codice decente per il drag-drop.
Ho bisogno di diverse labels che trascinate su un'altra label ne modifichino il testo con il loro proprio testo.

Ecco il form. Trascinando ognuna delle labels con scritti i nomi sulla label bianca, in questa deve apparire il nome della label trascinata.



Ecco il codice:
Public Class Form1

    
    Private Sub evento(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles lblMario.MouseDown, lblPippo.MouseDown, lblCiccio.MouseDown
        sender.DoDragDrop(sender.Text, DragDropEffects.Copy)
    End Sub

    Private Sub Label1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragDrop
        Label1.Text = e.Data.GetData(DataFormats.Text)
    End Sub

    Private Sub Label1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragEnter
        e.Effect = DragDropEffects.Copy
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub
End Class
E funziona.

domenica 12 agosto 2012

Adattamento delle labels alle dimensioni del form

Ora ho alcuni problemi...
Devo adattare l'altezza delle labels alle dimensioni del form.
Questo è il codice che ho trovato.
Non mi piace molto, perchè ho dovuto togliere una fetta arbitraria all'altezza del form per evitare che l'ultima label fosse "spezzata"... ci deve essere qualcosa che non torna... forse è perchè il risultato del rapporto fra l'altezza dell'area client del form e il numero di labels restituisce cifre decimali.
Public Class Form1
    Dim lblMorning, lblAfternoon, lblNight As ArrayList

    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        lblNight(13).backcolor = Color.Red
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        lblMorning = New ArrayList
        lblAfternoon = New ArrayList
        lblNight = New ArrayList
        Dim numero, vertSpace, horSpace As Integer
        numero = 31
        vertSpace = 0
        horSpace = 2
        popola(0, numero, vertSpace, horSpace, lblMorning)
        popola(1, numero, vertSpace, horSpace, lblAfternoon)
        popola(2, numero, vertSpace, horSpace, lblNight)

    End Sub
    Sub popola(ByVal ordine, ByVal numero, ByVal vertSpace, ByVal horSpace, ByVal lblArray)
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .Text = n + 1
                .Height = (Me.ClientSize.Height - 50) / (numero - 1)
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = (.Width + horSpace) * ordine
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
            lblArray.add(etichetta)
        Next
    End Sub
End Class
C'è sempre l'evento sentinella, che a questo punto potrei anche togliere perchè è assodato che la creazione di matrici mediante gli oggetti ArrayList funziona egregiamente.

Popolando un form di Labels per i turni di mattina, pomeriggio e notte.

Ecco il codice, compreso l'"evento test" che cambia colore a una label a scelta, per verificare che funzionino i riferimenti a una specifica label dell'array
Public Class Form1
    Dim lblMorning, lblAfternoon, lblNight As ArrayList

    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        lblNight(13).backcolor = Color.Red
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        lblMorning = New ArrayList
        lblAfternoon = New ArrayList
        lblNight = New ArrayList
        Dim numero, vertSpace, horSpace As Integer
        numero = 20
        vertSpace = 2
        horSpace = 2
        popola(0, numero, vertSpace, horSpace, lblMorning)
        popola(1, numero, vertSpace, horSpace, lblAfternoon)
        popola(2, numero, vertSpace, horSpace, lblNight)
    End Sub
    Sub popola(ByVal ordine, ByVal numero, ByVal vertSpace, ByVal horSpace, ByVal lblArray)
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = (.Width + horSpace) * ordine
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
            lblArray.add(etichetta)
        Next

    End Sub
End Class
Il codice funziona bene, come previsto.
Ci ho aggiunto anche lo spazio orizzontale fra le diverse colonne.
Ogni colonna viene memorizzata in una matrice ArrayList, in modo da mantenerne i riferimenti.

Popolando il form di un array di labels

Ecco il codice per aggiungere a un form, in runtime, una serie di labels, di numero variabile e con una spaziatura regolabile impostando una semplice variabile.
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim numero, vertSpace As Integer
        numero = 10
        vertSpace = 5
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
        Next
    End Sub
End Class
E funziona alla grande!
Non ho ancora raccolto le etichette in una ArrayList, che permetterà di fare riferimento a ogni singolo elemento della matrice.

Ho anche creato l'arraylist, insieme con l'evento che mi permette di vedere se il riferimento all'elemento funziona.
Public Class Form1
    Dim Etichette As ArrayList
    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        Etichette(2).backcolor = Color.Yellow
    End Sub
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Etichette = New ArrayList
        Dim numero, vertSpace As Integer
        numero = 10
        vertSpace = 2
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
            Etichette.Add(etichetta)
        Next
    End Sub
End Class
E funziona!

Problemi e nuove tecniche per creare matrici di controlli in VB.NET, ragionamenti...

Non comprendo la natura dell'errore la cui segnalazione ottengo dal codice che ho ideato prima. Non ricordo la dizione esatta della segnalazione di errore, ma è senz'altro un errore relativo al modo poco ortodosso di creare matrici di controlli che ho usato, in quanto richiama il riferimento a un oggetto assente.

Ho trovato un altro modo di aggiungere controlli a un form.
Ho ricopiato il codice sfrondandolo di alcune righe che devo ancora comprendere, e non ottengo alcuna segnalazione di errori. Il problema, però, è che una volta aggiunti i controlli non ho più alcun riferimento ai singoli elementi. Non ho creato un vero e proprio array, o matrice che dir si voglia, perchè una volta che l'identificatore è stato attribuito a un nuovo controllo, si perde il riferimento a quello precedente.
Il codice è questo:
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim LV As Integer
        Dim Btn As Button
        For LV = 0 To 49
            Btn = New Button
            Btn.Left = Btn.Width * (LV Mod 10)
            Btn.Top = Btn.Height * (LV \ 10)
            Btn.Text = "???"
            Me.Controls.Add(Btn)
        Next
    End Sub
End Class
e funziona egregiamente.

L'unico problema è che ho perso i riferimenti.

Ossia, se voglio richiamare un bottone dell'insieme di quelli aggiunti al form non ho nessun "appiglio" con il quale chiemarlo. Sono tutti bottoni"senza nome".
Vediamo come si risolve la cosa...

In realtà, una delle righe che ho cancellato è questa marcata in rosso:
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim LV As Integer
        Dim Btn As Button
        For LV = 0 To 49
            Btn = New Button
            Btn.Left = Btn.Width * (LV Mod 10)
            Btn.Top = Btn.Height * (LV \ 10)
            Btn.Text = "???"
            Me.Controls.Add(Btn)
            Buttons.Add(Btn)            
        Next
    End Sub
End Class
Se lascio questa riga nel mio IDE, ottengo una segnalazione di errore:
Errore 1 'Buttons' non dichiarato. Non è accessibile a causa del livello di protezione. 
...perchè nell'esempio in rete questo Buttons è un array.
Vediamo il codice usato per crearlo...
Friend Buttons As ArrayList
Buttons = New ArrayList
L'oggetto ArrayLiet viene dichiarato e poi istanziato.
Non mi è chiaro ancora perchè Friend...

Comunque, poi, mentre vengono aggiunti gli elementi al Form, ogni elemento viene aggiunto all'ArrayList chiamata Buttons.
In tal modo si può fare probabilmente riferimento al singolo elemento della matrice.
E infatti ho scritto un piccolo evento Click del Form, che cambia il testo dell'elemento 3 dell'array di bottoni, e funziona:
    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        Buttons(3).text = "Fanculo"
    End Sub


Conclusioni: usare un unico identificatore per caricare tutti i controlli che si vogliono, avendo l'accortezza di inserire ogni controllo in un oggetto di classe ArrayList, in modo da poter identificare ogni controllo della matrice per mezzo di un indice.

sabato 11 agosto 2012

Eventi di una matrice di controlli in VB.NET

Ho trovato come far rispondere a uno stesso evento una matrice di controlli!
Tramite l'istruzione AddHandler aggiungo a un evento da me creato con un nome arbitrario l'handler dell'evento di ciascun elemento della matrice che voglio evocare con l'evento da me creato.
Public Class Form1
    Dim btn(3) As Button
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For n = 0 To 2
            btn(n) = New Button
            Me.Controls.Add(btn(n))
            On Error Resume Next
            btn(n).Top = btn(n - 1).Top + btn(n).Height
            AddHandler btn(n).Click, AddressOf evento
        Next
    End Sub
    Private Sub evento(ByVal sender As System.Object, ByVal e As System.EventArgs)
        MsgBox("ciao")
    End Sub
End Class
Semplice!!!
La gestione degli eventi in VB.NET è nettamente superiore a quella del VB6.

Matrice di controlli in VB.NET

Ho trovato il modo di creare una matrice di controlli in VB.NRT.
Non differisce molto da come la creavo in VB6.
Mi pare di ricordare che anche in VB6 si poteva creare con Me.Controls.Add.
Io la creavo con Load. Comunque il risultato è ottimo anche qui.
Posso fare riferimento a uno degli elementi della matrice, come evidenziato dal codice dell'evento Form_Click che mi sposta il secondo elemento della matrice a destra, e che ho appunto creato come prova della possibilità di accedere a un preciso elemento a scelta della matrice.
Public Class Form1
    Dim btn(3) As Button
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For n = 0 To 2
            btn(n) = New Button
            Me.Controls.Add(btn(n))
            On Error Resume Next
            btn(n).Top = btn(n - 1).Top + btn(n).Height
        Next
    End Sub
    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        btn(1).Left = btn(1).Left + 200
    End Sub
End Class

giovedì 9 agosto 2012

Eventualità di misure del DIV inferiori allo spazio occupato dal border e padding

Ho risolto il problema dell'eventualità in cui la larghezza del DIV dovesse essere inferiore alla larghezza complessiva del padding e del bordo.
function div(colore,bord,largh,alt,sn,top,pad){
  var bordo=bord;
  var sinistra=sn;
  var alto=top;
  var padding=pad;
  var spazioMorto=((2*pad)+(2*(parseInt(bord))));
  var larghezza=function(){
   if(largh>=spazioMorto)
    return(largh-spazioMorto);
   else{
    padding=0;
    return(0);
   }
    
  }
  var altezza=function(){
   if(alt>=spazioMorto)
    return(alt-spazioMorto);
   else{
    padding=0;
    return(0);
   }
  }
 
 var inizia=function(){

  var elemento=document.createElement("div");
  elemento.style.position="absolute";
  elemento.style.backgroundColor=colore;
  elemento.style.border=bordo;
  elemento.style.width=larghezza();
  elemento.style.height=altezza();
  elemento.style.left=sinistra;
  elemento.style.top=alto;
  elemento.style.padding=padding;
  document.body.appendChild(elemento);
 }
 inizia();
} 

Creazione e aggiunta di un TextNode.

Ora proviamo ad "appendere" un textnode a un div.

Ecco il codice:
<html>
<head>
<script>
function addNode(){
 var testo=document.createTextNode("Ciao scemo!");
 document.getElementById("mioDiv").appendChild(testo);
 
}
</script>
</head>
<body onClick="addNode()">
<div id="mioDiv" style="background-color:#AAFFCC;height:100px"></div>
</body>
</html>
E funziona. A ogni click sul DIV viene aggiunta una nuova frase "Ciao scemo" al DIV stesso.

Padding e Border cambiano le dimensioni di un elemento.

Che relazione c'è fra la proprietà "padding" e le proprietà "height" e "width"?

Ecco, mediante una serie di ragionamenti e di correzioni, ho capito che il valore di padding e quello di border cambiano la larghezza e l'altezza dell'elemento, e ho apportato le necessarie correzioni nella funzione mediante la quale creo un elemento DIV:
function div(colore,bordo,larghezza,altezza,sinistra,alto,padding){
 var colore=colore;
 var bordo=bordo;
 var larghezza=larghezza-(2*padding)-(2*(parseInt(bordo)));
 var altezza=altezza-(2*padding)-(2*(parseInt(bordo)));
 var sinistra=sinistra;
 var alto=alto;
  
 var inner="
Fesso
" var inizia=function(){ var elemento=document.createElement("div"); elemento.innerHTML=inner; document.body.appendChild(elemento); } inizia(); }

giovedì 2 agosto 2012

Variabili private e scope, ancora esercizi

Vogliamo vedere come in un oggetto si mettono le variabili private?
Vediamo qual è lo scope per una variabile dichiarata dentro e fuori da una funzione...
<html>
<head>
<script>
var cerchio=function(){
 variabile =123;
}

cerchio();
alert (variabile); 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
così facendo ottengo
123

Se dichiaro la variabile con this che succede?
<html>
<head>
<script>
var cerchio=function(){
 this.variabile =123;
}

cerchio();
alert (variabile); 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
ottengo
123
quindi è esattamente la stessa cosa...

mercoledì 1 agosto 2012

La funzione usata come funzione o come costruttore

Bene, dopo aver fatto questa clamorosa scoperta dell'acqua calda, uso una funzione dell'oggetto finestra, quello di base, come costruttore per un nuovo oggetto.
 
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI;
 
 
}
var Cerchio = new cerchio(3);

alert(Cerchio.area);
 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
Ecco:
28.274333882308138

Se viceversa, uso this.area al di fuori dell'oggetto Cerchio, che succede?
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI
}

cerchio(3);
alert(window.area);

 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
28.274333882308138
in questo caso non istanzio alcun oggetto Cerchio di tipo cerchio, ma eseguo semplicemente la funzione appartenente all'oggetto window.
In questo caso la proprietà area appartiene all'oggetto window, tant'è vero che viene mostrata chiedendo al programma di mostrare nella finestra di dialogo la proprietà window.area.
Ora invece di eseguire la funzione cerchio, la uso come costruttore per istanziare un oggetto Cerchio, e poi vedo se dicendo al programma di mostrare la proprietà window.area avviene qualcosa di diverso.
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI
}

var Cerchio=new cerchio(3);
alert(window.area);

 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
undefined
Ecco: in questo caso, usando la funzione cerchio(raggio) come costruttore non l'ho eseguita nell'ambito dell'oggetto window, ma per costruire un oggetto Cerchio, cosa che crea una proprietà area dell'oggetto Cerchio, non dell'oggetto window.
Provo a chiedere al programma di mostrare sia la proprietà window.area sia la proprietà Cerchio.area
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI
}

var Cerchio=new cerchio(3);
alert(window.area);
alert(Cerchio.area);
 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
undefined
28.274333882308138
Come volevasi dimostrare.

Vorrei cogliere l'essenza della differenza fra il Javascript, il Java, il C++ per quanto riguarda l'uso dei costruttori...

Riprendendo un po' di Javascript

Vediamo di ricreare un oggetto javascript.
Parto dall'oggetto window, che è l'oggetto dal quale partiamo sempre.
Per dimostrare che è l'oggetto dal quale parto sempre, faccio alcune piccole prove.
<html>
<head>
<script>
function main(){
 alert(this);
}
main();
 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
Ottengo:
[object Window]
Il this, che fa riferimento all'oggetto corrente, in questo caso fa riferimento alla finestra, che è sempre l'oggetto corrente.