Newsgroup: it.comp.lang.visual-basic
Titolo: Moduli di classe? ma a che servono?

Ciao a tutti.
Devo convertire dei programmi scritti in VB3 in VB6. La struttura
generale è di un form MDI che attraverso le voci del menu carica un form
child alla volta (clienti, magazzino, fatture, ecc..). Nel momento che
il child è caricato, il precedente è distrutto, cioè c'è un meccanismo:
 Unload MainMDI.ActiveForm
frmPippo.Show
Ora, ci sono 20-30 frmPippo, che differiscono a volte di poco: ci sono
gli stessi pulsanti Modifica, Annulla, Nuovo, Elimina, c'è un TabControl
con 4 o 5 tab dove vedere i dati in griglia o in dettaglio, filtrarli,
ordinarli, eccetera.
Il codice di ogni form, dei controlli e dei loro eventi si ripete in
modo simile, spesso eguale.
Perciò ho inserito nel codice di ciascuno un'istanza di una classe, che
per prima cosa lancia una funzione pubblica che fa un lavoro
del tipo:
Public Sub LinkaControlli(f as Form)
  with f
    Set .Controllo1=Classe1.Controllo1
   Set .Controllo2 =Classe1.Controllo2
   ...
 end with
end sub
E poi ho cominciato a cercare di sostituire ad ogni routine del form un
metodo della classe, che attraverso il passaggio di
parametri specifici del form, faccia lo stesso lavoro, giusto per non
avere il codice 30uplicato nell'eseguibile. (E anche per
i famosi motivi di manutenzione del SW, che ci hanno insegnato
all'università)
Il problema è sorto a questo punto:
Ogni form apre da 1 a 5 tabelle appartenenti a 1 o 2 database diversi.
Ora, io che ho imparato il C++, ho pensato di passare i database, le
tabelle, i nomi di entrambi e gli indici in procedure separate.
Così ho costruito un
Public Type MioTipo
  DB as database
 DBName as string
  Tbl() as Recordset
  TblName() as string
  IndexName() as string
end type
e, prima frustrazione, non l'ho potuto inserire nella classe (ma
perché??), ma in un modulo a parte.
Poi ho messo nella classe:
private m_Tipo() as MioTipo
e ho scritto una routine
public Sub GetDBs(Paramarray P())
che con una chiamata dal form del tipo
GetDBs db1, "C:\data1.mdb", db2, "C:\data2.mdb"
riesce a capire quanti database sono coinvolti, a dimensionare l'array
m_Tipo() di conseguenza, e ad assegnare al membro .DB il riferimento del
database dichiarato nel form (ma non ancora aperto!)
Poi lacio altre 2 metodi della classe, e alla fine mi ritrovo con una
cosa come m_Tipo(0) che ha un membro Tbl() di dimensione 3 perché deve
aprire 3 tabelle, e magari con m_Tipo(1) che ce l'ha di dimensione 2, ad
esempio.
Poi devo aprire tutto:
Public sub OpenAll
  for i = 0 to ubound(m_Tipo)
   set m_Tipo(i).DB = OpenDatabase(m_Tipo(i).DBName,false,false)
  for j = 0 to ubound(m_tipo(i).Tbl)
     set
m_tipo(i).tbl(j)=m_tipo(i).db.openrecordset(m_tipo(i).tblname(j),dbOpenTable)
    m_tipo(i).ibl(j).index=m_tipo(i).indexname(j)
    ........
E' un po' criptico, ma funzionerebbe in C++ dove passo i puntatori agli
oggetti, ma qui non va, perché se assegno un database
o un recordset non ancora aperti ad un altro nelle stesse condizioni,
sono entrambi a Nothing e il riferimento si perde, cioè
quando apro l'oggetto con la mia Sub, l'oggetto del form che dovrebbe
corrispondergli e subire un effetto collaterale se ne rimane
chiuso. Ora, se apro gli oggetti prima di passarli alla classe, tanto
vale che lascio tutto com'è!
C'è qualcuno che ha una brillante idea?
Grazie
-Silvano-

C'è qualcuno che ha una brillante idea?
La butto lì così, senza averlo provato, anche vista l'ora...
L'area di validità di m_Tipo() è limitata alla classe... in alternativa potresti creare una
collection di oggetti che esportano ciascuno la connessione ad un database e ad un recordset....
esempietto:
Ecco la classe collection (class1):
Private Collclass2 As New Collection
Public Property Get Item(ByVal Index As Integer) As Class2
    Set Item = Collclass2.Item(Index)
End Property
Public Sub Add(dbname As String, rsname As String)
    Dim nuovo As New Class2
    With nuovo
        .Index = Indice
        Set .db = OpenDatabase(dbname)
        Set .rs = .db.OpenRecordset(rsname)
        Collclass2.Add nuovo, CStr(.Index)
    End With
    Indice = Indice + 1
End Sub
Public Property Get Count() As Long
    Count = Collclass2.Count
End Property
E questa è la classe (class2.. che fantasia...):
Private vdb As Database
Private vrs As Recordset
Private vIndex As Integer
Public Property Get db() As Database
    Set db = vdb
End Property
Public Property Set db(newv As Database)
    Set vdb = newv
End Property
Public Property Set rs(newv As Recordset)
    Set vrs = newv
End Property
Public Property Get rs() As Recordset
    Set rs = vrs
End Property
Public Property Get Index() As Integer
    Index = vIndex
End Property
Public Property Let Index(ByVal vNewValue As Integer)
    vIndex = vNewValue
End Property
Indice è una variabile globale che tiene traccia degli indici degli elementi della collection (si
può anche evitare tenendo conto di collclass2.count)
Per testarlo puoi provare:
Dim nuovacoll As Class1
Set nuovacoll = New Class1
nuovacoll.Add "C:\miodb.mdb", "tabella1"
MsgBox nuovacoll.Item(1).rs("campo1")
Così puoi aggiungere alla stessa collection n oggetti class2, uno per ogni tabella che vuoi
aprire... Nel caso le tabelle appartengono allo stesso db, puoi implementare la proprietà db alla
classse collection e lasciare solo la prop rs alla class class2.
Fammi sapere se c'ho azzeccato o se è meglio che vada a dormire e ci ripensi domani... :-))
Ciao,
Moreno
#sirri#@#morenosoft#.com
(togliete "#" dall'indirizzo)
Moreno Sirri VB Site - 
http://www.msvbsite.net
---------------------------------------------------------------------------
Le risposte alle tue domande le trovi sul Sito Comune di questo NewsGroup:
 
http://www.it-lang-vb.net
---------------------------------------------------------------------------

> La butto lě cosě, senza averlo provato, anche vista l'ora...
ma che cavolo ci fai in piedi alle 5 del mattino?
:D
--
Fibia "Sakamoto" FBI

 perché??), ma in un modulo a parte.
Di norma le strutture Type non possono essere esposte pubblicamente su una
classe, e le funzioni che accettano come argomento delle strutture Type,
devono essere private.
Se però dichiari le strutture type in una DLL a parte, allora possono essere
pubbliche anche in una classe di un exe standard.
ciao Rea

:D
 :-) Aspetto le 7:30 per andare a dormire... :-)))


quello di VB. Mi hai aperto un'autostrada. E tra l'altro, funzionano!
Bene, mi fa piacere... evidentemente di notte un po' meno cavolate di quante ne spari di giorno...
mi sa che devo regolare i miei bioritmi... :-)))


Grazie Moreno, il tuo suggerimento è stato per me un po' come l'anello
mancante tra la programmazione procedurale e la programmazione a oggetti in
VB.
-Silvano-