TheTruster's Box

  • Increase font size
  • Default font size
  • Decrease font size
Home Programmazione Articoli Compilare un Modello Word da Visual Basic 6

Compilare un Modello Word da Visual Basic 6

E-mail Stampa PDF

Visual Basic 6, come è noto, consente di creare anche applicazioni di tipo gestionale. Questo tipo di software deve possedere in molti casi, la possibilità di stampare documenti, resoconti, prospetti, lettere commerciali e quant'altro.

Nonostante VB6 disponga comunque di un buon seppur leggermente criptico sistema di reporting, a volte questo può non bastare per le proprie necessità, soprattutto se si desidera uno stile fortemente personalizzato sulle stampe da produrre.

La metodologia che vorrei esporre in questo articolo è quella di creare i propri modelli in Word, ottenendo così la possibilità di personalizzazioni piuttosto variegate, che contemplano ad esempio formattazioni particolari sia dei caratteri che dei paragrafi in genere, l'inserimento di tabelle, immagini, forme e così via.

L'unica accortezza che è necessario utilizzare è l'utilizzo dei Campi Modulo, nei punti dove sarà necessario inserire i dati provenienti dalla nostra applicazione, così che possano essere identificati e valorizzati.

Apriamo quindi il nostro Microsoft Word (va sicuramente bene qualsiasi versione dalla 2000 in poi) e iniziamo a scrivere, ad esempio, una lettera commerciale per ricordare ad un nostro cliente che la sua polizza assicurativa è scaduta:

Come dicevo prima, avremo l'accortezza di inserire, nei punti in cui sarà necessario inserire i dati relativi al cliente o alla polizza, dei Campi Modulo reperibili visualizzando la barra degli strumenti Moduli. Qualora non fosse già presente, per visualizzarla andiamo sul menu Visualizza -> Barre degli Strumenti -> Moduli.

Diventerà visibile la seguente barra e l'icona adeguata per l'inserimento di un Campo Modulo è la prima a sinistra (nel cerchio rosso)

Ogni campo inserito andrà adeguatamente rinominato, al fine di identificarlo in maniera esatta da codice, una volta terminato il modello. Per questo scopo possiamo fare doppio click sul campo da rinominare. Si aprirà la finestra delle impostazioni per il campo di testo, quindi nella sezione Impostazioni Campo variamo il contenuto del campo Segnalibro attribuendo il nome che riteniamo più opportuno.


Per esercizio, anzichè creare un modello da zero, si può prendere a base il documento Word fornito a corredo dell'articolo che contiene, opportunamente predisposti e nominati, dei campi di esempio.

A questo punto, per evitare modifiche indesiderate alla lettera-modello, si può "bloccare" il testo, lasciando comunque invariata la possibilità di editare i campi di testo. Per bloccare il modello basta cliccare l'icona del lucchetto sulla barra degli strumenti Moduli

Saviamo pure il documento, nominandolo opportunamente, per il futuro uso da Visual Basic.

Per rendere ancora più semplice l'attuazione di questo metodo, ho incluso nel progetto di esempio relativo all'articolo anche un Database Access (.mdb) contenente 2 clienti e 2 polizze. Ovviamente il DB è assolutamente scarno e adatto all'esclusiva funzionalità esplicativa che l'articolo intende avere.

Ci interfacceremo a questo DB da Visual Basic utilizzando il modello ad oggetti ADO, per cui sarà bene ricordarsi inserirlo tra i riferimenti in Visual Basic, prima di iniziare a scrivere il codice. Non sarà necessario farlo, in quanto già inserito, nel caso in cui si usi il progetto Visual Basic fornito in allegato.

Da VB6 è veramente semplice accedere ai campi modulo precedentemente inseriti, poichè si utilizzerà l'automazione OLE per definire da codice un'istanza di Word, sfruttando così il modello ad oggetti fornito dal pacchetto Office. Attraverso l'automazione possiamo accedere ad ogni singolo oggetto, proprietà e metodo dell'applicazione e, di conseguenza, anche ai campi modulo, visto che fanno parte di una Collection denominata FormFields che è possibile indirizzare sia numericamente che - cosa più importante - attraverso il segnalibro impostato in fase di definizione dei campi.

Un esempio per tutti:

wDoc.FormFields("tLuogo").Result = "Sede della Ditta"

wDoc, come si vedrà nel codice di esempio in allegato, definisce l'istanza di Word aperta da codice.

L'applicazione VB6 è anch'essa ridotta all'essenziale e consta di un solo Form che ospita una ListBox e 2 pulsanti.

La ListBox viene popolata con i dati presenti sul DB utilizzando un Recordset ADO e un ciclo While, mentre la compilazione vera e propria del modello Word, è affidata al codice presente nell'evento Click di uno dei pulsanti:

 
Private Sub cmdCompila_Click()
 
Dim wApp As Object
Dim wDoc As Object
Dim SQL As String
Dim rsPolizza As ADODB.Recordset
Dim rsCliente As ADODB.Recordset
Dim sNomeLettera
 
'Apro il recordset della polizza selezionata
Set rsPolizza = New ADODB.Recordset
SQL = "SELECT * FROM tPolizze WHERE IDPolizza = " & lstPolizze.ItemData(lstPolizze.ListIndex)
rsPolizza.Open SQL, cnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
 
'Apro il recordset del cliente relativo alla polizza selezionata
Set rsCliente = New ADODB.Recordset
SQL = "SELECT * FROM tAnagrafica WHERE IDCliente = " & rsPolizza("rifIDCliente").Value
rsCliente.Open SQL, cnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
 
'Apro il file Word del Modello della Lettera
Set wApp = CreateObject("Word.Application")
Set wDoc = wApp.Documents.Open(App.Path & "\LetteraEsempio.doc")
 
'Compilo i campi non corrispondenti al recordset
wDoc.FormFields("tNumPolizzaOgg").Result = rsPolizza("NumPolizza").Value
wDoc.FormFields("tIntestazioneLett").Result = rsCliente("Cognome").Value & " " & rsCliente("Nome").Value
wDoc.FormFields("tLuogo").Result = "Sede della Ditta"
wDoc.FormFields("tData").Result = Date 'Adesso
wDoc.FormFields("tTermineMax").Result = DateAdd("y", 20, Date) ' Tra 20 giorni da adesso

On Error Resume Next 'Salta l'errore se un campo non esiste

'Con un ciclo riempio i campi corrispondenti sul file di Word
For i = 0 To rsCliente.Fields.Count - 1
    wDoc.FormFields("t" & rsCliente.Fields(i).Name).Result = rsCliente.Fields(i).Value
Next i
 
For i = 0 To rsPolizza.Fields.Count - 1
    wDoc.FormFields("t" & rsPolizza.Fields(i).Name).Result = rsPolizza.Fields(i).Value
Next i
 
On Error GoTo 0 'Ripristina il gestore degli errori

'Salvo la lettera compilata con il nome scelto dall'utente
sNomeLettera = InputBox("Specificare il nome della lettera")
 
If Not sNomeLettera = "" Then
    wDoc.SaveAs App.Path & "\" & sNomeLettera
End If
 
'Chiudo il documento Word e annullo le variabili
wDoc.Close (False)
wApp.Quit
Set wDoc = Nothing
Set wApp = Nothing
 
'Chiudo i Recordset e annullo le variabili
rsCliente.Close
rsPolizza.Close
Set rsCliente = Nothing
Set rsPolizza = Nothing
 
End Sub
 

Come si può notare, innanzitutto vengono definiti gli oggetti indispensabili all'operazione di compilazione, ovvero l'applicazione Word, il Documento e i Recordset relativi al Cliente e alla Polizza, quindi vengono aperti i Recordset con opportune frasi SQL, sulla base della selezione effettuata sulla ListBox.

Il documento Word viene aperto con 2 semplici righe:

 
Set wApp = CreateObject("Word.Application")
Set wDoc = wApp.Documents.Open(App.Path & "\LetteraEsempio.doc")
 

Considerato che per definire i Campi Modulo di Word ho utilizzato gli stessi nomi dei campi presenti nelle tabelle del DB, aggiungendo una "t" come prefisso, riesce particolarmente semplice popolare il documento con un ciclo For...Next.

Per evitare errori sui campi che sul documento Word non verrebbero trovati (IDCliente, rifIDCliente, IDPolizza) ho attivato un gestore di errori (On Error Resume Next) che permette di ignorare l'errore, qualora si presenti. In questo caso l'uso l'uso di On Error Resume Next è sicuro e controllato, perchè l'unico errore che può presentarsi nella circostanza in cui viene usato è la mancanza di un nome di campo, ed è proprio quello che vogliamo ignorare.

Alla fine dei cicli, infatti, l'esposizione degli errori viene ripristinata con On Error Goto 0

Terminata la valorizzazione dei campi del documento, viene richiesto un nome di file, che servirà per salvare il modello con un altro nome, conservando così la copia originale.

Ovviamente, in una situazione reale si potrà prevedere una gestione più articolata del documento risultante, implementando, ad esempio, la stampa del modello ottenuto, piuttosto che il salvataggio in un'altra cartella attraverso una CommonDialog o l'invio tramite posta elettronica.

Non esitate nel fornire i vostri commenti, in caso vogliate farmi presente delle inesattezze o per richiedere ulteriori spiegazioni, in merito all'argomento trattato.

Scarica il Progetto di Esempio relativo a questo Articolo

 

HEADER  

 
+2 #1 Y-m-d H:i
A me servirebbe molto, ma è possibile solo usando VBA6 ? non si possono interfacciare direttamente con qualche altro metodo magari?
 
 
+1 #2 Y-m-d H:i
Grazie dell'attenzione, ciao e complimenti ancora :)
 
 
0 #3 TheTruster Y-m-d H:i
QUOTE_PREFIX gianniQUOTE_SUF FIX
A me servirebbe molto, ma è possibile solo usando VBA6 ? non si possono interfacciare direttamente con qualche altro metodo magari?


Ciao Gianni,
La cosa è fattibile senz'altro anche da VBA.
Nell'editor di VBA dell'applicazione che intendi usare per accedere al DB, ti basta spuntare tra i riferimenti (Strumenti -> Riferimenti...) la libreria Microsoft ActiveX Data Object 2.8 o la più recente che hai.

L'accesso a Word viene realizzato attraverso l'uso del Late Binding, quindi non hai bisogno di referenziare nulla.

Tutto il codice dovrebbe rimanere pressochè identico ed è quello presente nell'articolo (Sub cmdCompila_Clic k())
 
 
0 #4 Y-m-d H:i
Ciao, complimenti per l'articolo e per l'ottimo esempio. mi chiedevo se fosse possibile inserire come si fa con i datareport un elenco di nomi in un documento word sfruttando i campi modulo. grazie per l'attenzione.
 
 
0 #5 TheTruster Y-m-d H:i
QUOTE_PREFIX luigiQUOTE_SUFF IX
mi chiedevo se fosse possibile inserire come si fa con i datareport un elenco di nomi in un documento word sfruttando i campi modulo. grazie per l'attenzione.


Ciao Luigi, in teoria sarebbe possibile, ma dovresti prevedere, a priori, il numero di nominativi da inserire, predisponendo di conseguenza il numero sufficiente di campi Modulo.
Ritengo sia meglio lasciar perdere i campi modulo in favore di una tabella, che puoi tranquillamente creare e compilare da codice.

Per un aiuto sul codice da utilizzare ti conviene registrare delle macro in Word, studiandone la struttura e cercando di adattarla al tuo contesto.
 
 
0 #6 Y-m-d H:i
Ciao, complimenti per l'articolo però mi chiedevo se fosse possibile invece stampare tutti i record della tabella in sequenza. Ho provato ma mi blocca tutte le volte per salvare il file.
Grazie comunque e ciao
 
 
-1 #7 TheTruster Y-m-d H:i
QUOTE_PREFIX GiovanniQUOTE_S UFFIX
mi chiedevo se fosse possibile invece stampare tutti i record della tabella in sequenza. Ho provato ma mi blocca tutte le volte per salvare il file.


Ciao Giovanni,
Il comportamento che riscontri è normale, visto che la routine di compilazione del documento prevede il salvataggio del documento.
Se a te non interessa il salvataggio ma solo la stampa di ogni record, allora devi modificare la routine in modo che, al posto del salvataggio, venga eseguita la stampa.

In particolare, dovresti eliminare queste righe:

'Salvo la lettera compilata con il nome scelto dall'utente
sNomeLettera = InputBox("Specificare il nome della lettera")

If Not sNomeLettera = "" Then
wDoc.SaveAs App.Path & "\" & sNomeLettera
End If

sostituendole con queste:

wDoc.PrintOut Background:=False
DoEvents

Spero ti sia utile.
 
 
0 #8 Y-m-d H:i
Ciao! fino a qui io ci sono arrivata! a me servirebbe poter creare sulla base di un modello word (esempio una fattura) contenente una tabella con 20 righe, poter creare un'altra pagina identica al modello che sto trattando nell'ambito dello stesso documento. Mi spiego meglio: dal mio applicativo devo stampare una fattura che contiene 30 righe di dettaglio. La pagina del modello ne prevede 20. Creando lo stesso documento fatturaCliente devo poter dire a word crea una nuova pagina utilizzando lo stesso modello.
Potete aiutarmi?
 
 
+1 #9 TheTruster Y-m-d H:i
QUOTE_PREFIX FraQUOTE_SUFFIX
dal mio applicativo devo stampare una fattura che contiene 30 righe di dettaglio. La pagina del modello ne prevede 20. Creando lo stesso documento fatturaCliente devo poter dire a word crea una nuova pagina utilizzando lo stesso modello.


Ciao Fra,
Fermo restando che per la stampa di una fattura non ritengo che il metodo dell'articolo sia molto pratico, quello che posso consigliarti è di creare un ciclo sulle righe da stampare.
Quando arrivi a 20 stampi la fattura e cancelli le righe, quindi scrivi le restanti 10.
Altrimenti puoi creare una seconda pagina con le rimanenti 10 righe.
 
 
-3 #10 Y-m-d H:i
Ciao TheTruster, scusami ma non ho ben capito cosa intendi. Quello che vorrei fare e' creare una seconda pagina con le righe rimanenti.

Mi spiego meglio: dalla mia applicazione apro un modello word che ha la struttura di una fattura su una sola pagina, riempio i campi utilizzando i segnalibri (quindi associo ad esempio al segnalibro ART1 il codice articolo della prima riga, ART2 il codice articolo della seconda, ecc.), arrivo fino alla fine della tabella prevista dal mio modulo, ma mi serve di stampare ancora 10 articoli (righe). A questo punto vorrei mantenere il documento Fattura che ho creato utilizzando il modello Fattura e aggiungere un'altra pagina (nello stesso documento) che sia sempre una copia del modello. Io sono riuscita a fare tutto, ma quando creo un'altra pagina mi si crea una pagina bianca nello stesso documento e non con la struttura del modello. Come posso fare?

Considera che io sono autodidatta, ho scopiazzato qua e la cercando di capire e riutilizzare quello che ho trovato. Mi sembra di aver capito che devo creare delle Section del documento.....ma non sono riuscita ugualmente a risolvere il problema. In realta' io cerco di utilizzare WORD perche' ho trovato piu' informazioni, ma sarebbe uguale utilizzare un pdf.
Sai aiutarmi?
 
 
0 #11 TheTruster Y-m-d H:i
Ciao Fra,

Quando dicevo di creare una seconda pagina intendevo di realizzare un secondo modello, sulla seconda pagina, con i campi adeguatamente contrassegnati con i segnalibri, ovviamente susseguenti a quelli già utilizzati per la prima.

Dal codice basterà, come avviene già per la prima pagina, indirizzare i valori da stampare sui corrispondenti segnalibri, senza far caso a quale pagina essi si riferiscono.

In pratica, se dovrai stampare sul segnalibro "ART30" e questo si trova sulla seconda pagina, non farà alcuna differenza e il campo verrà riempito ugualmente.
 
 
0 #12 Y-m-d H:i
Si ok. Ci avevo pensato, non so se puo' essere corretto perche' io dico 2 pagine, ma potrebbero essere 6-7-8 o che ne so'!!!
Cosa dovrei fare: creare un modello con 10 pagine (che comunque sono tante), assegnando segnalibri diversi. Poi creare un documento utilizzando il modello e procedere al riempimento, quando ho finito cancello le pagine rimanenti. Non saprei.....pensavo di trovare una soluzione diversa....a te sembra valida?
 
 
0 #13 TheTruster Y-m-d H:i
QUOTE_PREFIX FraQUOTE_SUFFIX
io dico 2 pagine, ma potrebbero essere 6-7-8 o che ne so'!!!
[...]
creare un modello con 10 pagine (che comunque sono tante), assegnando segnalibri diversi.
[...]
pensavo di trovare una soluzione diversa....a te sembra valida?


Sinceramente te lo avevo già detto qualche risposta fa...
Nel tuo caso il metodo dell'articolo non mi sembra confacente all'esigenza.
Personalmente cambierei totalmente approccio. Non so consigliarti quale perchè non conosco il contesto della tua applicazione, ma in linea generale, se usi Visual Basic 6 potresti orientarti sul DataReport, mentre se usi un'altra applicazione del pacchetto Office potresti pensare all'uso di Excel...
Comunque non vorrei andare troppo fuori tema, rispetto all'argomento dell'articolo
 
 
+1 #14 Y-m-d H:i
ok. Grazie! Provo a studiare anche altre soluzioni.
 
 
+1 #15 Y-m-d H:i
Ciao complimenti per l'articolo e vista la tua esperienza magari riesci a darmi un piccolo aiuto sulla questione moduli di word. La mia app funzione esattamente come hai spiegato tu ma il mio problema è che in un modulo devo metterci un testo su più righe, mi spiego meglio, la ragione sociale indicata nel doc è un campo unico suddiviso su più righe da dei cr lf es:
ragione sociale
via.....
cap citta provincia
Mi serve mantenere il layout inserito e quindi passare sia i testo che i cr + lf per far si che il testo si presenti nello stesso modo come inserito nella app. Invece nel modulo mi finisce tutto in fila una parola dietrol'altra. Ho controllato cosa gli arriva e pare che al modulo arrivi testo + cr, CHR(13), ma non il Line Feed chr(10) malgrado lo passi insieme al testo. Hai un idea di come possa risolvere il problema?

Grazie
 
 
+1 #16 TheTruster Y-m-d H:i
QUOTE_PREFIX FabioQUOTE_SUFF IX
il mio problema è che in un modulo devo metterci un testo su più righe, mi spiego meglio, la ragione sociale indicata nel doc è un campo unico suddiviso su più righe da dei cr lf es


Prova ad effettuare un replace dei vbCrLf con Chr(13)+Chr(10)
 
 
0 #17 Y-m-d H:i
Si penso sia l'unica soluzione e la via migliore dovrebbe essere una macro di word, visto che da vb6 non riesco a mandare il carattere LF
CIAO GRAZIE
 
 
0 #18 Y-m-d H:i
Ciao, complimenti per la chiarezza nella spiegazione. Ho un problema con un'applicazione simile, che ho sviluppato tra excel e word: ho utilizzato prima i segnalibri, poi i campi modulo, ma ho sempre lo stesso problema: quando copio da excel a word, i dati non vengono copiati nelle posizioni dove ho piazzato i campi, per esempio se ne piazzo tre in fila, il risultato è che i valori copiati sono scritti su tre righe di seguito, e non riesco a capirne il motivo....
Hai qualche suggerimento utile? non ci sto capendo il verso!!!
Grazie.
 
 
0 #19 Y-m-d H:i
ho appena scaricato il progetto, non l'ho ancora provato volevo sapere se era possibile usarlo anche con OPEN OFFICE.
Complimenti, e grazie per il contributo che dai allo sviluppo con VB6
 
 
0 #20 TheTruster Y-m-d H:i
QUOTE_PREFIX pietroQUOTE_SUF FIX
ho appena scaricato il progetto, [...] volevo sapere se era possibile usarlo anche con OPEN OFFICE.


Ciao Pietro, il codice é relativo al VBA di Excel e così com'è non si può usare in Writer/Base di Open Office.

Grazie per i complimenti
 
 
0 #21 Y-m-d H:i
scopro solo oggi questo articolo ed è ottimo, vi chiedo però
come posso applicarlo ad un report di access, ovvero avrei
bisogno che mi riportasse più record contemporaneame nte nel foglio word es. lo utilizzo per ordinare degli articoli quindi
più righe. grazie ancora attendo gradito aiuto
 
 
0 #22 TheTruster Y-m-d H:i
QUOTE_PREFIX GianniQUOTE_SUF FIX
scopro solo oggi questo articolo ed è ottimo, vi chiedo però
come posso applicarlo ad un report di access, ovvero avrei
bisogno che mi riportasse più record contemporaneame nte nel foglio word es. lo utilizzo per ordinare degli articoli quindi
più righe. grazie ancora attendo gradito aiuto


Ciao Gianni, il codice e la metodologia esposti nell'articolo sono applicabili solo a word. Il report di Access necessita di altri metodi per realizzare quello che ti serve.
 

Sondaggio

Cosa vorresti vedere di più su TheTruster's Box?
 

Utenti on-line

 256 visitatori online

MasterDrive.it



Aggiungi TheTruster's Box ai preferiti!


Scarico di Responsabilità


Tutto il materiale pubblicato è di libero utilizzo.
E' gradito il riferimento al Sito ed all'autore nel codice o nel progetto in cui questo viene utilizzato. NON si garantisce in alcun modo per errori di programmazione o eventuali danni causati da bugs, nè si è responsabili di alcuna problematica inerente all'utilizzo del codice o dei prodotti esposti. Chi usa il materiale esposto nel sito lo fà a proprio rischio assumendosene la completa responsabilità.

Questo sito utilizza cookie, anche di terze parti, per personalizzare i contenuti. Per informazioni o negare il consenso a tutti o ad alcuni cookie leggi la nostra Cookie Policy. Chiudendo questo banner, scorrendo questa pagina o cliccando su qualunque suo elemento acconsenti all'uso dei cookie. Per informazioni sui Cookies che usiamo e su come cancellarli, guarda la nostra Cookie Policy.

Accetto esplicitamente i Cookies di questo sito.

EU Cookie Directive Module Information