Visualizzazione dei risultati da 1 a 10 su 23

Hybrid View

  1. #1
    Moderatore di Hardware L'avatar di teo1964
    Registrato dal
    Feb 2006
    Messaggi
    6,138

    [Excel] Chiudere un foglio in automatico

    In azienda abbiamo un file in excel che viene consultato da diversi utenti tramite accesso all'area comune del disco di rete mentre modificato solo da pochi.
    Il problema è che spesso gli utenti aprono il file, si dimenticano di chiuderlo ed escono dall'ufficio, quindi fino al loro rientro non è possibile modificare il file in quanto apribile solo in sola lettura.

    E' possibile creare una macro che dopo un tot tempo che il file è stato aperto lo chiuda automaticamente ? La possibilità anche di inserire un camnpo con una forma di countdown da mettere in un angolo del foglio sarebbe il massimo !!

    Solo due cose sono infinite: l'universo e la stupidità umana, ma non sono sicuro della prima - Albert Einstein

  2. #2
    Moderatore di Hardware L'avatar di teo1964
    Registrato dal
    Feb 2006
    Messaggi
    6,138
    Salve ragazzi, sono ancora qui che rompo.
    Allora finalmente abbiamo migrato a win7/office 2010 ed ho potuto provare la macro.
    Funziona tutto tranne una cosa, per evitare di chiudere tutta l'applicazione excel ma semplicemente il file in uso, ho provato a modificare la macro suggerita sostituendo "Application.Quit" con "thisWorkbook.close".
    Effettivamente il file si chiude (dopo il salvataggio) ma si riapre da solo in loop.
    Cosa ho sbagliato ? Allego di seguito la macro come è adesso:
    In ThisWorkbook:
    Private Sub Workbook_Open()
    Application.OnTime Now + TimeValue("00:00:30"), "Chiudi"
    Application.OnTime Now, "Countdown"
    End Sub
    In Modulo:
    Private Sub Countdown()
    Sheets(1).[c2] = TimeValue("00:00:30")
    Visualizza
    End Sub
    Private Sub Visualizza()
    Dim TempoRimanente As Date
    TempoRimanente = ActiveSheet.Range("C2")
    Sheets(1).[c2] = TempoRimanente - TimeValue("00:00:01")
    Application.OnTime Now + TimeValue("00:00:01"), "Visualizza"
    End Sub
    Private Sub Chiudi()
    ThisWorkbook.Save
    ThisWorkbook.Close
    End Sub

    Grazie ed auguri a tutti di un sereno e prospero 2014



    Application.Quit
    Solo due cose sono infinite: l'universo e la stupidità umana, ma non sono sicuro della prima - Albert Einstein

  3. #3
    Quote Originariamente inviata da teo1964 Visualizza il messaggio
    Effettivamente il file si chiude (dopo il salvataggio) ma si riapre da solo in loop.

    Grazie ed auguri a tutti di un sereno e prospero 2014
    Dunque, il problema sembra che sia questo:

    Appena il foglio excel viene aperto vengono fatte partire due routine, una che interviene dopo un certo tempo per chiudere il foglio (Chiudi) e un'altra, la Countdown, che innesca il ciclo della Visualizza su se stessa con periodo di un secondo.

    Quando la Chiudi chiudeva tutta l'applicazione terminava anche la Visualizza che era lì a ciclare tranquillamente su stessa ma ora che la Chiudi si limita a chiudere solo il workbook, lasciando l'applicazione in vita, la Visualizza continua a richiamare se stessa e, per farlo, riapre il foglio (a me poi viene generato un errore dovuto al disallineamento delle variabili ma questo è un effetto collaterale).

    La soluzione migliore mi sembra di killare esplicitamente la Visualizza aggiungendo questa riga prima di chiudere il foglio:

    codice:
       Application.OnTime Now + TimeValue("00:00:01"), "Visualizza", , False

    Dalle prove che ho fatto sembra funzionare, nel senso che il ciclo non viene reinnescato e, contemporaneamente, si ottiene l'effetto di lasciare aperti eventuali altri workbook però non basta ancora perché se il foglio col conto alla rovescia è l'unico aperto resta excel aperto con la schermata grigia perché in quel caso bisogna fare la vecchia Application.Quit.

    Per risolvere allora ho aggiunto un test sul numero di workbooks aperti: se è 1 faccio la Quit, altrimenti uccido la Visualizza e poi Close:

    codice:
    Private Sub Chiudi()
       Application.DisplayAlerts = False
       ThisWorkbook.Save
       If Application.Workbooks.Count = 1 Then
          Application.Quit
       Else
          Application.OnTime Now + TimeValue("00:00:01"), "Visualizza", , False
          ThisWorkbook.Close
       End If
    End Sub

    Poi però, provando ad aprire e chiudere fogli mi sono accorto di un altro problema e cioè che la ActiveSheet.Range("C2") non punta sempre allo stesso foglio ma al foglio che è attivo in quel momento ed allora succede che se apro il foglio col countdown e poi, mentre il tempo scorre, apro un altro foglio, mi ritrovo il conto alla rovescia nella C2 di questo nuovo foglio.

    Per risolvere ho utilizzato la

    codice:
    ThisWorkbook.Sheets(1).[c2]

    in tutti i punti in cui viene referenziata la cella C2.

    In definitiva quindi:

    codice:
    Private Sub Countdown()
       ThisWorkbook.Sheets(1).[c2] = TimeValue("00:30:00")
       Visualizza
    End Sub
    Private Sub Visualizza()
       Dim TempoRimanente As Date
       TempoRimanente = ThisWorkbook.Sheets(1).[c2]
       ThisWorkbook.Sheets(1).[c2] = TempoRimanente - TimeValue("00:00:01")
       Application.OnTime Now + TimeValue("00:00:01"), "Visualizza"
    End Sub
    Private Sub Chiudi()
       Application.DisplayAlerts = False
       ThisWorkbook.Save
       If Application.Workbooks.Count = 1 Then
          Application.Quit
       Else
          Application.OnTime Now + TimeValue("00:00:01"), "Visualizza", , False
          ThisWorkbook.Close
       End If
    End Sub

    Così mi sembra che vada bene.


    Auguri a tutti
    La democrazia rappresentativa ha fatto il suo tempo, è ora di passare alla democrazia diretta.
    www.beppegrillo.it

  4. #4
    Moderatore di Hardware L'avatar di teo1964
    Registrato dal
    Feb 2006
    Messaggi
    6,138
    Cattura1.PNGCattura2.JPG
    Ciao e grazie dell'aiuto.
    Allora provato sul pc di casa (oofice 2007) funziona tutto, ma in quello del lavoro (office 2010) mi da il seguente errore (ti allego gli screen shot). Se e quando avrai tempo e voglia ..... grazie 1000.
    Solo due cose sono infinite: l'universo e la stupidità umana, ma non sono sicuro della prima - Albert Einstein

  5. #5
    Purtroppo (o per fortuna ) non ho Office 2010 quindi posso solo andare per ipotesi anche perché cercando in rete non ho trovato nessuno che lamenti differenze fra le due versioni quindi non ho nulla su cui lavorare.

    Comunque un paio di prove possiamo farle.

    La prima cosa che mi viene da pensare è che la OnTime di chiusura della Visualizza non riesca a trovare il timer da killare perché nel frattempo Now è cambiato e quindi Now + TimeValue("00:00:01") ha un valore diverso da quello che aveva quando il timer è partito.
    In realtà mi sto arrampicando sugli specchi perché, visto che la Visualizza parte ogni secondo, qualunque sia il Now qualcosa di attivo in quel momento ci sarà di sicuro, però, chissà, magari excel 2010 utilizza un Now con una precisione maggiore e questo porta problemi di arrotondamenti quindi tanto vale provare ad assegnare il valore Now + TimeValue("00:00:01") ad una variabile e poi usare quella sia nel loop che nel kill.

    codice:
    Dim dTime
    Private Sub Countdown()
       ThisWorkbook.Sheets(1).[c2] = TimeValue("00:10:00")
       Visualizza
    End Sub
    Private Sub Visualizza()
       Dim TempoRimanente As Date
       TempoRimanente = ThisWorkbook.Sheets(1).[c2]
       ThisWorkbook.Sheets(1).[c2] = TempoRimanente - TimeValue("00:00:01")
       dTime = Now + TimeValue("00:00:01")
       Application.OnTime dTime, "Visualizza"
    End Sub
    Private Sub Chiudi()
       Application.DisplayAlerts = False
       ThisWorkbook.Save
       If Application.Workbooks.Count = 1 Then
          Application.Quit
       Else
          Application.OnTime dTime, "Visualizza", , False
          ThisWorkbook.Close
       End If
    End Sub

    La nuova variabile come vedi è la dTime che viene calcolata in un solo punto e poi utilizzata sia per attivare che per killare il timer.

    L'unica altra prova che mi viene in mente è di provare a passare i paramentri alla OnTime indicandone esplicitamente i nomi, chissà mai ...

    codice:
    Dim dTime
    Private Sub Countdown()
       ThisWorkbook.Sheets(1).[c2] = TimeValue("00:10:00")
       Visualizza
    End Sub
    Private Sub Visualizza()
       Dim TempoRimanente As Date
       TempoRimanente = ThisWorkbook.Sheets(1).[c2]
       ThisWorkbook.Sheets(1).[c2] = TempoRimanente - TimeValue("00:00:01")
       dTime = Now + TimeValue("00:00:01")
       Application.OnTime EarliestTime:=dTime, Procedure:="Visualizza"
    End Sub
    Private Sub Chiudi()
       Application.DisplayAlerts = False
       ThisWorkbook.Save
       If Application.Workbooks.Count = 1 Then
          Application.Quit
       Else
          Application.OnTime EarliestTime:=dTime, Procedure:="Visualizza", Schedule:=False
          ThisWorkbook.Close
       End If
    End Sub

    Per ora non mi viene in mente nient'altro, fammi sapere come va.
    La democrazia rappresentativa ha fatto il suo tempo, è ora di passare alla democrazia diretta.
    www.beppegrillo.it

  6. #6
    Moderatore di Hardware L'avatar di teo1964
    Registrato dal
    Feb 2006
    Messaggi
    6,138
    Grazie1000, domani provo e ti faccio sapere.
    Solo due cose sono infinite: l'universo e la stupidità umana, ma non sono sicuro della prima - Albert Einstein

  7. #7
    Moderatore di Hardware L'avatar di teo1964
    Registrato dal
    Feb 2006
    Messaggi
    6,138
    Ok, errore risolto.
    Ti chiedo se puoi un ultimo sforzo: se voglio chiudere il file manualmente (con file/chiudi, prima cioè che la macro sia giunta al termine del countdown), il file in realtà non si chiude ma si ripropone aperto con proseguimento del countdown.
    Solo due cose sono infinite: l'universo e la stupidità umana, ma non sono sicuro della prima - Albert Einstein

  8. #8
    Quote Originariamente inviata da teo1964 Visualizza il messaggio
    Ok, errore risolto.
    Ti chiedo se puoi un ultimo sforzo: se voglio chiudere il file manualmente (con file/chiudi, prima cioè che la macro sia giunta al termine del countdown), il file in realtà non si chiude ma si ripropone aperto con proseguimento del countdown.
    Eh, già, per chiudere anticipatamente il foglio non basta il comando chiudi perché restano i timer attivi che lo riaprono quindi occorre inserire un pulsante apposito per la chiusura anticipata che resetti i timer, salvi e chiuda il foglio.

    Sostanzialmente si tratta di ripetere, sul timer lungo, ciò che abbiamo già fatto sul timer breve e inserire un pulsante che richiami la solita Sub Chiudi arricchita della chiusura del timer lungo.

    Cominciamo dal pulsante: dalla scheda sviluppo clicca su Inserisci e poi dalla metà inferiore (ActiveX) inserisci un pulsante nel foglio.

    La personalizzazione la lascio a te, basta che dal tasto destro scegli proprietà mentre il codice va inserito nel foglio corrispondente al foglio in cui hai inserito il pulsante, comunque basta che ci clicchi spora due volte e finirai già nel foglio giusto in cui inserire la prima parte di codice.

    Ti faccio notare solo una cosa: se l'icona Modalità di Progettazione della scheda sviluppo è attiva potrai modificare le proprietà del pulsante col tasto destro e accedere al codice cliccandoci sopra, altrimenti il click eseguirà l'azione associata al pulsante.

    L'azione associata al pulsante non è altro che far partire istantaneamente la routine Chiudi, nient'altro.

    Purtroppo non sono riuscito a far eseguire una Sub da un ramo all'altro dell'albero dei progetti quindi ho usato l'escamotage della OnTime ma sarebbe stata meglio una semplice chiamata di routine come una call ma non ce l'ho fatta quindi accontentiamoci della OnTime che non sarà elegantissima ma funziona.

    Ho modificato anche il codice in Modulo1.

    Per prima cosa ho definito la variabile dClose che serve a identificare il timer lungo in modo certo calcolando il momento di chiusura in un solo punto (analoga alla dTime già usata), poi ho spostato il codice che si trovava nella Workbook_Open in una nuova Sub di Modulo1 che ho chiamato Start_Timer in modo che la variabile dClose potesse essere vista anche dalla Chiudi.

    Visto che avevo portato l'innesco dei timer nella Modulo1 ho potuto anche utilizzare una variabile unica (la dDurata) per impostare il tempo del countdown invece di doverlo impostare in due punti com'era prima.

    La Countdown e la Visualizza non sono cambiate.

    La Chiudi invece ha un paio di novità: la prima è che ho aggiunto il reset del timer lungo, identificato dalla dClose e la seconda è che ho dovuto aggiungere le due On Error che hanno lo scopo di disattivare momentaneamente (e riattivare subito dopo) la partenza automatica del debugger in caso di errore perché c'è un caso in cui è corretto che la chiusura del timer dia errore e non voglio che parta il debugger.

    Mi spiego meglio.

    Se si richiede una chiusura anticipata col pulsante i due timer sono entrambi attivi e quindi possono essere chiusi senza problemi ma se, invece, la chiusura avviene perché il timer principale ha raggiunto la sua ora il reset del ciclo lungo va in errore perché il timer lungo non è più attivo.

    In altre parole quella Sub può trovarsi a lavorare con un solo timer attivo o con due quindi occorre disattivare per un attimo il controllo degli errori.

    Questo è il nuovo codice, fammi sapere come va:


    codice:
    In Foglio1
    ----------
    
    Private Sub CommandButton1_Click()
       Application.OnTime Now, "Chiudi"
    End Sub
    
    
    
    In Modulo1
    ----------
    
    Dim dTime, dClose, dDurata
    
    Private Sub Start_Timer()
       dDurata = "00:10:00"
       dClose = Now + TimeValue(dDurata)
       Application.OnTime EarliestTime:=dClose, Procedure:="Chiudi"
       Application.OnTime Now, "Countdown"
    End Sub
    
    Private Sub Countdown()
       ThisWorkbook.Sheets(1).[c2] = TimeValue(dDurata)
       Visualizza
    End Sub
    
    Private Sub Visualizza()
       Dim TempoRimanente As Date
       TempoRimanente = ThisWorkbook.Sheets(1).[c2]
       ThisWorkbook.Sheets(1).[c2] = TempoRimanente - TimeValue("00:00:01")
       dTime = Now + TimeValue("00:00:01")
       Application.OnTime EarliestTime:=dTime, Procedure:="Visualizza"
    End Sub
    
    Private Sub Chiudi()
       Application.DisplayAlerts = False
       ThisWorkbook.Save
       If Application.Workbooks.Count = 1 Then
          Application.Quit
       Else
          On Error Resume Next
          Application.OnTime EarliestTime:=dClose, Procedure:="Chiudi", Schedule:=False
          On Error GoTo 0
          Application.OnTime EarliestTime:=dTime, Procedure:="Visualizza", Schedule:=False
          ThisWorkbook.Close
       End If
    End Sub
    
    
    
    In ThisWorkbook
    ---------------
    
    Private Sub Workbook_Open()
       Application.OnTime Now, "Start_Timer"
    End Sub
    La democrazia rappresentativa ha fatto il suo tempo, è ora di passare alla democrazia diretta.
    www.beppegrillo.it

  9. #9
    Moderatore di Hardware L'avatar di teo1964
    Registrato dal
    Feb 2006
    Messaggi
    6,138
    Gentilissimo come sempre. Martedì provo direttamente dalla rete aziendale e ti faccio sapere.
    Intanto grazie.
    Solo due cose sono infinite: l'universo e la stupidità umana, ma non sono sicuro della prima - Albert Einstein

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.