sabato 20 settembre 2014

Il mio programma: prima parte: il caricamento di un nuovo foglio nella cartella.

La prima da considerare è l'aggiunta del foglio.
Un foglio va aggiunto se non ne esiste già uno con lo stesso nome, altrimenti si va incontro all'errore di tentare di rinominare un foglio con il nome di uno già esistente.
Come ho affrontato il problema?

Public Sub aggiungiFoglio()

    Dim d As Date, nomeFoglio As String
    
    d = DateAdd("m", 1, Date)      'attribuisce alla variabile locale d il valore del mese successivo alla data attuale
    nomeFoglio = MonthName(Month(d)) & " " & Year(d)    'attribuisce alla stringa nomeFoglio mese e anno della variabile locale d
    
    Sheets.Add          'aggiunge un nuovo foglio
    On Error GoTo X     'gestisce l'errore di tentata rinominazione del foglio
    ActiveSheet.Name = nomeFoglio   'rinomina il foglio con la stringa nomeFoglio.
    ActiveSheet.Move after:=Sheets(Sheets.Count) 'sposta alla fine della cartella il nuovo foglio

        
    formattaFoglio Riga, Colonna, Month(d), Year(d)  'formatta il foglio secondo lo schema

    Exit Sub
X:     'gestione dell'errore di tentata rinominazione del foglio: elimina il foglio senza suscitare avvisi di eliminazione.
    Application.DisplayAlerts = False
    ActiveSheet.Delete
    Application.DisplayAlerts = True
End Sub
Analizziamolo pezzo-pezzo...
Dim d As Date, nomeFoglio As String
    
    d = DateAdd("m", 1, Date)      'attribuisce alla variabile locale d il valore del mese successivo alla data attuale
    nomeFoglio = MonthName(Month(d)) & " " & Year(d)    'attribuisce alla stringa nomeFoglio mese e anno della variabile locale d
Dichiara la variabile d/ di tipo Date e la variabile nomeFoglio di tipo String.
Quindi attribuisce alla variabile d il valore della data odierna aumentata di un mese, e sulla base di questa attribuisce alla variabile nomeFoglio il valore del nome del mese e dell'anno di questa data, uniti in una stringa e separati da uno spazio bianco. Questo sarà il nome del nuovo foglio da aggiungere.

Andiamo avanti:
    Sheets.Add          'aggiunge un nuovo foglio
    On Error GoTo X     'gestisce l'errore di tentata rinominazione del foglio
    ActiveSheet.Name = nomeFoglio   'rinomina il foglio con la stringa nomeFoglio.
Ora aggiunge un nuovo foglio, e cerca di nominarlo con la stringa nomeFoglio comprensiva del nome del mese e dell'anno del mese successivo, ma se viene fuori l'errore di rinominazione di un foglio con il nome di uno già esistente si rimanda all'etichetta X, a fine routine.

Ho preferito gestire l'errore: prima avevo usato un codice che diceva al programma di aggiungere e nominare un nuovo foglio solo se il nome dell'ultimo foglio della cartella non fosse uguale a quello calcolato nella variabile nomeFoglio. Ma così facendo, nel caso in cui il foglio non fosse capitato alla fine si sarebbe potuto incorrere ugualmente nell'errore.
Inoltre, fare in modo che la variabile nomeFoglio fosse confrontata con i nomi di tutti i fogli mi è sembrata una soluzione troppo lunga, nel caso in cui la cartella dovesse contenere molti fogli, da confrontare uno per uno.


Bene, adesso abbiamo, se non c'è stato errore, un nuovo foglio nominato con il nome di mese e anno del mese successivo.
Procediamo mettendolo alla fine di tutti i fogli della cartella e quindi formattandolo secondo il formato prestabilito usando la routine apposita che abbiamo preconfezionato, dopodiché si esce dalla routine e la prima parte del lavoro è conclusa.
    ActiveSheet.Move after:=Sheets(Sheets.Count) 'sposta alla fine della cartella il nuovo foglio

        
    formattaFoglio Riga, Colonna, Month(d), Year(d)  'formatta il foglio secondo lo schema

    Exit Sub


Nel caso invece in cui si sia incorsi nell'errore di tentare di rinominare il foglio con il nome di un foglio già esistente, il programma viene gestito con il codice segnato dall'etichetta X, alla quale si viene rimandati dal gestore dell'errore.
X:     'gestione dell'errore di tentata rinominazione del foglio: elimina il foglio senza suscitare avvisi di eliminazione.
    Application.DisplayAlerts = False
    ActiveSheet.Delete
    Application.DisplayAlerts = True
Disattivando gli avvisi, che in tale contesto sarebbero fastidiosi, di eliminazione di fogli, si elimina semplicemente il foglio appena aggiunto, quindi si ripristinano gli avvisi e la prima parte del lavoro viene conclusa senza l'aggiunta di nuovi fogli.

giovedì 18 settembre 2014

Codice per contare le ricorrenze di vari nomi in una lista in Excel

Ecco una routine ottima per la ricerca di nomi in una lista contandone il numero di occorrenze:
Sub trova()
    Dim r As Range
    Dim tb As Range
    Dim risultato As Range
    Set r = Range(Cells(1, 1), Cells(10, 1))
    Set tb = Range(Cells(10, 3), Cells(14, 3))
    Dim k As Integer
    k = 1
    Do While r.Cells(k).FormulaR1C1 <> ""
        Set risultato = tb.Find(r.Cells(k).FormulaR1C1)
        If Cells(risultato.Row, risultato.Column + 1).FormulaR1C1 = "" Then Cells(risultato.Row, risultato.Column + 1).FormulaR1C1 = 0
        Cells(risultato.Row, risultato.Column + 1).FormulaR1C1 = Cells(risultato.Row, risultato.Column + 1).FormulaR1C1 + 1
        
        k = k + 1
    Loop
End Sub
E funziona!



L'ultimo numero in fondo è la somma di tutte le presenze, per verificare che fosse uguale al totale di tutte le presenze rilevate nella prima colonna.
Corrisponde tutto, il codice funziona, ed è rapido.

Metodo Find applicato a un Range di Excel

Bene.
Dopo essere impazzito a costruire una funzione che trovasse l'occorrenza di una stringa all'interno di una tabella di celle, la quale lo faceva egregiamente, sia pure, come c'era da aspettarsi, alla velocità di una tartaruga asmatica con l'artrosi deformante, sono andato a cercare, e a trovare, funzioni di Excel che soddisfano parimenti alla bisogna, ma alla velocità di Speedy Gonzales è dir poco!

Ovviamente, dal momento che anche i rutti e le scorregge di Excel hanno un corrispettivo in codice VBA, si può fare tutto con del codice.

E procedo.
Ho una tabella situata in un punto imprecisato al centro del foglio di lavoro di Excel, fatta così:



E adesso voglio ritrovare Luciano Stronzini, nel foglio, e sostituire al numeretto la frase "ECCOTI QUA".
Come farò?
Così:
Sub trova()
    Dim r As Range
    Set r = ActiveSheet.Cells
    Set ricerca = r.Find("Luciano Stronzini")
    Cells(ricerca.Row, ricerca.Column + 1).FormulaR1C1 = "ECCOTI QUA"
End Sub
Ed ecco la nuova tabella (ricopiata pari pari):



Il metodo Find, applicato a un Range, dà origine a un altro range del quale possiamo poi determinare la fila e la colonna per agire di conseguenza su altre celle che ne condividano uno di questi due valori.

E le costruzioni cervellotiche e lentissime che ho costruito prima vengono liquidate come semplici esercizi mentali!

lunedì 15 settembre 2014

Codice della cartella di lavoro per gestire dall'esterno gli eventi dei fogli di Excel (ovvero come dire "sì" usando diecimila parole)

Quando non si conosce a sufficienza l'applicazione...

Ho eliminato tutto quell'apparato cervellotico di costruzione di classi per la gestione dei fogli, perché avevo sottovalutato il codice dell'oggetto Workbook! Io una gestione dall'esterno del codice dei singoli fogli ce l'ho già dal codice della cartella, e quindi è perfettamente inutile che vada a gestire questo codice per mezzo di una classe creata ex novo per ogni singolo foglio!!!

E va bene... mi è servito da esercizio e potrebbe tornare utile successivamente!!!

Ecco il codice, semplice e lineare.

Codice di Workbook:
Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
    Target.FormulaR1C1 = "CICCIA"
    Cancel = True
End Sub
Ed ecco il codice del modulo 1 (quello statico):
Public Sub aggiungiFoglio()
ThisWorkbook.Sheets.Add
gestisciFoglio 1, 1, 10, 2014
End Sub
(gestisciFoglio con i quattro parametri è il metodo pubblico del modulo che crea il modello della pagina da stampare, preso pari pari preconfezionato e messo qui).

Tutto quello su cui mi sono masturbato il cervello finora decade completamente, anche se sicuramente ciò che ho imparato tornerà utile in futuro per qualche altra esigenza...

Almeno mi consolo per aver capito tutto da solo...

domenica 14 settembre 2014

Creare fogli di Excel con un evento gestito dall'esterno.

Dunque...

L'aggiunta di un foglio prevede la creazione di una classe "di appoggio".
Per ogni foglio esistente nella cartella si deve creare questa classe, e ogni volta che si aggiunge un foglio si deve aggiungere un'istanza in più di questa classe.
Questa è la classe, che io chiamo "gestore":
Public WithEvents foglio As Worksheet

Private Sub foglio_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    Target.FormulaR1C1 = "CICCIA"
    Cancel = True
End Sub


La sua creazione è soggetta all'apertura della cartella di lavoro:

Codice della cartella di lavoro:
Public mioGestore() As gestore
Private Sub Workbook_Open()

ReDim mioGestore(Sheets.Count - 1)
For n = 1 To Sheets.Count
Set mioGestore(n - 1) = New gestore
Set mioGestore(n - 1).foglio = Sheets(n)
Next n
End Sub
La matrice di mioGestore è resa pubblica in modo che alla procedura di aggiunta di ogni foglio si possa ampliare con la creazione di una nuova istanza del gestore:
Proviamo a creare un nuovo foglio con creazione di questa nuova istanza, ponendo in Modulo 1 il codice per la funzione "aggiungiFoglio".

Modulo1:
Public mioGestore() As gestore
Sub aggiungiFoglio()
ReDim Preserve mioGestore(UBound(mioGestore) + 1)
MsgBox UBound(mioGestore)
Set mioGestore(UBound(mioGestore)) = New gestore
Set mioGestore(UBound(mioGestore)).foglio = ThisWorkbook.Sheets.Add
End Sub
Però, dato che la dichiarazione di una variabile pubblica nel codice della cartella di lavoro non "funziona", ho spostato qui (in rosso) la dichiarazione della matrice di mioGestore.
in modo che il codice della cartella di lavoro diventa:

Cartella di lavoro:
Private Sub Workbook_Open()
ReDim mioGestore(Sheets.Count - 1)
For n = 1 To Sheets.Count
Set mioGestore(n - 1) = New gestore
Set mioGestore(n - 1).foglio = Sheets(n)
Next n
End Sub
Funziona.
Anzi, tolgo quella MsgBox nel codice del Modulo 1, che avevo messo per verificare se la grandezza della matrice aumentasse.
Public mioGestore() As gestore
Sub aggiungiFoglio()
ReDim Preserve mioGestore(UBound(mioGestore) + 1)

Set mioGestore(UBound(mioGestore)) = New gestore
Set mioGestore(UBound(mioGestore)).foglio = ThisWorkbook.Sheets.Add
End Sub
Okay!!!

sabato 13 settembre 2014

Modulo di classe in VBA Excel per gestire dall'esterno gli eventi di un oggetto

Comincio a vederci un po' più chiaro sull'uso dei moduli di classe...

Un modulo di classe potrebbe funzionare da gestore di eventi per un oggetto.
Proviamo un po'...

Innanzitutto, gestiamo l'evento direttamente da un foglio di Excel Codice del Foglio1
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    MsgBox "Il foglio è stato cliccato col destro!"
    Cancel = True
End Sub
E al click destro sul foglio si ottiene una MsgBox con il messaggio "Il foglio è stato cliccato col destro!".

Adesso facciamo con una classe: dopo aver cancellato il codice dalla finestra di codice del Foglio1, creo un modulo di classe e lo chiamo "gestore", con questo codice:
Dim WithEvents foglio As Worksheet

Private Sub Class_Initialize()
    Set foglio = Sheets(1)
End Sub

Private Sub foglio_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    MsgBox "Il foglio è stato cliccato col destro!"
    Cancel = True
End Sub
E istanzio la classe da Modulo 1 con questo codice:
Dim mioGestore As gestore
Sub main()
    Set mioGestore = New gestore
End Sub
Vado sul foglio, avvio main dalla finestra delle Macro, e quando vado a cliccare col destro sul foglio 1 ottengo lo stesso risultato, ossia una MsgBox con il messaggio "Il foglio è stato cliccato col destro!"

Creazione di un oggetto a parte che formatta il foglio, nel programmino che mi è stato richiesto

Voglio isolare, in un modulo, tutti i metodi che formattano il foglio del mio programma...
Si tratta di un oggetto statico, perché le funzioni vanno semplicemente richiamate, senza necessità di istanziare.

Questa è la routine che coordina le varie sezioni che gestiscono il foglio.
Private Sub organizzaFoglio()

'inizializza le variabili colonna e riga, e ne copia i valori iniziali per preservarli, nelle
'variabili PrimaColonna e PrimaRiga

Riga = 3
Colonna = 1

PrimaColonna = Colonna
PrimaRiga = Riga

scriviIntestazioni
    
aggiuntaDate

creazioneGriglia

scrittaDiCoda

impostazioniStampa

End Sub
Metterle su un modulo a parte significa dover definire le variabili in quest'altro modulo.
Dim Riga As Integer
Dim Colonna As Integer
Dim primaRiga As Integer
Dim primaColonna As Integer

Sub gestisciFoglio()

'inizializza le variabili colonna e riga, e ne copia i valori iniziali per preservarli, nelle
'variabili PrimaColonna e PrimaRiga

Riga = 3
Colonna = 1

primaColonna = Colonna
primaRiga = Riga

scriviIntestazioni
    
aggiuntaDate

creazioneGriglia

scrittaDiCoda

impostazioniStampa

End Sub
Alla funzione va passato il valore di riga e colonna, che è meglio inizializzare prima per tenere in mano il comando di dove si vuole creare il prospetto.
Dim Riga As Integer
Dim Colonna As Integer
Dim primaRiga As Integer
Dim primaColonna As Integer

Sub gestisciFoglio(R As Integer, C As Integer)

'inizializza le variabili colonna e riga, e ne copia i valori iniziali per preservarli, nelle
'variabili PrimaColonna e PrimaRiga

Riga = R
Colonna = C

primaRiga = Riga
primaColonna = Colonna

scriviIntestazioni
    
aggiuntaDate

creazioneGriglia

scrittaDiCoda

impostazioniStampa

End Sub
Bene.
Dunque questa routine usa due variabili a livello di modulo, che vengono inizializzate a partire dai parametri passati alla routine.
Ora vediamo le routines che essa chiama.

Copio sul nuovo modulo scriviIntestazioni, che mi pare usi solo le variabili che sono state dichiarate a livello di modulo sul nuovo modulo, ossia Riga e Colonna. Routine scriviIntestazioni
Private Sub scriviIntestazioni()
     'ALTEZZA GENERALE DELLE RIGHE
     
     Cells.Select
     Selection.RowHeight = 15
     'AGGIUNTA DELL'INTESTAZIONE RIGA 1
    Range(Cells(Riga, Colonna), Cells(Riga, Colonna + 3)).Select
    Selection.Merge
    Selection.RowHeight = 17
    Selection.VerticalAlignment = xlCenter
    Selection.HorizontalAlignment = xlCenter
    Selection.Font.bold = True
    Selection.FormulaR1C1 = "GUARDIA MEDICA AREA FUNZIONALE OMOGENEA"
    
    Riga = Riga + 1
    
    'AGGIUNTA DELL'INTESTAZIONE RIGA 2
    Range(Cells(Riga, Colonna), Cells(Riga, Colonna + 3)).Select
    Selection.Merge
    Selection.RowHeight = 17
    Selection.VerticalAlignment = xlCenter

    Selection.HorizontalAlignment = xlCenter
    Selection.Font.bold = True
    Selection.FormulaR1C1 = "MEDICINA-CARDIOLOGIA"
    Selection.Font.ColorIndex = 48
    
    Riga = Riga + 1
    
    'SCRIVE LE PRIME 2 RIGHE DELLA TABELLA
    Columns(Colonna).HorizontalAlignment = xlLeft
    With Cells(Riga, Colonna)
        .FormulaR1C1 = "DATA"
        .ColumnWidth = 10
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 1)
        .FormulaR1C1 = "Nominativo turno"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 2)
        .FormulaR1C1 = "Unità Operativa"
        .ColumnWidth = 20
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 3)
        .FormulaR1C1 = "Nominativo turno"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With
    
    Riga = Riga + 1
    
        With Cells(Riga, Colonna)
        .FormulaR1C1 = NomeMese
        .ColumnWidth = 10
        .HorizontalAlignment = xlCenter
        .Font.bold = True
    End With
    With Cells(Riga, Colonna + 1)
        .FormulaR1C1 = "08.00 - 20.00"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 2)
        .FormulaR1C1 = ""
        .ColumnWidth = 20
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 3)
        .FormulaR1C1 = "20.00 - 8.00"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With

    Riga = Riga + 1

End Sub
Usa solo le variabili Riga e Colonna, che sono già dichiarate a livello di modulo.
Altera il valore di Riga, che comunque è già stato salvato nella variabile primaRiga nel suo valore iniziale.

Funziona.

Adesso dobbiamo spostare la routine aggiungiDate.
Vediamo quali variabili usa...
Private Sub aggiuntaDate()
    Dim dat As Date
    Dim primoGiorno As Date
    primoGiorno = CDate("01/" & Month(dataMeseSuccessivo) & "/" & Year(dataMeseSuccessivo))
    
    dat = primoGiorno
    Do While Month(dat) = Month(primoGiorno)
        With Cells(Riga, Colonna)
            .FormulaR1C1 = Day(dat)
            If WeekdayName(Weekday(dat, vbUseSystemDayOfWeek)) = "domenica" Then .FormulaR1C1 = .FormulaR1C1 & " D"
            .Font.bold = True
        End With
        dat = dat + 1
        Riga = Riga + 1
    Loop
End Sub
E' un po' rudimentale, dato che ho trovato una miglior sintassi per aggiungere un mese al valore di una data.
Per quanto riguarda le variabili, dichiara e inizializza una variabile locale che forse può anche essere eliminata con la nuova sintassi, e usa le variabili relative al mese e all'anno successivi, che con la nuova sintassi possono anche essere eliminate. Provo a riscriverla.
Private Sub aggiuntaDate()
    
    'stabiliamo la data del mese
    Dim Dat As Date, primaData As Date
    Dat = CDate("01/" & Mese & "/" & Anno)
    
    
    With Cells(Riga - 1, Colonna)
        .FormulaR1C1 = MonthName(Mese)
        .Font.bold = True
    End With
    
    ActiveSheet.Name = MonthName(Mese) & " " & Anno
    Do While Month(Dat) = Mese
        With Cells(Riga, Colonna)
            .FormulaR1C1 = Day(Dat)
            If WeekdayName(Weekday(Dat, vbUseSystemDayOfWeek)) = "domenica" Then .FormulaR1C1 = .FormulaR1C1 & " D"
            .Font.bold = True
        End With
        Dat = Dat + 1
        Riga = Riga + 1
    Loop
End Sub

Ho preferito basarmi sulle variabili Mese e Anno, dichiarate a livello di modulo, anziché sul rilevare la data attuale in questa routine, in modo che il modulo possa essere usato in modo più flessibile, non necessariamente sul mese successivo a quello attuale.

Poi aggiungo le altre funzioni che formattano il foglio.
Ecco la struttura completa del mio modulo:
Option Explicit
Dim Riga As Integer
Dim Colonna As Integer
Dim primaRiga As Integer
Dim primaColonna As Integer
Dim Mese As Integer
Dim Anno As Integer


Sub gestisciFoglio(R As Integer, C As Integer, M As Integer, Y As Integer)

'inizializza le variabili colonna e riga, e ne copia i valori iniziali per preservarli, nelle
'variabili PrimaColonna e PrimaRiga

Riga = R
Colonna = C
Mese = M
Anno = Y
primaRiga = Riga
primaColonna = Colonna


scriviIntestazioni
    
aggiuntaDate

creazioneGriglia

scrittaDiCoda

impostazioniStampa

End Sub
Private Sub aggiuntaDate()
    
    'stabiliamo la data del mese
    Dim Dat As Date, primaData As Date
    Dat = CDate("01/" & Mese & "/" & Anno)
    
    
    With Cells(Riga - 1, Colonna)
        .FormulaR1C1 = MonthName(Mese)
        .Font.bold = True
    End With
    
    ActiveSheet.Name = MonthName(Mese) & " " & Anno
    Do While Month(Dat) = Mese
        With Cells(Riga, Colonna)
            .FormulaR1C1 = Day(Dat)
            If WeekdayName(Weekday(Dat, vbUseSystemDayOfWeek)) = "domenica" Then .FormulaR1C1 = .FormulaR1C1 & " D"
            .Font.bold = True
        End With
        Dat = Dat + 1
        Riga = Riga + 1
    Loop
End Sub

Private Sub scriviIntestazioni()
     'ALTEZZA GENERALE DELLE RIGHE
     
     Cells.Select
     Selection.RowHeight = 15
     'AGGIUNTA DELL'INTESTAZIONE RIGA 1
    Range(Cells(Riga, Colonna), Cells(Riga, Colonna + 3)).Select
    Selection.Merge
    Selection.RowHeight = 17
    Selection.VerticalAlignment = xlCenter
    Selection.HorizontalAlignment = xlCenter
    Selection.Font.bold = True
    Selection.FormulaR1C1 = "GUARDIA MEDICA AREA FUNZIONALE OMOGENEA"
    
    Riga = Riga + 1
    
    'AGGIUNTA DELL'INTESTAZIONE RIGA 2
    Range(Cells(Riga, Colonna), Cells(Riga, Colonna + 3)).Select
    Selection.Merge
    Selection.RowHeight = 17
    Selection.VerticalAlignment = xlCenter

    Selection.HorizontalAlignment = xlCenter
    Selection.Font.bold = True
    Selection.FormulaR1C1 = "MEDICINA-CARDIOLOGIA"
    Selection.Font.ColorIndex = 48
    
    Riga = Riga + 1
    
    'SCRIVE LE PRIME 2 RIGHE DELLA TABELLA
    Columns(Colonna).HorizontalAlignment = xlLeft
    With Cells(Riga, Colonna)
        .FormulaR1C1 = "DATA"
        .ColumnWidth = 10
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 1)
        .FormulaR1C1 = "Nominativo turno"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 2)
        .FormulaR1C1 = "Unità Operativa"
        .ColumnWidth = 20
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 3)
        .FormulaR1C1 = "Nominativo turno"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With
    
    Riga = Riga + 1
    
        
    With Cells(Riga, Colonna + 1)
        .FormulaR1C1 = "08.00 - 20.00"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 2)
        .FormulaR1C1 = ""
        .ColumnWidth = 20
        .HorizontalAlignment = xlCenter
    End With
    With Cells(Riga, Colonna + 3)
        .FormulaR1C1 = "20.00 - 8.00"
        .ColumnWidth = 30
        .HorizontalAlignment = xlCenter
    End With

    Riga = Riga + 1

End Sub

Private Sub creazioneGriglia()
'CREAZIONE DELLA GRIGLIA COI BORDI

Range(Cells(primaRiga + 2, primaColonna), Cells(Riga, primaColonna + 3)).Select
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
    Selection.Borders(xlDiagonalUp).LineStyle = xlNone
    With Selection.Borders(xlEdgeLeft)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlEdgeTop)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlEdgeBottom)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlEdgeRight)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlInsideVertical)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
    With Selection.Borders(xlInsideHorizontal)
        .LineStyle = xlContinuous
        .Weight = xlThin
        .ColorIndex = xlAutomatic
    End With
End Sub

Private Sub scrittaDiCoda()
Riga = Riga + 2
Range(Cells(Riga, primaColonna), Cells(Riga, primaColonna + 3)).Select
Selection.Merge
Selection.RowHeight = 35
Selection.VerticalAlignment = xlTop
Selection.WrapText = True
Selection.FormulaR1C1 = "N.B. Gli eventuali cambi turno di Guardia Medica AFO devono essere comunicati, ai fini di riscontro, alla scrivente Direzione Sanitaria, sig.ra XXXXXXXXXXXX, 38*** fax 38***"
Cells(1, 5).Select
End Sub

Private Sub impostazioniStampa()
    'IMPOSTAZIONI PER LA STAMPA
    With ActiveSheet.PageSetup
        .LeftMargin = Application.InchesToPoints(0.5)
        .RightMargin = Application.InchesToPoints(0)
        .PrintArea = "$A$" & primaRiga & ":$D$44"
    End With

End Sub
Funziona.
Su questo modulo ho un solo metodo "esposto" all'esterno, il quale richiede i parametri Riga, Colonna, Mese e Anno per formattare completamente il foglio.
Così si gestisce meglio il resto.