TheTruster's profileTheTruster's BoxPhotosBlogListsMore ![]() | Help |
TheTruster's Box |
September 25 Sezione Modelli 3D - Aggiunti 4 ModelliAggiunti 4 nuovi modelli nella sezione 3D Models. Di seguito le anteprime con i collegamenti per scaricarli. Potete scaricarli liberamente accedendo all'area Download -> Modelli 3D. November 19 Automazione 2 - Importare dati da Excel ad Access con ADONel post precedente ho affrontato il problema dell'importazione di dati da un foglio di lavoro di Excel ad un Documento Word. La stessa cosa avrebbe potuto essere realizzata utilizzando come destinazione, in luogo del documento Word, un altro Foglio di Lavoro Excel, un Database Access oppure un programma in Visual Basic 6. Il sistema dell'automazione, però, ci pone nella situazione di dover avere installato sulla macchina l'applicazione del pacchetto Office che intendiamo utilizzare. Nel caso di Excel ad esempio, non potremmo fare ricorso all'apposita DLL se Excel stesso non fosse installato nel sistema. Una soluzione alternativa, anche se non si tratta propriamente di automazione, è quella di trattare Excel come fosse un Database, nel qual caso avremmo bisogno solo del modello ad oggetti ADO e, se il sistema operativo è Windows XP, questo è installato insieme al sistema, per cui sicuramente disponibile. Per il nostro esempio di importazione prenderemo a base un Database Access anche perfettamente vuoto senza alcuna tabella, visto che ci occuperemo di crearla dinamicamente al momento dell'importazione. Avremo anche bisogno di un file di Excel per la nostra prova per cui, se non ne abbiamo uno già disponibile con dei dati intabellati in maniera coerente, creiamone uno, con questa impostazione:
Come si può notare, la cosa importante è utilizzare la prima riga come intestazione dei campi. Passiamo alla creazione del nostro Database - o creiamone uno nuovo - e aggiungiamo un nuovo Modulo, premendo Moduli nella finestra del Database e Nuovo sulla barra superiore della stessa finestra. Si aprirà la finestra dell'Editor di Visual Basic e la prima cosa che faremo, è referenziare la libreria che ci interessa, relativa ad ADO. Lo possiamo fare da Strumenti -> Riferimenti.... Molto probabilmente, dipendentemente dalla versione di Access, si troverà già referenziata la Microsoft ActiveX Data Object 2.1 Library nel qual caso possiamo de-referenziarla andandone a scegliere una analoga, ma più aggiornata, ovvero la Microsoft ActiveX Data Object 2.8 Library oppure la più recente installata nel sistema, se questa non è presente. Il modello ad oggetti ADO, benchè disponga di un numero relativamente basso di oggetti, risulta piuttosto articolato e sarebbe impossibile discuterne le potenzialità e le caratteristiche in poche righe. In generale, comunque, anche ADO come gli oggetti della libreria di Excel si possono riassumere in una certa gerarchia, a capo della quale troviamo l'oggetto Connection. Questo è l'oggetto principale poichè permette di "aprire una porta" sul Database permettendoci l'accesso ai dati. Attraverso la Connection possiamo eseguire delle operazioni direttamente sul DB inviandogli delle frasi SQL, per cui ci consente di inserire dati e riceverne indietro, creare tabelle o cancellarne o ancora modificarne la struttura. Se creare una tabella piuttosto che inserire dati o modificarli non presuppone per forza un ritorno degli stessi verso la nostra applicazione, la semplice lettura dei dati contenuti in una tabella per la loro visualizzazione, ci pone nella situazione di doverli "immagazzinare" da qualche parte. Ci serve un contenitore, insomma. Questo contenitore si chiama Recordset. Come suggerisce la parola questo oggetto è un set di record ovvero una porzione dei dati contenuti genericamente nel nostro DB anche se distribuiti su più tabelle, selezionati secondo dei criteri. Per selezionare dei record si usa una Query ovvero una frase SQL che il motore del DB interpreta per restituirci dei dati coerenti con le nostre condizioni. Mi scuso per questa digressione, forse per qualcuno superflua, ma probabilmente necessaria per permettere a chi si avvicina per la prima volta a questa tecnologia di capire almeno il senso delle righe di codice che andrò a riportare in seguito. In ogni caso consiglio, per una concezione più dettagliata dell'argomento, di dare una scorsa a questo sito (in inglese) dove, oltre alle spiegazioni riferite ai vari oggetti di ADO, sono presenti anche alcuni esempi di utilizzo. Ritornando alla nostra importazione, prepariamo l'oggetto principale di cui ci serviremo per aprire il DB Excel ovvero una Connection. Codice: Dim oConn As ADODB.Connection Di solito, personalmente, preferisco avere un unico oggetto Connection, attraverso il quale aprire più Recordset. L'oggetto Connection viene dichiarato pubblico, aperto all'inizio dell'applicazione e chiuso alla chiusura della stessa oppure quando non risulta più necessario, mentre gli oggetti Recordset vengono aperti e chiusi, spesso nella stessa routine, quando esauriscono la loro utilità, sia essa di inserimento/modifica che di lettura. In questo caso, possiamo accontentarci un solo oggetto Recordset che dichiareremo all'interno della routine di importazione. A proposito, cominciamo a costruirla. Dal punto di vista logico la nostra routine dovrà:
Per aprire la Connessione verso una qualsiasi DB è necessaria la cosiddetta ConnectionString ovvero stringa di connessione. Essa ci permette di scegliere la modalità di apertura del DB, specificando il motore e il file del DB stesso, e passando al Database Username e Password nel caso in cui fossero necessari per accedervi. Per Excel è necessario una particolare ConnectionString e un'ottima fonte per reperirne una adeguata alle nostre necessità è il sito ConnectionStrings.com. Guardando tra quelle disponibili per aprire Excel come DB troveremo anche questa Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MyExcel.xls;Extended Properties="Excel 8.0;HDR=Yes;IMEX=1"; Per semplicità possiamo anche realizzare una Routine riutilizzabile, appositamente creata per aprire la connessione, liberandoci dalla necessità dover inserire il codice necessario tutte le volte in diverse routines: Codice: Sub ApriConnessione(NomeDB As String) Come si può notare la connessione verso il nostro file Excel si ridurrà ad una semplice riga del tipo: Codice: ApriConnessione "C:\Cartella\FileExcel.xls" Analogamente possiamo creare una seconda routine per chiudere la connessione eventualmente aperta: Codice: Sub ChiudiConnessione() Abbiamo praticamente realizzato i punti 1 e 7 della lista precedente, quindi passiamo, finalmente, alla creazione della routine di importazione. Nella sua costruzione utilizzeremo, oltre alla Connessione verso Excel e al Recordset, la connessione che Access, ovvero la sua Applicazione, apre verso le sue tabelle. Questa Connessione è accessibile attraverso l'oggetto CurrentProject. Sfrutteremo questa Connessione per inviare al DB delle frasi SQL idonee a creare la tabella che ospiterà i dati e le frasi di UPDATE (sempre SQL) che ci permetteranno di inserirvi i dati letti da Excel. Codice: Sub ImportaDatiExcel() Nel codice appena riportato ho richiamato anche la Routine EliminaTabella, appositamente creata per eliminare la tabella, nel caso fosse presente, prima di crearne una nuova. E' ovvio che, se non si cancellasse la tabella preesistente si avrebbe un errore. Utilizzando una routine separata, l'errore viene trascurato, se rilasciato dall'applicazione, evitandoci di inserire ulteriori righe di codice alla routine di importazione mantenendola, tutto sommato, compatta. Ecco la dichiarazione della routine: Codice: Sub EliminaTabella(NomeTabella As String) Abbiamo praticamente terminato e l'unica cosa che rimane da fare è provare il tutto. Se tutto andrà a buon fine, riusciremo ad importare i dati contenuti in un File Excel aperto come fosse un DB in un Database Access, dentro una tabella creata dinamicamente. La creazione della tabella, in questo caso, è stata fatta in maniera un po' "rigida" nel senso che abbiamo già impostato da codice i campi con loro tipo e lunghezza, ma volendo rendere il tutto ancora più flessibile, prima della creazione della tabella, potremmo scorrere con un ciclo i campi del Recordset importato per valutarne numero, nome e tipo di dati inseriti, creando una tabella esattamente corrispondente ai dati da importare. Nel caso vogliate segnalarmi inesattezze o richiedere ulteriori chiarimenti contattatemi pure senza remore November 14 Automazione 1 - Importare dati da Excel a WordLe applicazioni del pacchetto Office, possiedono in compendio alle loro già numerose funzioni, anche un ambiente di sviluppo integrato: il Visual Basic for Application o VBA. Ognuna delle applicazioni ovvero Excel, Access, Word, etc., ha delle peculiarità, principalmente dovute alla diversità degli oggetti che in esse vengono trattati. Per fare un esempio, in Word esistono gli oggetti Document, mentre in Excel gli oggetti Worksheet, e così via. La base del linguaggio, quindi, è una sola ed è Visual Basic (seppure in una versione "ridotta" e adattata), ma a seconda dell'applicazione che si sta utilizzando è possibile avere a disposizione degli oggetti ognuno con sue proprietà e metodi utili per automatizzare molte delle operazioni che normalmente andrebbero compiute manualmente. Descrivere seppur brevemente tutte le possibilità offerte dall'automazione sarebbe impossibile per cui mi limiterò a descrivere come è possibile accedere ad un file di Excel dall'esterno, ovvero da un programma Visual Basic 6, o un altro file di Excel o ancora da un documento Word o un Database Access. La metodologia non cambia e data la base comune del linguaggio le operazioni da compiere sono esattamente le stesse. La prima cosa da considerare è che Excel stesso è un oggetto, come pure oggetti sono i suoi vari elementi gerarchicamente dipendenti come Workbook, WorkSheet, Range, Cell, etc. Tutti questi oggetti fanno parte di una cosiddetta Libreria che, se si usa Excel, è già referenziata e fruibile senza fare null'altro, ma che va referenziata nel caso in cui si abbia intenzione di accedere ad un'applicazione Excel da un qualsiasi altro programma VB6 o applicazione Office. Per referenziare la libreria è sufficiente andare nella finestra dell'Editor di Visual Basic attraverso Strumenti -> Macro -> Visual basic Editor - oppure premendo CTRL+F11 - scegliere da questa nuova finestra, dal menu Strumenti, la voce Riferimenti... e cercare la libreria che si chiama Microsoft Excel xx.x Object Library spuntando l'apposita casellina. ![]() Effettuata questa semplice operazione avremo a disposizione tutti gli oggetti che Excel espone normalmente all'interno del proprio VBA. Come accennato in precedenza la struttura degli oggetti di Excel è di tipo gerarchico, nel senso che esiste un oggetto principale ovvero Application, dal quale interdipendono via via altri oggetti. Im maniera molto, molto semplificata, potrebbe riassumersi in questo modo: ![]() Tenendo a mente questa struttura è facile immaginare come può essere possibile gestire più Workbook facenti parte della stessa applicazione o più Worksheet sempre dipendenti dallo stesso Workbook. Alla base ci sono gli oggetti Range che rappresentano una cella o un loro insieme, e gli oggetti Cells attraverso i quali è possibile identificare una singola cella attraverso riga e colonna. Ognuno di questi oggetti possiede numerosi metodi e proprietà, che sarebbe eccessivamente dispersivo trattare in questo piccolo spazio, ma che è possibile esplorare e provare con un minimo di intraprendenza e l'aiuto della Guida in Linea. Fatta questa doverosa presentazione, entriamo nel vivo dell'argomento, ovvero l'accesso ad un file di Excel da VBA. Proveremo, da un Documento Word, ad accedere ad un Workbook Excel salvato sul nostro HardDisk per prelevare il valore da alcune celle, importandole contestualmente sul nostro documento. La prima cosa da fare in Word, dopo aver referenziato la libreria come descritto sopra, è aggiungere un nuovo Modulo VBA. Si fa semplicemente scegliendo la voce Modulo dal menu Inserisci. Nel nuovo Modulo cominciamo con l'istanziare gli oggetti che ci serviranno per accedere al nostro file di Excel, iniziando dall'Applicazione e proseguendo con il WorkBook e il Worksheet. Codice: Dim xlApp As Excel.Application Quindi creiamo una nuova sub che chiameremo Importa. All'interno di questa dovremo occuparci di "dare vita" alla nuova istanza dell'applicazione Excel che intenderemo utilizzare, assegnando di seguito i vari oggetti, "puntandoli" sul Workbook che intendiamo aprire e sul Worksheet sul quale risiedono i dati che vogliamo importare. C'è da precisare che accedendo ad Excel in questo modo, esso rimarrà invisibile (a meno che non si renda visibile esplicitamente), permettendoci così di effettuare le operazioni che ci servono in maniera trasparente per l'utente. Codice: Sub Importa() Possiamo già provare il funzionamento del nostro codice chiudendo la finestra di Visual Basic e, da Word, andando sul menu Strumenti -> Macro -> Macro... per visualizzare una finestra contenente la lista di tutte le macro contenute nel Documento Word, tra le quali dovremmo trovare anche la nostra, denominata Importa. Selezioniamola e premiamo Esegui per avviarne l'esecuzione. Se tutto è andato bene sulla pagina del Documento Word, a partire dal cursore, dovrebbe visualizzarsi la lista di valori contenuta nella prima colonna del nostro file di Excel. Spero che questo semplice esempio sia stato abbastanza chiaro e utile a comprendere almeno i meccanismi che stanno alla base dell'automazione. In caso contrario non esitate a chiedermi ulteriori chiarimenti. Nel prossimo intervento proverò a spiegare come trattare Excel come un DB, accedendovi attraverso il modello ad oggetti ADO e prelevando dei valori da un Foglio di Lavoro, importandoli su una Tabella di un Database Access. November 03 Inserire delle ProgressBar in una ListView con Visual Basic 6Spesso capita che un programmatore si trovi a prendere spunto da altre applicazioni per realizzare ciò che gli passa per la testa. A volte è un'esigenza reale, a volte è solo la curiosità di confrontarsi con se stessi, cimentandosi in qualcosa che, probabilmente, sul momento non è utile. Ovviamente non ritengo queste attività "tempo perso", prima di tutto perchè tutto ciò che ci spinge a ragionare vale come bagaglio culturale e secondo perchè c'è la possibilità che, un giorno, si debba realizzare quella determinata cosa, e la si abbia già pronta! La mia "ispirazione" in questo caso, è stata la ListView di e-Mule. Come molti sapranno, in una delle sue colonne è presente una barra di avanzamento che sta ad indicare lo stato di avanzamento del download di un file. Incuriosito, ho deciso di provare a realizzare una cosa del genere con una ListView standard di Visual Basic 6. La barra di avanzamento che ho realizzato non è della stessa complessità di quella di e-Mule, nel senso che non tiene conto di un avanzamento frammentato, ma mi ritengo soddisfatto del risultato e della sua funzionalità. Il principio che sta alla base è quello di realizzare la barra di avanzamento in un'immagine bitmap, assegnandola successivamente al SubItem del controllo ListView. Per prima cosa, cominciamo la realizzazione di questo progetto aggiungendo i Microsoft Windows Common Controls 6.0 ai componenti. Possiamo farlo andando su Progetto -> Componenti e selezionandoli dalla lista dei Controlli. Poi prepariamo il Form che farà da base come in figura, rispettando la nomenclatura dei controlli: ![]() Come accennavo prima, abbiamo bisogno che la nostra barra sia formata da una serie di bitmap, ognua delle quali rappresenterà uno stadio di avanzamento, ma nella ListView facente parte dei Common Controls non è possibile inserire direttamente un'immagine. Essa per essere assegnata ad un Item o SubItem deve risiedere su una ImageList. La prima cosa da fare, quindi, è popolare l'ImageList con le immagini della barra di avanzamento. Ovviamente le immagini della ProgressBar dovranno essere proporzionate alla colonna nella quale dovranno essere inserite, per cui definiamo una variabile pubblica nel form che ci consente di variare con poco sforzo e in qualunque momento, la sua collocazione. Codice: Dim pBarCol As Integer Adesso possiamo creare la routine che disegna materialmente una ProgressBar. Per farlo, abbiamo bisogno del riferimento alla ListView per calcolare altezza e larghezza della barra, del valore di colonna nella quale dovrà essere inserita e, infine, del suo valore. La routine MakeProgressBar, per spiegarla in breve, si occupa di:
Questa è la routine completa. Codice: Sub MakeProgressBar(lw As ListView, colHead As Integer, Value As Integer) Prima ho detto che di ProgressBar ne andranno create una per ogni valore, quindi ci serve una routine che si occupi di generarle, passando alla MakeProgressBar i valori sequenzialmente corretti, da 1 a 100. Codice: Sub CreateProgressBars() Come si può notare, la routine si occupa di eliminare l'assegnazione della ImageList dalla ListView poichè altrimenti non sarebbe possibile popolarla o cancellarla, lancia la generazione delle barre attraverso il ciclo da 1 a 100 e riassegna la ImageList alla ListView. Vedremo in seguito che questa routine tornerà utile anche quando sarà necessario aggiornare la visualizzazione del controllo al variare della dimensione della colonna che ospita la ProgressBar. Arrivati a questo punto abbiamo popolato la nostra ImageList con le immagini rappresentanti tutti i valori di avanzamento necessari. Non rimane che assegnare quella opportuna, in base al valore da rappresentare, al SubItem di nostro interesse. Per rendere le cose più semplici ho predisposto 2 routines: SetValue e GetValue. La SetValue controlla, innanzitutto, se il valore passato rispetta il range di 1 a 100 consentito, quindi assegna al SubItem scelto l'immagine corrispondente al valore da rappresentare, tramite la proprietà ReportIcon. In questa routine, per tenere traccia del valore attualmente rappresentato, viene conservato, nella proprietà Tag del SubItem, anche il valore numerico passato come argomento. Codice: Sub SetValue(itm As ListItem, Value As Integer) Per ottenere il valore attualmente impostato in un determinato SubItem basta usare la Function GetValue, passando l'Item di riferimento come argomento: Codice: Function GetValue(itm As ListItem) As Integer Procediamo, adesso, al monitoraggio della larghezza delle colonne della ListView, poichè in corrispondenza di una variazione della loro larghezza sarà necessario adeguare la dimensione delle ProgressBar. Purtroppo la ListView non fornisce nessun feedback riguardante l'evento di espansione o riduzione delle colonne, per cui possiamo ricorrere ad un semplice Timer, il quale si occuperebbe di controllare ciclicamente che le dimensioni della colonna contenente le ProgressBar non sia variata. Non è un'operazione molto impegnativa, poichè il "lavoro" di ridimensionamento verrebbe eseguito solo nel caso in cui ci sia una variazione di dimensioni. Questa è la routine di evento del Timer nominato tResize: Codice: Private Sub tResize_Timer() Come dicevo, attraverso una variabile Static (WidthMonitor) si controlla che la dimensione rilevata non sia differente rispetto al controllo precedente, nel qual caso le ProgressBar verrebbero rigenerate (sulla base della nuova dimensione) attraverso l'invocazione della CreateProgressBar. Abbiamo adesso tutti gli strumenti per poter utilizzare le ProgressBar nel nostro controllo ListView e quello che dobbiamo fare, per provare il tutto è disporre di un certo numero di Item nella nostra ListView ai quali assegnare le barre. Sfruttiamo l'evento Load del form, per formattare correttamente la ListView, popolandola con degli Item e dei dati fittizi. Codice: Private Sub Form_Load() Si noterà nel codice, che alla ListView viene aggiunta una colonna iniziale che ho definito "Dummy" e che ha larghezza 0. Questo è, più che altro, un escamotage di natura estetica: quando si assegna un'immagine alla proprietà ReportIcon di un SubItem, lo stesso spazio che essa occupa, ma vuoto, viene aggiunto anche accanto all'Item nella prima colonna. Esteticamente è poco gradevole per cui ho preferito nascondere la prima colonna, lasciandola comunque non popolata. Se lanciamo adesso il progetto possiamo già notare che la nostra ListView è popolata e con le barre di avanzamento (tutte settate a valore 0) inserite nella terza colonna. Possiamo anche variare la dimensione di quest'ultima, notando che le ProgressBar si ridimensioneranno di conseguenza. Allo stato attuale il progetto è già funzionante e potrebbe essere usato per rappresentare i valori di avanzamento dei vari "files", poichè basterebbe impostare attraverso la SetValue il corretto valore all'Item interessato, per notare l'avanzamento della barra al valore settato. Per una prova generale, però, abbiamo inserito sul form (vedi immagine iniziale) un secondo Timer e un CommandButton denominati rispettivamente tProgress e Command1. Il Command1 serve semplicemente per avviare/stoppare il Timer, mentre all'interno della routine di evento tProgress_Timer() vengono generati dei valori casuali "decidendo" arbitrariamente l'uno o l'altro Item, incrementando il valore della ProgressBar di un tot, anch'esso casuale. Ecco entrambe le routine di evento: Codice: Private Sub Command1_Click() Codice: Private Sub tProgress_Timer() Questo è il risultato finale con le barre in avanzamento: ![]() I colori delle barre possono essere variati a piacere, basta intervenire sulle variabili BarBorder, BarBack, BarNormal e BarComplete dichiarate nella routine MakeProgressBar. Come al solito, potete scaricare il progetto completo dalla sezione Download -> Software, oppure cliccando qui: ![]() Non esitate a contattarmi per farmi presenti inesattezze o chiedere ulteriori chiarimenti. October 14 Array di Controlli in VBA di ExcelIl VBA (Visual Basic for Applications) relativo alle varie applicazioni Office quali Excel, Word, Access, etc. è uno strumento decisamente utile per coloro i quali intendono "espandere" le già ampie possibilità offerte da questi software, implementando da soli caratteristiche non previste dall'applicazione originale o creando, ad esempio, una maschera per il data-entry che faccia da front-end per il proprio documento. Proprio riguardo l'aspetto del data-entry, chi è abituato a lavorare in Visual Basic 6, utilizzando il VBA potrebbe trovarsi ad operare in un ambiente un po' più stretto considerato che in quest'ultimo mancano strumenti importanti che renderebbero agevole la gestione di molti controlli dello stesso genere. Uno di questi è l'array di controlli. Un array è definito come una serie di variabili identificate da uno stesso nome al quale è possibile riferirsi utilizzando un numero ovvero un indice. Analogamente, un array di controlli, è una serie di controlli dello stesso genere che condividono il nome. Anche in questo caso ogni controllo è raggiungibile attraverso un indice numerico. La cosa che rende gli Array di Controlli decisamente utili è l'esposizione degli eventi in maniera comune a tutti i suoi elementi e le Routines di evento sono in grado di restituire un indice che identifica il controllo che ha scatenato l'evento stesso. In Visual Basic 6 è molto semplice creare e gestire un Control Array, poichè questi vengono gestiti direttamente dall'ambiente di sviluppo. Non si può dire alltrettanto per il VBA dove, se vogliamo un array di controlli, dobbiamo crearcelo e gestircelo da soli. In VBA, quando si dispongono i controlli sul Form, essi vengono a far parte della collection Controls che è possibile ciclare per effettuare delle operazioni su più controlli, anche di genere diverso, a prescindere dal loro nome. Questo è un breve esempio per dimostrare come è possibile azzerare il contenuto di tutti i TextBox presenti su un Form utilizzando la collection Controls: Codice: Sub AzzeraTxt(frm As UserForm) Se si inserisce la suddetta routine in un Modulo, sarà possibile richiamarla da qualsiasi UserForm semplicemente scrivendo: Codice: AzzeraTxt Me Purtroppo, se è vero che tramite la collection Controls abbiamo accesso ad una serie di controlli pur se non indicizzati e con nomi differenti è altrettanto vero che non possiamo che ricevere singolarmente gli eventi relativi a ciascuno dei controlli presenti sul Form. Questo ci costringe a dover scrivere in maniera ripetitiva del codice per inserirlo negli eventi relativi a tutti i controlli che ci interessa gestire. Una maniera interessante di far fronte al problema è l'utilizzo delle Classi. Utilizzando una Classe si possono gestire attraverso un solo oggetto molti aspetti relativi a più oggetti facenti parte di uno stesso insieme. All'interno di una Classe si possono definire Proprietà, Metodi ma soprattutto Eventi, il che è proprio ciò che ci interessa, considerato che potremo rilasciare degli eventi comuni a tutti i controlli gestiti dalla Classe stessa. Per fare in modo di avere la maggiore flessibilità possibile ho pensato di realizzare 2 Classi. La prima rappresenta l'oggetto vero e proprio, ovvero l'Item della Array di controlli che andremo a gestire, mentre la seconda si occuperà di fare da "tramite" tra la gestione dei singoli Item disposti in una Collection e la nostra applicazione. La prima delle due Classi è molto semplice e non fa altro che definire gli oggetti relativi alle varie tipologie di controlli che si desiderano gestire (TextBox, CheckBox, Images, etc...) ed il rilascio degli eventi peculiari per ogni controllo. In considerazione del fatto che la classe può essere istanziata più volte per ottenere più Array di controlli, si è manifestato il problema di identificare la Classe "madre" alla quale restituire la chiamata dell'evento. Per ovviare a ciò è bastato utilizzare un ulteriore oggetto "CallerObject" che in pratica permette ad ogni Item di "sapere" a quale Classe appartiene. Ecco il codice della classe cMatrixItem: Codice: Public WithEvents itmTextBox As MSForms.TextBox Come si può notare gli eventi definiti sono davvero pochi come pure i tipi di oggetti gestiti ma, per analogia, è immediata l'aggiunta sia di ulteriori tipi di controlli che di ulteriori eventi ad essi relativi. Andiamo adesso a progettare la Classe che ospiterà la Collection vera e propria. Definiamo prima di tutto gli oggetti che la classe dovrà gestire: gli Item e la Collection. Codice: Dim itm As cMatrixItem L'oggetto itm è dichiarato come cMatrixItem e servirà per tipizzare correttamente l'oggetto da aggiungere alla Collection. Quindi definiamo gli Eventi che la Classe sarà in grado di rilasciare. Come detto prima, gli eventi qui dichiarati a scopo esemplificativo sono pochi, ma è possibile arricchire, semplicemente dichiarandoli, la lista di eventi che la Classe sarà in grado di rilasciare in risposta alle azioni compiute sui controlli gestiti dalla Collection. Codice: Public Event Click(item As Object) Nel nostro caso, al posto di restituire esclusivamente un indice, nelle Routines di Evento forniremo un riferimento all'oggetto che l'evento lo ha generato. Restituire solo l'indice servirebbe a poco visto che i controlli in VBA non sono comunque indicizzabili, rendendo di conseguenza difficile l'identificazione del controllo stesso in relazione all'evento scatenato. I moduli di Classe possiedono un evento che viene scatenato quanto esse vengono istanziate nel codice che le utilizza: l'evento Class_Initialize(). Questo possiamo sfruttarlo per "dare vita" alla nuova Collection di controlli: Codice: Private Sub Class_Initialize() Occupiamoci di definire adesso un metodo Add attraverso il quale, da codice, potremo aggiungere alla Collection i controlli che ci interessa gestire come Array Codice: Public Sub Add(ByVal actItm As Object) Nel metodo appena definito si può notare che il controllo è visto in maniera generica ma viene fatta una distinzione sul suo tipo tramite l'If...Then. Questo avviene perchè non tutti i controlli possiedono le stesse proprietà o i medesimi eventi, anche se molti condividono entrambi. Anche in questo caso gli oggetti considerati sono solo 3, ma la possibilità di espandere il range di tipologie è sempre valida e fattibile in maniera immediata. Continuiamo lo sviluppo della Classe aggiungendo 2 Proprietà in sola lettura: Count e ItemCollection per ottenere rispettivamente il numero di elementi già presenti nell'Array e il riferimento ad uno dei controlli dell'Array attraverso un Indice numerico. Codice: Public Property Get Count() As Single Ricordo che anche nella ItemCollection è possibile aggiungere altri tipi di controlli analogamente a come già fatto per le 3 tipologie in esame. Passiamo adesso a definire le routines che rilasceranno gli eventi veri e propri attraverso la loro invocazione (da parte dell'Item) dei metodi del CallerObject Codice: Friend Sub ItemClick(item As Object) Inutile dire che anche in questo ennesimo caso si possono aggiungere tutti gli eventi necessari relativi ai vari controlli. Ovviamente bisogna badare al fatto che molti controlli possono condividere eventi dello stesso genere, come nel caso dei controlli Image e CheckBox che condividono l'evento Click. In questi casi basterà dichiarare una sola volta la Routine ItemClick. Questo è il codice completo della Classe cCtlMatrix: Codice: Dim itm As cMatrixItem La progettazione delle Classi è terminata. Non rimane che creare un semplice progetto di prova per valutare la correttezza del comportamento. Aggiungiamo un nuovo UserForm e disponiamo su di esso alcuni controlli Image, delle CheckBox, qualche TextBox, un CommandButton e una Label. Lasciamo pure i nomi di default, come in figura. ![]() Usiamo questo codice per il Form: Codice: Dim WithEvents TextBoxArray As cCtlMatrix Per dubbi o chiarimenti non esitate a contattarmi. E' possibile scaricare il file di Excel con il progetto completo da qui: ![]() |
Benvenuto in questo piccolo angolino di Web! Se ti va, lascia un commento per testimoniare il tuo passaggio!
Francescowrote:
Bellissime le immagini 3D. Mi ha colpito "Terrace" che se non mi sbaglio è stata pubblicata in una rivista di grafica 3D.
Non sono un grafico ma mi piace ammirare le opere di questo genere. Complimenti di Nuovo. Gandalfrank
Jan. 4
|
|||||||||||||||||||||||||||||
|
|