Il blog di Gianni Giaccaglini

Blog su VBA e VSTO
Gianni Giaccaglini

My Links

News

NB - V. anche gli ARTICOLI (in fondo a questa barra)
Solo quesiti validi a: giannigiac@tin.it
Il mio Best seller su VBA
(v. www.hoepli.it)


Il mio ultimo libro su Open XML
(v. www.FAG.it):



La mia nipotina ELISA

Foto con dedica a ME di
Bill Gates giovanissimo
nei mitici anni 80!

Categorie Post

Categorie Articoli

Archivio

Immagini

Blog Stats

Copiare intestazioni di tabelle Word (uno sfizio, però istruttivo)

Copiare intestazioni di tabelle Word (uno sfizio, però istruttivo)

Di ritorno dalle vacanze (e da rogne infinite) propongo al visitatore una varietà di soluzioni a un problemino sollevato da un tal Rick. Come dirò al termine, più che altro è uno sfizio di cui non trovo valore pratico, tuttavia è una curiosità che chiarisce il trattamento di tabelle in Word, ergo ha una certa valenza se non altro didattica.

Ma ecco il quesito del summenzionato Rick. Si abbiano in un documento Word due tabelle di pari numero di colonne come le seguenti:

TABELLA 1

Prodotto

Prezzo

Quantità

Importo

Sconto

Netto

 

 

 

 

 

 

 

 

 

 

 

 

 

TABELLA 2

Questo

Quello

Eccetera...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Si desidera, nel modo più automatico possibile, che la prima riga di intestazioni della Tabella 1 venga riprodotta nella Tabella 2. Va subito premesso che in Word l’unica possibilità è data da una macro ad hoc: ci si tolga dalla testa quel che invece offre Excel, con formule tipo =$A1 o con macro d’evento, tipicamente quella dell’evento Change che si scatena quando l’utente modifica qualcosa. Word è assai povero di eventi e non c’è nulla del genere.

Ecco perché in apertura ho parlato di “sfizio”: specie se l’operazione va fatta una tantum il gioco non vale la candela, essendo più semplice un copia/incolla fatto a manina. Comunque ecco le varie trovate.

Soluzione 1

Ottenuta nella fretta di rispondere a caldo all’impaziente soggetto:

Sub CopiaIntest()

  For i = 1 To Tables(1).Columns.Count

    Tables(1).Rows(1).Cells(i).Select

    DatoCella = Selection

    DatoCella = Left(DatoCella, Len(DatoCella) - 2)

    Tables(2).Rows(1).Cells(i).Select

    Selection = DatoCella

  Next

End Sub

 

Premesso che Tables(1) e Tables(2) sono le nostre due tabelle e che Tables(1).Rows(1).Cells sono le celle dalla prima intestazione, mentre ovviamente la riga intestataria dell’altra tabella è data dalla stessa espressione ma con Tables(2) al posto di Tables(1).

Il procedimento consiste in un loop che spazzola le celle della prima intestazione (il cui numero è Tables(1).Columns.Count)  selezionando ciascuna, mediante Tables(1).Rows(1).Cells(i).Select, quindi l’oggetto Selection, basilare in Word, è registrato in DatoCella, con successiva “cura” che ne toglie gli ultimi due caratteri. Si passa poi a selezionare l’i-esima cella della prima riga della seconda tabella, rendendo infine Selection = DatoCella.

Il motivo della predetta cura? Come si constata col debug passo passo (tasto F8) la selezione, verbigrazia,  della prima cella di Tabella 1 non è solo “Prodotto” ma è seguito da un Carriage Return e da un pallino (Ascii 7), il che fa parte della codifica delle celle di una tabella Word (per distinguerle, penso). Si provi infatti a eliminare l’istruzione DatoCella = Left(DatoCella, Len(DatoCella) - 2): si constaterà che nella cella destinataria compare un CR.

Variante, con sorprese

Sub CopiaIntestBIS()

  For i = 1 To Tables(1).Columns.Count

    Tables(1).Rows(1).Cells(i).Select

    Selection.Copy

    Tables(2).Rows(1).Cells(i).Select

    Selection.Paste

  Next

End Sub

 

Qui ho rinunciato alla variabile-punte DatoCella sfruttando il metodo Copy della Selection relativa alla cella i-esima per poi applicare il metodo Paste alla Selection della corrispondente cella della Tabella 2. Stavolta, ecco la sorpresa!, l’istruzione “curativa” è per così dire indifferente: il risultato è corretto sia che venga o non venga applicata. Un’altra differenza che si constata è che mentre CopiaInTest lascia immutati sia gli sfondi che gli attributi delle celle destinatarie CopiaIntestBIS conserva solo gli sfondi ma, ad esempio, il grassetto delle celle di Tabella 1 viene acquisito dalle corrispettive di Tabella 2 (che non l’aveva).

Nota Di queste particolarità non ho sinceramente avuto modo né voglia di farmi una ragione. Lo faccia chi può, comunque pragmaticamente non c’è che da prenderne atto..

Seconda soluzione

I procedimenti fin qui esaminati, agiscono per successive selezioni di celle (e quando terminano si ha è selezionata l’ultima cella della seconda tabella). Quelli “più audaci” che andiamo a vedere agiscono invece “a distanza”, ossia mantenendo la selezione corrente. Per constatarlo si ponga il cursore in un punto qualsiasi del documento, magari fuori delle tabelle.

Ma ecco la prima Sub “audace”:

Sub CopiaIntestaz()

  For i = 1 To Tables(1).Columns.Count

    Tables(1).Rows(1).Cells(i).Range.Copy

    Tables(2).Rows(1).Cells(i).Range.Paste

  Next

End Sub

 

Qui, come nelle altre soluzioni che mostreremo, si ricorre alla basilare proprietà Range. Difficile definirla in due parole, dirò solo che restituisce il dato di un certo oggetto Word. In tal modo l’applicazione dei metodi Copy e Paste funziona correttamente e, quel che è più bello, agisce “a distanza”! E con le non del tutto attese modalità del caso precedente.

Terza soluzione

Ma perché, ci siamo subito detti, operare cella per cella? Proviamo allora con copia / incolla sulle intere prime righe. Ed ecco il primo tentativo in tale direzione, basato sul fatto che anche a un oggetto Row  si applicano Copy e Paste:

Sub CopiaIntestazioniOLD()

  'Dio sa perché viene AGGIUNTA una riga, con

  'formattazioni identiche a quelle della tabella 1

  Tables(1).Rows(1).Range.Copy

  Tables(2).Rows(1).Range.Paste

End Sub

 

Tutto OK? Mica poi tanto. Infatti viene mantenuta l’azione “a distanza”, ma si presenta l’ennesima sorpresina:

TABELLA 2

Prodotto

Prezzo

Quantità

Importo

Sconto

Netto

Questo

Quello

Eccetera...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Ovvero stavolta la prima riga di Tabella 1 viene inserita prima di quella della Tabella 2. Ancora una volta non so darne spiegazione e faccio appello ai più esperti, se riescono a trovare una pezza migliore di quella che infine propongo, basata sulla cancellazione della riga 1 di Tabella 2, prima del Paste.

Sub CopiaIntestazioni()

  'Funziona! sempre copiando anche i formati

  Tables(1).Rows(1).Range.Copy

  Tables(2).Rows(1).Delete

  Tables(2).Rows(1).Range.Paste

End Sub

 

Un’ultima annotazione (espressa dai commenti inseriti): stavolta la copia dei formati dell’intestazione di Tabella 1 è totale, riguarda sia i font che gli sfondi. Perché mai? A noi pigri non resta che prenderne atto.

?>

posted on lunedì 12 gennaio 2009 11.24