uso delle sotto classi



  • uso delle sotto classi
    di prgiudicato_83 (utente non iscritto) data: 07/02/2015 11:09:59

    Carissimi, chiedo il vostro potentissimo aiuto per capire come impostare una sotto classe (sempre che si possa chiamare così)
    scusate la terminologia non appropriata ma sto imparando adesso ad usare le classi e non trovo molto materiale
    dunque quello che vorrei ottenere sono delle "variabili" di un "oggetto" a più livelli da usare ovunque nel mio programma in VBA.

    Qualcosa del tipo:
    Automobile.colore= "giallo"
    Automobile.velocità = 180
    Automobile.motore = "1300 diesel"

    e del secondo livello tipo:
    Automobile.motore.numero_pistoni = 4
    Automobile.motore.alimentazione = "benzina"

    al primo livello ci arrivo,....non so come fare il "secondo livello"

    1) "definisco" una nuova classe che si chiama "automobile" (da --> inserisci --> Modulo di classe, e la chiamo Automobile) ed inserisco:
    Public colore As String
    Public velocità As Integer
    Public motore As String

    2) in un modulo inserisco
    Public auto As Automobile

    3) in una sub "setto" la variabile con
    Set auto = New Automobile

    e utilizzo le mia "variabile" auto con tutte le sue "proprietà" quando voglio all'interno del programma in VBA semplicemente assegnandogli un valore con
    Automobile.motore = "1300 diesel"

    ora come faccio ad arrivare a poter impostare altrettanto semplicemente il valore del secondo livello con un'istruzioe tipo:
    Automobile.motore.alimentazione = "benzina"

    spero di essere stato almeno comprensibile e qualcuno sappia aiutarmi.

    ciao e grazie come al solito







  • di Vecchio Frac data: 07/02/2015 13:33:13

    Premessa importantissime: VBA *non* è object oriented. La programmazione "ad oggetti" vera non fa parte di questo mondo. Pur sapendo manipolare oggetti di diverso tipo, esposti dalle applicazioni Office, VBA non offre gli strumenti tipici di una programmazione ad oggetti pura e strutturata.
    Ne è stata implementata una simulazione, copiata dal modello a pseudooggetti di VB6, non esente da difetti di progettazione e implementazione. Col risultato che se ne viene fuori n'idea distorta della vera programmazione ad oggitti (con i suoi capsosaldi di ereditarietà, incapsulamento e polimorfismo).
    Ti consiglio di studiare soluzioni alternative al metodo "ad oggetti" e di dedicarti allo studio delle classi in VBA solo per sapere che ci sono, e che le puoi usare, senza avere un grande valore aggiunto. L'uso delle classi viene in aiuto in pochi casi (ad esempio per implementare le matrici di controlli). Io ho realizzato una class collection tempo fa (un'estensione di un oggetto Collection): poco più di un giocattolo. La curva di apprendimento per capire come funziona il meccanismo è abbastanza ripida.
    Inoltre, ci sono limitazioni come avrai notato dai diversi messaggi di errore che ti sono capitati (anche frustranti a volte).

    Per il tuo problema, però, veniamo al dunque ^_^
    Devi anzitutto creare due classi, una "automobile", e una "tipo_motore".
    Entrambe le classi devono avere l'attributo "2 PublicNotCreatable" impostato (Ctrl-F4, finestra proprietà).
    Nella prima classe metti gli attributi relativi all'automobile, nella seconda alle caratteristiche del motore.
    Nel modulo normale infili il codice che mostro sotto, dove assegnerai il tipo "automobile" all'oggetto "auto" e una volta creata questa istanza potrai creare un nuovo oggetto di tipo_motore assegnandolo all'attributo auto.motore; dopodichè potrai accedere ai singoli attributi di tipo_motore con la classica notazione punto.

    Nell'esempio ho semplificato, ma per irrobustire l'assegnazione e la lettura dovrai studiare con fanno le diverse Property Get/Let/Set. Eoni fa avevo un bel libro di Francesco Balena su VB6 dove spiegava bene l'uso di queste "classi". Devo cercare nelle carte sepolte e vedere se trovo qualcosa di interessante.
    Se ti intriga l'argomento, poi, ti passo il link all'articolo che avevo scritto per la class Collection, che illustra alcuni meccanismi interessanti.

     
    'classe "automobile"
    Option Explicit
    
    Public colore As String, _
        velocità As Integer, _
        motore As tipo_motore
    
    '--------------------------------------------
    'classe "tipo_motore"
    Option Explicit
    
    Public alimentazione As String, _
        cilindrata As Integer, _
        cavalli As Integer, _
        max_velocita As Integer
    
    '---------------------------------------------
    'modulo1
    Option Explicit
    
    Sub test()
    Dim auto As automobile
    
        Set auto = New automobile
        Set auto.motore = New tipo_motore
       
        auto.motore.alimentazione = "benzina"
    
        MsgBox auto.motore.alimentazione
    End Sub
    






  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 15:26:30

    Grazie Frac, ne sai una più del diablo,
    effettivamente la logica è lineare e non fa una piega, forse a sbatterci un po di più la capoccia avrei potuto arrivarci.
    Per adesso vedo cosa succede e scopro dove mi portano queste classi... poi vedrò se è il caso di approfondire, nel senso che il tempo è poco e bisogna scegliere in base alle necessità.
    un saluto e un grande Grazie. ciao



  • di Vecchio Frac data: 07/02/2015 17:17:50

    La mia perplessità nell'uso concreto di questo genere di oggetti self-made, è che realmente non servono.
    Principalmente non puoi salvarli, e allora che ce ne facciamo? perchè "fa più figo" crearli e gestirli a livello di programmazione? all'utente sono invisibili!
    Per carità, è giusto sapere come si usano i moduli di classe, i loro limiti, il contesto in cui si possono implementare le interfacce, ecc. Ma alla fine: per salvarne il contenuto, cioè per serializzare questi oggetti, e quindi riusarli in un momento successivo, serve un metodo, che non c'è nativamente... devi salvare il contenuto di ogni singolo membro dell'oggetto magari in un file random (al pari di ogni altro stream dati) ^_^
    Del resto la fatica di costruire un meccanismo simile è vanificata se pensi che:
    - se usi Access, semplicemente crei delle tabelle e accedi ai record come se fossero oggetti per simulare gli attributi dell'oggetto che devi creare;
    - se usi Excel, hai a disposizione le celle del foglio, che disposte in forma tabellare ti aiutano a strutturare i diversi membri di un oggetto;
    - se usi Word, ecco in quel caso ha più senso... io avevo realizzato una classe di etichette e una classe etichetta che poi salvavo su file nella modalità suddetta... una pena perchè bastava creare un semplice file di testo e scrivere in sequenza tutti i dati (hai mai sentito parlare di csv?) :)

    ...morale: un bell'esercizio, per impratichirsi con i concetti di object oriented programming, e per sentirsi meno impreparati casomai si volesse affrontare un linguaggio più evoluto.





  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 17:35:54

    Ho perso un mesaggio nell'etere che riposto (potrebbe arrivare 2 volte) anche se poi ho visto che hai forse già risposto.
    il messaggio era questo:

    allora fin qui ho capito,
    ora accade una cosa strana:
    il mio programma (semplificando) riempie i dati relativi alla prima auto con un ciclo for che va da 0 a 1 (considero solo 2 auto).
    prima di aumentare l'indice del ciclo e passare a riempire i dati della seconda auto, devo salvare l'auto appena "configurata" assegnandone tutti i valori e le proprietà ad una variabile di tipo automobile.
    (quello che concettualmente farei con: if i = 0 then Set auto1 = auto)
    poi riparte tutto il programma grazie al ciclo for configurando tutti i parametri di un'altra auto.
    prima di uscire definitivamente dal ciclo for devo "salvare" l'auto configurata durante il secondo ciclo nella "variabile" auto2 (con qualcosa del tipo: if i = 1 then Set auto2 = auto).



  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 17:45:22

    ma quindi qual'è lo strumento migliore se le classi non vanno bene.
    qualcosa che mi permetta di creare un "oggetto" auto con tutte le sue variabili.
    Come esempio efficace si puo usare anche la classica rubrica: mi servirebbe poter avere un variabile tipo "persona" con tutte le sue proprietà: nome, cognome, num_tel etc... e poi salvarle in variabili tipo persona1 e persona2 mantenendone tutte le proprietà (non in un database o file esterno)
    tenete conto che ho bisogno di gestire solo 2 "persone" (o 2 auto a seconda dell'esempio) per quello che devo fare.



  • di Vecchio Frac data: 07/02/2015 19:48:56

    Bè se è solo per creare istanze diverse dello stesso oggetto allora ti bastano due variabili diverse:
    set auto1 = new automobile
    set auto1.motore = new tipo_motore

    set auto2 = new automobile
    set auto2.motore = new tipo_motore

    Il problema è, appunto, salvare auto1 e auto2 su disco ^_^

    cit. "ma quindi qual'è lo strumento migliore se le classi non vanno bene.
    qualcosa che mi permetta di creare un "oggetto" auto con tutte le sue variabili"
    ---> Io ti risponderei "un database", con una tabella "auto", e i campi corrispondenti alle varie caratteristiche.
    Un record, un auto.
    In Excel come puoi rappresentare questo database? con una semplice tabella fatta di righe e colonne.
        A    B
    
    1 auto motore cilindrata cavalli
    2 auto1 benzina 1200 90
    3 auto2 diesel 1600 75


    ...più o meno ^_^






  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 20:14:55

    purtroppo non va bene il discorso del database.
    se riusciamo a far funzionare il codice sotto (che so essere sbagliato) ho risolto tutto.
    ..sto diventando pazzo
     
    Dim auto2 As Automobile
    Dim auto1 As Automobile
    Set auto = New Automobile
    auto.Nome = "fiat"
     auto1 = auto
    auto.Nome = "Audi"
     auto2 = auto
    controllo1 = auto1.Nome '<-- vorrei ci fosse memorizzato Fiat
    controllo2 = auto2.Nome '<-- vorrei ci fosse memorizzato Audi



  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 20:18:33

    L'unica cosa che sembra funzionare è la seguente.
    è più vicina al mio progetto reale quindi i nomi delle variabili e tutto il resto non sono di automobili o persone ma di attuatori che è quello di cui si occupa il programma.


     
    Private Sub CommandButton1_Click()
     Dim Act As Attuatore
     Set col_act = New Collection
    
     For i = 0 To 1
         Set Act = New Attuatore
            Act.Nome = "claudio_" & i
            Act.Indirizzo = "indirizzo_" & i
           col_act.Add Act
     Next
    
      nome1 = col_act(1).Nome
      nome2 = col_act(2).Nome
    End Sub



  • di Vecchio Frac data: 07/02/2015 20:30:13

    Sì certo. Anche con una Collection. Non cambia l'approccio: butti l'istanza dell'oggetto dentro una variabile.
    L'esempio sotto riprende quello delle automobili.
    A ogni variabile deve essere assegnata una istanza New dell'oggetto di classe, e ogni variabile vivrà di vita propria.

    Forse è meglio parlare del progetto reale e non di automobili :)
    Il pezzo che hai scritto mi sembra in teoria funzionare a dovere.
    Purtroppo ad ogni esecuzione del pulsante annienti col_act e perdi gli inserimenti precedenti.
    Hai bisogno di serializzare l'oggetto? cioè di salvarlo su disco o in un db personalizzato?
    Puoi mostrare la classe Attuatore?
     
    Dim auto1 As Automobile
    Dim auto2 As Automobile
    
    Set auto1 = New Automobile
    Set auto2 = New Automobile
    
    auto1.Nome = "fiat"
    auto2.Nome = "Audi"
    
    msgbox auto1.Nome '<-- vedrai Fiat
    msgbox auto2.Nome '<-- vedrai Audi






  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 20:49:36

    Ora mangio una pizza veloce e poi torno in dittaba lavorarci. Ora son da cellulare x cui saro breve. Il problema e' che tutto il programma sulla classe auto con 1000 funzioni diverse e impostandone 1000 proprieta.
    Ad un certo punto devo assegnare tutto il pacchetto "auto" ad una variabile auto1 e ricalcolare tutto. Poi assegnare il pacchetto "auto" ricalcolato ad auto2.
    Questo solo per poter fare siccessivamente uj confronto tra le due auto in moda da poter scegliere quella piu adeguata tramite una funzione....non so se si capisce.
    Insomma non posso assegnare direttamente ad auto1 e poi ad auto2 come nel tuo esempio, ma al primo giro del ciclo for costruisco tutte le proprieta di auto, poi le salvo in auto1. Eseguo il secondo ciclo ridefinendo auto. Alla fine "salvo" auto in auto2.
    E finalmente vado a fare il mio confronto con la funzione tra auto1 e auto2



  • di Vecchio Frac data: 07/02/2015 21:22:13

    Allora segui la logica di quel pezzo di codice della classe Attuatore.
    Puoi impostare tutte le proprietà di auto1 dopo averla instanziata con "set auto1 = new automobile".
    Ma non puoi assegnarla ad una auto2 con "set auto2 = auto1" perchè se cambi qualcosa di auto1 cambi anche auto2 (puntano al medesimo oggetto).
    "Eseguo il secondo ciclo ridefinendo auto."
    ---> Non ridefinisci la classe ma una sua istanza che è già assegnata a un oggetto, quindi devi creare un secondo oggetto che abbia come attributi quelli della prima auto. Poi fai le modifiche su questo secondo oggetto. Infine fai i confronti che devi fare.







  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 21:46:38

    non devo serializzare l'oggetto,
    l'iter completo (restando sull'esempio delle auto) è
    1) leggo una riga una riga da un foglio excel piena di parametri
    2.1) (primo giro del ciclo for): "calcolo" l'auto che corrisponde a quei parametri tramite una serie di funzioni, così da avere un'auto con tutte le sue proprietà (circa 50/60)- e la salvo in qualche modo in una variabile "auto1"
    2.2) (secondo giro del ciclo for): "calcolo" nuovamente l'auto che corrisponde a quei parametri ma con alcune varianti e la salvo in "auto2"
    3) entrambe le auto soddisfano i parametri in ingresso quindi potrebbero andare bene
    4) butto entrambe le auto in una funzione che sceglie quella che costa meno.
    5) scelta l'auto che costa meno stampo tutte le sue caratteristiche su un foglio excel.
    6) distruggo tutte le variabili auto e ricomincio leggendo i parametri dalla riga successiva per scegliere l'auto successiva (sempre calcolandone 2 diverse e poi scegliendo quella delle 2 che costa meno)

    Provo a seguire la logica dell'attuatore con le collection come mi hai suggerito (anche se non ho idea di cosa stia facendo)...solo una cosa:
    (con riferimento al codice dell'attuatore) come faccio a "distruggere" gli elementi 1 e 2 nella collection col_act quando voglio io?
    nel senso: (restando sull'attuatore) il codice completo dovrebbe essere:


     
    Private Sub CommandButton1_Click()
     Dim Act As Attuatore
     Set col_act = New Collection
    For j = 1 To 10
             For i = 0 To 1
                 Set Act = New Attuatore
                    Act.Nome = "claudio_" & i
                    Act.Indirizzo = "indirizzo_" & i
                   col_act.Add Act
             Next
              indice = funzione_prezzo_migliore(col_act(1), col_act(2))
              Call stampa_stampa(col_act(indice))
              'qualcosa che distrugga col_act(1) e col_act(2)
     Next
    End Sub



  • di Vecchio Frac data: 07/02/2015 21:52:52

    Sto pensando al metodo migliore per implementare 'sta cosa.
    Ma per rispondere alla tua domanda la risposta è:
    sposta l'istruzione "Set col_act = New Collection" dentro il ciclo for j. Ad ogni esecuzione la variabile viene annientata e predisposta a ricevere una nuova collezione di oggetti.
     
    Private Sub CommandButton1_Click()
       Dim Act As Attuatore  
       
       For j = 1 To 10
            Set col_act = New Collection
            For i = 0 To 1
    
    ......
    End SUb
    






  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 22:06:04

    mi pare funza in qualche modo (non so cosa faccia ma funza)

     
    'in classe Attuatore c'è
    Option Explicit
        Public Nome As String
        Public Indi As String
    
    'in modulo1 c'è
    Public col_act As Collection
    
    'nel foglio che vuoi metti un pulsante con questo codice
    Private Sub CommandButton3_Click()
     Dim Act As Attuatore
    For J = 1 To 10
     Set col_act = New Collection
         Nome_act = "Claudio_" & J: indirizzo_act = "indirizzo_" & J
             For i = 0 To 1
                 Set Act = New Attuatore
                    Act.Nome = Nome_act & i
                    Act.Indi = indirizzo_act & i
                   col_act.Add Act
             Next
                controllo = col_act(1).Nome
                controllo = col_act(1).Indi
                controllo = col_act(2).Nome
                controllo = col_act(2).Indi
     Next
    End Sub
    



  • di Vecchio Frac data: 07/02/2015 22:24:04

    Bè dai non dire che non sai cosa faccia, il codice è abbastanza chiaro e si spiega da solo :)
    Le ultime quattro righe con "controllo = ..." sono invero totalmente inutili: primo perchè assegni alla stessa variabile valori diversi in sequenza e secondo non ne fai niente, una volta che "controllo" è stato valorizzato.
    Sempre se non c'è altro: stiamo vedendo codice a spizzichi e bocconi e manca la visione di insieme :)





  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 22:38:27

    Caro amico (perchè uno che perde tempo dietro ai problemi di un altro non saprei come chiamarlo se non amico)..comunque..
    caro amico la variabile controllo è quella che uso sempre per controllare cosa succede mentre faccio girare il codice.
    in questo caso ad ogni ciclo (mi fermo) e leggo i 4 controlli per capire se sta funzionando (sai non conosco altri modi).

    Grazie immensamente..vado avanti.
    ci sentiamo al prossimo problema ciao



  • di Vecchio Frac data: 07/02/2015 22:49:01

    Io non "perdo tempo" e mi arricchisco ad ogni interazione con chiunque abbia bisogno.
    Molti anni fa anch'io ho trovato chi ha "perso tempo" con me :)

    Per controllare i risultati delle elaborazioni, ci sono metodi diversi:
    - usa debug.print (nella finestra Immediata troverai il risultato)
    - usa dei bei msgbox
    - usa la finestra Variabili locali oppure la finestra Espressioni di controllo (menu Visualizza dell'editor di codice)

    Inoltre:
    - non sprecare variabili :)
    - metti sempre Option Explicit in testa ai tuoi moduli ed eviterai tanti errori





  • di pregiudicato_83 (utente non iscritto) data: 07/02/2015 23:26:37

    ok ricevuto. ti saluto e metto risolto