› Sviluppare funzionalita su Microsoft Office con VBA › Dopo un certo tempo di ininattività si va in cella predefinita
-
AutoreArticoli
-
buongiorno a tutti!
torno con una domanda e un problema. Ho un file Excel, dove inseriamo diversi dati, poi ci posizioniamo nella sheets("intervento spinale").range("j97") per scansionare i vari prodotti con lettore ottico. il cursore rimane sempre nella cella sheets("intervento spinale").range("j97") in quanto ho creato un Private Sub Worksheet_Change(ByVal Target As Range), così rimane sempre li. Avendo un lettore ottico wireless, non siamo al computer fisicamente, e quindi abbiamo fatto si che quando si scansiona in quella cella automaticamente rimane in quella cella.
Il problema nasce ora: ogni tanto dobbiamo spostarci per andare a compilare altri campi nella scheda sheets("intervento spinale"). magari compilare i dati inerenti alla pressione, o altro. Poi ci dimentichiamo di tornare nella sheets("intervento spinale").range("j97") per scansionare i materiale e scansioniamo con il lettore ottico in giro per la scheda...
C'è un sistema per dire ovunque io sia nella scheda sheets("intervento spinale") (al di fuori chiaramente se mi trovo già nella casella giusta Range("j97"))... visto che abbiamo un lettore ottico con noi wireless ovunque io sia nella sheets, se scansiono il numero 9000050 torna in automatico sul tasto di scansione sheets("intervento spinale").range("j97"). Però chiaramente quando scansiono quel numero, non dovrebbe cancellare il contenuto della cella dove si trova...
Magari più semplice è ovunque io sia nella scheda sheets("intervento spinale")... dopo 1 minuto di inattività dell'utente, torna in automatico e seleziona in automatico la sheets("intervento spinale").range("j97") .
Vi ringrazio anticipatamente dell'aiuto, e spero che qualcuno sappia darmi una soluzione... saluti e buona serata
marco
Allegati:
You must be logged in to view attached files.Si pero vorrei capire , quando fai la scansione il valore letto(9000050) excelvba, dove memorizza questo dato?
Cioe , la lettura dello scanner dove viene memorizzata?
Qual è il punto di avere gusti diversi, se non mostrare che i cervelli lavorano diversamente, che pensiamo diversamente? ( Alan Turing)
Sempre il mare, uomo libero, amerai!
( Charles Baudelaire )ciao Albatros, grazie della tua risposta,
e si infatti... questo è il problema... cioè io dovrei leggere quel numero in qualunque cella libera(non bloccata) della Sheets("intervento spinale"). Pero il problema sarebbe che cancellerebbe il contenuto. e questo non dovrebbe accadere.
cioe esempio io mi trovo nella cella H59 e ho inserito un dato... ma mi sono dimenticato di tornare nella cella di scansione materiale sheets("intervento spinale").range("j97"). quindi se scansiono il prodotto, mi cancellerà quello che ho inserito nella h59... e non registrerà il prodotto.
l'idea è che ovunque io sia, celle sbloccate, esempio sono in h59... scansiono un codice preciso (9000050) nella cella dove mi trovo (nel nostro esempio h59).. riconosce il codice speciale, non cancella il contenuto, e torna in sheets("intervento spinale").range("j97").
fattibile?
o è più semplice quello della tempistica?
ti ringrazio molto, e ti auguro una buona serata
Marco
La domanda di albatros però è azzeccata e non hai risposto: in che modo viene acquisito il dato letto dal lettore wireless? come avviene il trasferimento della comunicazione tra dispositivo e Excel? hai un pezzo di codice che interviene? si fa tutto mediante un driver apposito fornito dal costruttore dell'apparecchio? per leggere il valore, premi un pulsante e questo è tutto o devi avviare una lettura attraverso Excel che magari si connette a un db remoto?
Visto che utilizzate l'evento Change, è molto più semplice, forse, fare in modo che dopo qualsiasi modifica del foglio, ci si sposti sempre e comunque nella cella J97. Anche se modifichi la cella ABC123 per esempio, con l'evento Change hai la possibilità di far tornare il cursore in J97. Questo può disorientare un po' l'utente a dire il vero ma non ci son molte soluzioni, visto anche lo scenario (e se fosse di implementare uno userform?)
ciao frac!! grazie per la tua risposta,
allora no niente di tutto questo, noi abbiamo un lettore ottico, che è wireless, al computer è collegato una base, che registra la lettura del lettore. avendo aperto un Excel, selezionato la cella sheets("intervento spinale").range("j97") la base inoltra la lettura a quella cella. quello che leggiamo con il lettore ottico sono QR code/ e codici a barre… quindi sono tutti numerici. Quindi una volta scansionato automaticamente appare nella cella sheets("intervento spinale").range("j97") il numero scansionato. il codice Private che rappresenta la cella sheets("intervento spinale").range("j97") fa fare il resto.
ma si potrebbe fare un Private per tutte le celle sbloccate? che torna dopo l'inserimento sheets("intervento spinale").range("j97") ? senza dover scrivere un Private per ogni cella?
tempisticamente non si può fare molto vero?
ringrazio anticipatamente e ti auguro una buona serata!
a presto
Marco
Non è esatto dire "il codice Private che rappresenta la cella ...". Il codice in sè non "rappresenta" nulla, il codice "fa" qualcosa o "restituisce" qualcosa.
Accade che Excel permette di intercettare alcuni eventi che accadono al foglio di lavoro (e anche all'intera cartella di lavoro). Uno di questi riguarda la modifica di una cella. L'evento in questione si chiama Worksheet_Change, è relativo a un determinato foglio e con esso puoi intercettare la modifica a una qualsiasi cella di quel foglio. Quindi non si dice "scrivere un codice che rappresenta la cella...", ma "scrivere un codice che intercetta la modifica di una cella". E ovviamente sì, si può fare.
Chi ti ha fornito il file lo ha bloccato e programmato in modo da rispondere all'evento di modifica del contenuto di una cella. Quello che non sappiamo è come venga trasmesso il dato letto dal lettore a Excel (via DDE?).
Infine, se per "tempisticamente" intendi governare gli eventi in modo che dopo un tot Excel faccia qualcosa (tipo spostarsi su una cella), anche questo si può fare 🙂
ciao Frac, grazie mille per le tue delucidazioni. Il file l'ho creato io personalmente con il vostro prezioso aiuto. ogni codice creato è stato adeguato alle mie esigenze. infatti hai ragione la cella in questione sheets("intervento spinale").range("j97") ha dietro un Worksheet_Change e quindi gli faccio fare un sacco di cose, copia/incolla, riconosce, ...tutto. la password per sbloccare le celle...se non lo già fatto io è nessuna pasword.. basta fare "enter".
La trasmissione non ti so dire come avvenga… ma è come se io scrivessi nella cella. Cioè io mi posiziono su una cella, e quando scansiono con il lettore ottico mi trasmette il numero scansionato nella cella selezionata. Quindi il metodo mi chiedi troppo.
come si fa allora a dire… ovunque io mi trovi selezionato nella scheda Excel sheets("intervento spinale"), dopo 2 minuti di inattività da parte dell'utente, va in automatico alla cella sheets("intervento spinale").range("j97") . se mi muovo io chiaramente, o sono già sulla cella j97, o se faccio delle registrazioni/scansioni... non va alla cella sheets("intervento spinale").range("j97") … solo dopo i due minuti di inattività.
ti ringrazio dell'aiuto e delle informazioni che mi dai.
saluti e a presto
Marco
Non sono una cima, però si dovrebbe intercettare l'attivazione dello scanner al momento della trasmissione del dato, per quanto riguarda il tempo si potrebbe ricorrere alla funzione ontime
Scusate a sono da cellulare
Vedo delle difficoltà a capire proprio come arriva il dato a Excel, perciò se l'alternativa di posizionarsi ogni minuto su una certa cella va bene, propongo il seguente codice:
Public Sub start_timer() 'attiva il timer ogni minuto Application.OnTime EarliestTime:=Now + TimeValue("00:01:00"), Procedure:="TimerRoutine" End Sub 'qui il codice da eseguire ogni secondo Public Sub TimerRoutine() Range("J9").Select start_timer ' Reschedule the procedure End Sub Sub stop_timer() Application.OnTime EarliestTime:=Now + TimeValue("00:01:00"), Procedure:="TimerRoutine", Schedule:=False End Sub
start_timer nell'evento Open del Workbook.
TimerRoutine in un modulo pubblico.
stop_timer all'uscita dalla cartella di lavoro (evento BeforeClose del Workbook).
Non sarà una cosa pulitissima ma è meglio di niente 🙂
Grazie mille della tua risposta frac, ho provato ad inserire i tuoi codici... credo di averli inseriti in maniera sbagliata... (modulo 16 ho messo il tuo codice centrale)... poi nel ThisWorkbook ho aperto il l'Open ... e poi il BeforeClose e inserito i due codici... ma questo non funziona... penso che ho sbagliato qualcosa 🙂 mi puoi dare una mano?
Una domanda, ma questo codice non influenza L utilizzo della scheda, nel senso che io posso fare altre cose senza che non si blocca o altro giusto? a prescindere da quello che faccio dopo 2 minuti precisi va nella cella predefinita o aspetta che finisce quello che faccio?
Seconda domanda. il tempo sarà uguale per ogni scheda... ma la cella di riferimento sarà diversa. Cioè... nella scheda "intervento spinale" la cella di riferimento dove dovrà andare sarà la J97.. Mi spiego, quando apriamo il File, dal menù principale scegliamo la scheda dove andare (spinale/stroke/Diagnostic/...). poi durante tutto l'intervento rimaniamo all'interno di quella scheda scelta. La tempistica è sempre 2 minuti come impostato da te, mentre per la cella di riferimento cambia per ogni scheda.
- "stroke" sarà "J131; per la scheda "infiltrazione" sarà J67; per la scheda "Diagnostica" sarà J97; per la scheda "Embo" sarà J136; per la scheda "Epatobiliare" sarà J88; mentre per la scheda "Body" sarà J151.
come viene impostato?
ti riallego il file con l'errore...Ti ringrazio per il grande aiuto che mi dai.
saluti
marco
Allegati:
You must be logged in to view attached files.marco_budin wrote:questo non funziona
Non dici che errore ricevi ma penso di saperlo.
La TimerRoutine, che sta in un modulo pubblico, non sa a cosa si riferisce il Range specificato. Devi per forza qualificarlo premettendogli il nome del foglio:
sheets("intervento spinale").range("j97")
Errore mio che non sono stato abbastanza chiaro 🙂
Il fatto di dire a Excel di svegliarsi ogni minuto e fare qualcosa è certamente influente sul suo comportamento: dovunque sei, allo spirare del tempo ti porta in quel foglio e a quella cella. Questo non accade soltanto se in quel momento stai modificando una cella (credo che l'evento venga rinviato al momento successivo). Ma se stai consultando la posta elettronica, per dire, il timer corre regolarmente e ogni minuto il cursore ritorna nella cella stabilita.
Invece non avevi detto, all'inizio, che la cella di riferimento cambia in funzione del foglio scelto: è chiaro che la TimerRoutine, per come è scritta, ti rimanda sempre alla cella J97 del foglio Intervento spinale. Dovunque tu sia. Pertanto occorre prevedere i diversi casi sempre all'interno di TimerRoutine.
Analizzando il codice comunque noto che non sono stato chiaro io, di nuovo, nel spiegarti meglio come e dove posizionare il codice.
In ThisWorkbook devi inserire il codice per gli eventi Open e BeforeClose in modo che richiamino start_timer e stop_timer, routine che puoi mettere in un modulo a parte (come hai già fatto). Anche TimerRoutine puoi posizionarla nello stresso modulo, però bisogna specificare i diversi select case.
Riscrivo qui l'intero contenuto del codice da mettere in ThisWorkbook e nel Modulo di gestione del timer:
'THISWORKBOOK Option Explicit Private Sub Workbook_BeforeClose(Cancel As Boolean) stop_timer End Sub Private Sub Workbook_Open() start_timer End Sub
'MODULO Option Explicit Public Sub start_timer() 'attiva il timer ogni minuto Application.OnTime EarliestTime:=Now + TimeValue("00:01:00"), Procedure:="TimerRoutine" End Sub 'qui il codice da eseguire ogni minuto Public Sub TimerRoutine() Select Case LCase(ActiveSheet.Name) Case "intervento spinale" ActiveSheet.Range("J97").Select Case "stroke" ActiveSheet.Range("J131").Select Case "infiltrazione" ActiveSheet.Range("J67").Select Case "diagnostica" ActiveSheet.Range("J97").Select Case "embo" ActiveSheet.Range("J136").Select Case "epatobiliare" ActiveSheet.Range("J88").Select Case "body" ActiveSheet.Range("J151").Select End Select start_timer ' Reschedule the procedure End Sub Public Sub stop_timer() Application.OnTime EarliestTime:=Now + TimeValue("00:01:00"), Procedure:="TimerRoutine", Schedule:=False End Sub
Provo a riallegare il file con le mie modifiche (ci mette una vita a salvarsi e riaprirsi... è normale?)
Allegati:
You must be logged in to view attached files.Cit: Provo a riallegare il file con le mie modifiche (ci mette una vita a salvarsi e riaprirsi... è normale?)
Ho notato che ogni foglio utilizza formattazioni differenti in singole celle.
Consiglio quando possibile di impostare un unico formato distinto in ogni singola colonna.
Poi per la lentezza dipende dal PC, con 32 GH ram non credo sia tanto lento 🙂
Ciao Vecchio Frac!
ti ringrazio moltissimo per l'aiuto che mi hai fornito! funziona tutto alla perfezione. A parte un errore che ricorre sempre:
viene fuori un debug quando cerco di chiudere il file: Errore di run-time '10004', Metodo 'OnTime' dell'oggetto '_Application' non riuscito. E quando osservo il debug si selezione:
Public Sub stop_timer() Application.OnTime EarliestTime:=Now + TimeValue("00:01:00"), Procedure:="TimerRoutine", Schedule:=False End Sub
sai dirmi come mai viene quell'errore??
ho provato a correggere l'errore in questo modo... ma adesso non so se l'application OnTime si ferma veramente o continua all'infinito 🙂
`Public Sub stop_timer() On Error Resume Next Application.OnTime EarliestTime:=Now + TimeValue("00:01:00"), Procedure:="TimerRoutine", Schedule:=False End Sub`
in questo modo, l'errore debug non appare, e il file si chiude.
ti ringrazio ancora molto dell'aiuto, ti auguro una buona giornta
marco
marco_budin wrote:Metodo 'OnTime' dell'oggetto '_Application' non riuscito
L'ho verificato dopo aver chiuso e riaperto il file, pensavo fosse ininfluente ma che sorpresa, dopo aver chiuso Excel si riapre tutto dopo un minuto... Ci sto riflettendo su da un po' e sono giunto alla conclusione che non si deschedula il timer; per farlo deve essere settato a False nelle medesime condizioni in cui è stato attivato, ma noi attiviamo il timer con Now e lo disattiviamo sempre con Now quindi le condizioni non saranno mai uguali 🙂 ho pronta la soluzione ma devo testarla bene per non fare ulteriori figure 😉
marco_budin wrote:non so se l'application OnTime si ferma veramente o continua all'infinito
già... in teoria continua all'infinito finchè non spegni il pc. Ecco perchè preferisco le API SetTimer e KillTimer.
Ciao Vecchio frac, grazie per la tua risposta.. e assolutamente non fai figure.. anzi mi stai dando un enorme aiuti.
L Open e il BeforeClose... devono d’essere uguali con il falso finale... non c’è una funziona generica che “blocca” la funziona all uscita?
in attesa della tua soluzione ti ringrazio ancora e ti auguro una buona giornata!
saluti
marco
La mia soluzione è:
1- congelo Now in una variabile
2- attivo il timer da questa variabile + un minuto
3- quando il timer si attiva, sposta il cursore nella cella adeguata
4- si rischedula il timer: uccido il timer precedente (il riferimento è nella variabile congelata quindi dovrebbe funzionare), quindi ricomincio dal punto 2
5- quando chiudo Excel, uccido il timer definito nell'ultimo valore della variabile congelata e quindi esco senza problemi.
Fammi fare una prova, in teoria funziona 🙂
Mirko wrote:per la lentezza dipende dal PC, con 32 GH ram non credo sia tanto lento
Io ho solo 8 GB di Ram e un povero processore a 3GHz 🙁
Non ho esaminato a fondo i problemi di formattazione del file, del resto non l'ho creato io e mi guardo dal metterci mano 🙂
Hai lavorato benissimo e infatti è conforme alla mia idea, però a me continua a bloccarsi.
Mumble...
🙂 mi spiace Vecchio Frac! comunque un'altra domanda. adesso il codice viene eseguito indipendentemente da se l'utente lavora, o no! se volessi che il minuto di coutdown partisse dal momento che l'utente non è inattivo? cioè quando io ho finito di fare le cose nel modulo, mi fermo, non muovo il mouse e da li parte il minuto. Se però ricomincio ad utilizzare il mouse a 40 secondi, il coutdown ricomincia a calcolare da quando io mi fermerò la prossima volta...
si complica molto il codice? come dovrei procedere?
ti ringrazio davvero tanto.
buona giornata e a presto
Marco
Basta, mi sono scocciato 🙂
Buttiamo a mare OnTime e lavoriamo con le API.
In ThisWorkbook non modifichiamo niente. Modifichiamo il modulo dove risiedono le routine del timer:
Option Explicit Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long Public timerID As Long Public Sub start_timer() 'attiva il timer ogni minuto circa timerID = SetTimer(0, 0, 60000, AddressOf TimerRoutine) End Sub 'qui il codice da eseguire ogni minuto Public Sub TimerRoutine(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal SysTime As Long) Select Case LCase(ActiveSheet.Name) Case "intervento spinale" ActiveSheet.Range("J97").Select Case "stroke" ActiveSheet.Range("J131").Select Case "infiltrazione" ActiveSheet.Range("J67").Select Case "diagnostica" ActiveSheet.Range("J97").Select Case "embo" ActiveSheet.Range("J136").Select Case "epatobiliare" ActiveSheet.Range("J88").Select Case "body" ActiveSheet.Range("J151").Select End Select End Sub Public Sub stop_timer() KillTimer 0, timerID End Sub
Questo dovrebbe essere un sistema più sicuro.
Vecchio Frac, posso solo dirti che sei fantastico. Il codice funziona alla grande come prima (unica cosa che anche se abbiamo impostato 60000, il computer dopo 48 secondi esegue la funzione)...
Il problema è che esegue il codice indipendentemente se l'utente lavora o no sulla scheda. Dopo 48 secondi, anche se sto lavorando... il programma esegue il codice e va nella cella predefinita. In se, dovrebbe essere che io nella scheda selezionata posso lavore, scrivere, cambiare cella, e quando mi fermo e non faccio niente, lui parte il countdown del minuto...altrimenti mi trovo sempre che sto inserendo un dato da una parte... e poi torna sotto nella cella designata dal tempo, e magari io non ho finito sopra e devo tornare su.
ti ringrazio ancora per la tua infinita pazienza.
saluti e a presto
Marco
Salve a tutti.
Si potrebbe sfruttare l'evento SheetChange del Workbook per resettare il timer ogni volta che viene modificato un qualunque foglio
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) stop_timer start_timer End Sub
Ciao zer0kelvin,
Ti ringrazio molto per la tua risposta e sopratutto di grande aiuto.
Ma basta quella funzione li per resettare ogni vokta il conteggio del minuto mentre io lavoro giusto?
Girando un po in internet ho trovato anche altre funzioni da aggiungere:
Private Sub Workbook_SheetCalculate(ByVal Sh As Object) stop_timer start_timer End Sub Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _ ByVal Target As Excel.Range) stop_timer start_timer End Sub
Devo inserire anche questi o solo quello proposto da te?
Ti ringrazio in anticipo e ti auguro una buona giornata
Saluti
Marco
Zer0kelvin ne ha sempre una giusta per tutti 🙂 buona idea!
@marco, ogni volta che cambi foglio si resetta il timer. Gli altri eventi che hai citato servono per intercettare il "ricalcolo" del foglio e il cambiamento di cella nel foglio.
Sono tutti palliativi ma puoi provare... in realtà non c'è un evento preciso che intercetti l'Idle di Excel cioè i momenti di inattività.
Sui 48 secondi, dipende dal clock interno, fai un'aggiustatina coi millisecondi e prova...
ciao vecchio frac!
ho inserito il codice, e funziona alla grande. ti ringrazio come sempre per l'aiuto e ringrazio anche gli le altre persone che mi hanno dato una risposta in così breve tempo! e soprattutto che mi hanno portato ad una soluzione. Vi auguro una buona serata e a presto!
Marco
-
AutoreArticoli