Corretta utilizzazione della proprietà OpenArgs

di il
45 risposte

Corretta utilizzazione della proprietà OpenArgs

Premessa: sono alle prime armi e sto studiando VBA; tuttavia come esercitazione, sto cercando di costruire un DB per il mio archivio di musica lirica. Ho cercato su questo forum le discussioni riguardanti l'argomento e ho cercato di applicare quanto ho capito: evidentemente poco!

Sto costruendo la maschera per l'inserimento delle edizioni che ho di tutte le opere; tale inserimento avviene in due passaggi: prima inserisco l'Edizione, che comprende tutti i campi che mi occorrono, tranne i cantanti, cioè gli interpreti e poi inserisco i cantanti. Ho pensato di utilizzare due maschere: InsNuovaEdizione, con il comando Salva che dovrebbe passare l'IDEdizione alla InsNuovaInterpretazione con la proprietà OpenArgs del metodo OpenForm. In InsNuovaInterpretazione dovrei caricare solo i personaggi relativi a quella determinata opera, per i quali poi dovrò inserire, tramite caselle combinate, i relativi interpreti.

Non funziona niente! Ho la sensazione di essermi addentrato in un dedalo da cui non riesco ad uscire...

Chiedo allora se è possibile che qualcuno mi aiuti a capire come si usa OpenArgs: ho letto anche sul supporto di Microsoft, ho letto le discussioni di questo forum, ho letto le definizioni, ma credo che quando si tratta poi di applicare la teoria alla pratica mi sfugga qualcosa.

Grazie.

45 Risposte

  • Re: Corretta utilizzazione della proprietà OpenArgs

    Provo a dirti qualcosa per come la vedo io e usando il linguaggio a me più congeniale (terra-terra).
    A) Quando si tratta di dati correlati, il classico ID da una tabella/maschera a un'altra, sfrutta più la condizione WHERE di DoCmd.OpenForm.
    B) OpenArgs è una STRINGA che si usa come un "testimone" da passare da una maschera1 a maschera2. Proprio come un testimone resta in maschera2 e maschera1 può tranquillamente essere anche chiusa (se non serve). È una proprietà che non esiste tra la lista delle proprietà interne delle maschere (e anche report) e si gestisce solo ed esclusivamente in VBA.
    Ora maschera1 decide di aprire maschera2 con DoCmd.OpenForm e l'utente ci mette in OpenArgs = "Pippo". A questo punto, maschera2 aprendosi si carica della propria Me.OpenArgs = "Pippo". Tutti i codici che girano dentro i vari eventi di maschera2 possono servirsi del valore Me.OpenArgs.
    A cosa serve OpenArgs (che non è obbligatorio)? Lo si può usare in tanti modi...e occorre agire di strategia. Io ad esempio lo uso spesso se maschera2 può capitare di essere chiamata da più maschere. Ogni maschera che la chiama si fa riconoscere con il proprio OpenArgs invocato. Poi con un Select Case Me.OpenArgs dentro maschera2 puoi gestire il da farsi caso per caso. L'evento più usato su maschera2 per gestire queste cose è "Su caricamento" (Load).
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Intanto ti ringrazio Osvaldo: in una dozzina di righe mi hai fatto capire più dei testi consultati finora (sì, lo so che il problema è mio, non ho ancora una visione globale dell'uso di VBA e di tutte le sue potenzialità).

    Quindi, se ho capito bene:

    1. a me servono IDEdizione (per accodare l'insieme di personaggi dell'opera che sto considerando all'Edizione che sto inserendo) e IDTitolo (per estrarre esattamente e solo quell'insieme di personaggi dalla TabPersonaggi);

    2. potrei memorizzare IDEdizione e IDTitolo in una stringa (per esempio: str="[IDEdizione]" & "-" & [IDTitolo]) e poi scrivere... già, scrivere cosa? Dovrei prima separare i due dati, per esempio con l'istruzione varID=Split(Me.OpenArgs,"-"), ossia, sull'evento LOAD di InsNuovaInterpretazione:
    Dim str As String
    str="[IDEdizione]-[IDTitolo]"
    DoCmd.OpenForm "InsNuovaInterpretazione", acNormal, , , acFormAdd, acDialog,"str"
    varID=Split(Me.OpenArgs,"-")
    3. A questo punto disporrei di varID(0)=IDEdizione e di varID(1)=IDTitolo

    O no?

    4. Da quando sto combattendo con questo problema, mi dico: magari sto architettando tutto questo per realizzare un qualcosa che potrebbe essere fatto molto più semplicemente... ed ho il terrore che sia così!

    5. Osvaldo, poi ho impostato la query di accodamento e funziona... non sono riuscito però ancora ad utilizzarla...
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Donizetti ha scritto:



    .. potrei memorizzare IDEdizione e IDTitolo in una stringa (per esempio: str="[IDEdizione]" & "-" & [IDTitolo]) e poi scrivere...
    
    Dim str As String
    str="[IDEdizione]-[IDTitolo]"
    DoCmd.OpenForm "InsNuovaInterpretazione", acNormal, , , acFormAdd, acDialog,"str"
    varID=Split(Me.OpenArgs,"-")
    Ti stai avvicinando ma commetti errori "d'infanzia" ...
    Se vuoi utilizzare Openargs non puoi passare un array ma solo una stringa come stai tentando di fare tu.
    La stringa devi comporla non tanto pensando in maniera umana ma cercando di identificare un carattere che ti possa agevolare la vita per fare lo split, io ti consiglio di usare il carattere pipe | (lo ottieni premendo shift e \) o un altro carattere a tuo piacimento purché tu abbia la certezza che non sia usato anche nei campi che compongono la stringa e che non possa dare adito a confusione (il segno meno è comunque un operatore che sebbene non disturbi è meglio evitare di usare, il segno più sarebbe più problematico).
    Poi devi prestare attenzione a come concateni la stringa, ovvero a cosa concateni. Per come hai scritto tu la concatenazione non ottieni quello che credi (ovvero il valore di IDEdizione e il valore di IDTitolo separati dal segno meno) ma ottieni letteralmente quello che hai scritto (quindi ottieni un testo che non ti servirà a nulla).
    Quindi tu dovresti scrivere qualcosa del genere :
    
    str = me.IDEdizione & "|" & me.IDTitolo
    
    Gli apici (o i doppi apici) fanno la differenza, io non uso la sintassi con le parentisi quadre preferisco utilizzare l'intellisense (prova a digitare me. e poi capisci).
    Per quanto riguarda poi l'utilizzo della proprietà Openargs tu DEVI utilizzarla negli eventi del form chiamato (quindi InsNuovaInterpretazione) e NON nel form chiamante. Per come fai tu, stai cercando di utilizzare il valore dell'Openargs del chiamante (che ti ricordo è una proprietà di sola lettura che tu imposti proprio nel momento che lanci il comando OpenForm).
    Nel form chiamato puoi utilizzare l'evento Form_Load oppure l'evento Form_Open per utilizzare l'openargs.
    Utilizzo dello split nel form chiamato :
    
    i.e. nell'evento Form_Open
    Dim varID()  as variant (potrebbe essere Long oppure string)
    varID=split(me.openargs,"|")
    if ubound(varID()) > 0 then
    	'ho separato la stringa di partenza e ho ottenuto almeno 2 elementi nell'arrary varID
    	varID(0) - contiene l'IDEdizione
    	varID(1) - contiene l'IDTitolo
    endif
    
    Penso che ci sia ancora qualcosa a livello di logica che non funzioni ma inizia prima a vedere se riesci a fare qualche passo avanti.
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Per essere in linea con il titolo della discussione, max.riservo ti sta dando la soluzione esatta.
    Io però, proprio perché OpenArgs lavora su UNA STRINGA...non so perché...mi sembra una strategia poco favorevole quella del carattere speciale e lo Split a seguire.
    So di andare fuori tema, ma riguardo strettamente al problema "di fondo" di Donizetti, io preferirei tenere "in viva memoria" IDEdizione (corrente) e IDTitolo (corrente).
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Grazie Max: sto imparando più partecipando a queste discussioni, che leggendo testi voluminosi. È vero, sono ancora un lattante: ho una conoscenza solo superficiale sia di Access, sia soprattutto del VBA, per cui mi rendo conto di commettere errori in ogni dove.
    So di andare fuori tema, ma riguardo strettamente al problema "di fondo" di Donizetti, io preferirei tenere "in viva memoria" IDEdizione (corrente) e IDTitolo (corrente).
    Che intendi dire con tenere in viva memoria?
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Tieni presente che oltre a passare un valore si può anche passare un riferimento al Pointer di un Oggetto qualsiasi, una maschera, un controllo, una classe...
    Ovviamente poi serve fare il restpre del pointer dalla memoria.
    Questo è leggermente più complesso, ma ad esempio se si volessero passare più proprietà una valida alternativa alla stringa concatenata dal carattere speciale come suggerito giustamente da Max, potrebbe essere passare una collection di valori pescabili per Key(nome proprietà).
    Magari serve un esempio... appena ho 3 minuti lo posto.
    Saluti
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Donizetti ha scritto:


    Che intendi dire con tenere in viva memoria?
    [Maschere]![InsNuovaEdizione]![IDEdizione] e [Maschere]![Titoli]![IDTitolo] sono i valori di riferimento tenendo le maschere aperte che puntano sui corrispondenti ID.
    Se lavori dentro il VBA [Maschere] viene sostituito da Forms.
    Ripeto, rischiamo di andare fuori dal titolo della discussione...ne abbiamo già parlato in una precedente...
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Sì, mi rendo conto.

    Ma allora devo lasciar perdere, non ne vengo a capo. Continuerò a studiare il VBA e ad approfondire Access.

    Grazie a tutti, soprattutto per la pazienza.
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Giusto per chiarire alcuni aspetti:

    OsvaldoLaviosa ha scritto:


    [Maschere]![InsNuovaEdizione]![IDEdizione] e [Maschere]![Titoli]![IDTitolo] sono i valori di riferimento tenendo le maschere aperte che puntano sui corrispondenti ID.
    La tua soluzione implica che vi sia la sequenza prefissata fra la prima maschera e la susseguente (che prenda quindi, con riferimenti fissi, i dati dalla form iniziale);
    La soluzione con OpenArgs rende più indipendenti le due form in quanto:
    - si può valutare se il parametro OpenArgs è stato fornito e quindi operare (con o senza parametro in modo anche da non avere possibili errori);
    - la maschera che deve ricevere il parametro OpenArgs può essere richiamata da, qualsiasi, ulteriore form e non da una specifica (offrendo maggiore personalizzazione).

    Il procedimento è piuttosto semplice e, per ottenere ulteriori esempi pratici, si possono visionare le seguenti discussioni:
    https://forum.ialweb.it/forum_posts.asp?TID=1527435
    https://forum.ialweb.it/forum_posts.asp?TID=1646457
    https://www.youtube.com/watch?v=vh00PQ9y6r
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Faccio un esempio di come passare il riferimento ad un Oggetto Complesso, senza dover dichairare Variabili o Oggetti Public, invece di usare una Stringa Concatenata.

    Codice nella Maschera Principale chiamata [fOpenArgSendObject].
    In questa Maschera dichiaro una Collection ed associo Proprietà(usate come KEY) e relativo Valore.
    Ricavo il Pointer in memoria della collection e lo passo come Args.
    
    Option Compare Database
    Option Explicit
    
    Private Sub OpenReceiverForm_Click()
        
        Dim mC      As New Collection
        mC.Add Date, "DataIniziale"
        mC.Add "126", "IdPK"
        mC.Add "Paolo Rossi", "Cliente"
        mC.Add "Via Mazzini 3, 37100 Verona", "Indirizzo"
        
        DoCmd.OpenForm "fOpenArgsReceiveObject", , , , , , GetPointerToObject(mC)
    End Sub
    Questa è la Form secondaria o ricevente [fOpenArgsReceiveObject], recupero la proprietà OpenArgs e sapendo che è un Pointer in memoria recupero l'oggetto ad esso associato.
    
    Option Compare Database
    Option Explicit
    
    Private Sub Form_Load()
        Dim mC      As Collection
    
        Set mC = GetObjectFromPointer(Me.OpenArgs)
    
        Debug.Print mC.Item("DataIniziale")
        Debug.Print mC.Item("IdPK")
        Debug.Print mC.Item("Cliente")
        Debug.Print mC.Item("Indirizzo")
        ' --------------------------------------------------------------------------
        ' Aprire la Finestra Immediata CTRL+G dal VBEditor...
        ' --------------------------------------------------------------------------
    End Sub
    Mi pare semplice intuire che sia possibile passare qualsiasi Oggetto, Maschere, Controlli, e Classi strutturate.

    Ora le poche righe di codice da inserire in un MOdulo Standard per lo scambio del Pointer/Object:
    
    Option Explicit
    Option Compare Text
    
    ' API and constants from http://allapi.mentalis.org/apilist/apilist.php
    Private Const POINTERSIZE As Long = 4
    Private Const ZEROPOINTER As Long = 0
    
    #If VBA7 Then
        Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal length As LongPtr)
    #Else
        Private Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As Any, ByRef Source As Any, ByVal length As Long)
    #End If
    
    Public Function GetPointerToObject(ByRef objThisObject As Object) As Long
        ' Purpose  : Return the value of a pointer.
        ' Argument : A pointer to an Object.
        ' Author   : ChrisO.
        ' Updated  : 2012-04-18
        
        Dim lngThisPointer As Long
    
        RtlMoveMemory lngThisPointer, objThisObject, POINTERSIZE
        GetPointerToObject = lngThisPointer
    
    End Function
    
    Public Function GetObjectFromPointer(ByVal lngThisPointer As Long) As Object
        ' Purpose  : Return a pointer to an Object.
        ' Argument : The value of a Pointer.
        ' Author   : ChrisO.
        ' Updated  : 2012-04-18
        
        Dim objThisObject As Object
    
        RtlMoveMemory objThisObject, lngThisPointer, POINTERSIZE
        Set GetObjectFromPointer = objThisObject
        RtlMoveMemory objThisObject, ZEROPOINTER, POINTERSIZE
    
    End Function
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Ultimo tentativo di capire, dopodiché mi arrendo alla mia incapacità!

    Ho creato due mascherelle: MascheraChiamante e MascheraChiamata.

    La prima contiene 5 Edizioni e mostra i valori di IDEdizione e di IDTitolo.

    Maschera_chiamante.JPG
    Maschera_chiamante.JPG

    Il comando Apri maschera contiene il seguente codice:
    Private Sub ApriMaschera_Click()
    Dim str As Variant
    DoCmd.RunCommand Command:=acCmdSaveRecord
    str = Me.IDEdizione & "|" & Me.IDTitolo
    DoCmd.OpenForm "MascheraChiamata", acNormal, , , , acDialog, str
    End Sub
    La MascheraChiamata mi deve mostrare i due ID provenienti dalla MascheraChiamante: quindi ha due caselle di testo (txtIDEdizione e txtIDTItolo) e, all'evento Load, ha il seguente codice:
    Private Sub Form_Load()
    Dim varID() As Variant
    If Len(Me.OpenArgs) > 0 Then
    	varID() = Split(Me.OpenArgs, "|")
    End If
    txtIDEdizione = varID(0)
    txtIDTitolo = varID(1)
    End Sub
    Può darsi che già così abbia commesso degli errori... ma quando clicco sul comando, compare il messaggio "Errore di runtime '13': Tipo non corrispondente". Il Debug mi evidenzia la riga varID() = Split(Me.OpenArgs, "|").

    Cosa succede? Perché?
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Openargs è di tipo stringa.
    Cambia questo :
    
    Nel Chiamante
    Dim str as string
    
    Nel Chiamato
    Dim varID() as string
    
    Fai sapere ...
  • Re: Corretta utilizzazione della proprietà OpenArgs

    Manca l'indice... non puoi usare un array a prescindere sia string o variant senza indicare quale indice stai valorizzando.
    Quindi così dovrebbe andare:
    
    Private Sub Form_Load()
    Dim varID As Variant
    If Len(Me.OpenArgs) > 0 Then
    	varID = Split(Me.OpenArgs, "|")
    End If
    txtIDEdizione = varID(0)
    txtIDTitolo = varID(1)
    End Sub
    
    Oppure come ha indicato Max.
  • Re: Corretta utilizzazione della proprietà OpenArgs

    @Alex ha scritto:


    Manca l'indice... non puoi usare un array a prescindere sia string o variant senza indicare quale indice stai valorizzando.
    Mea culpa ...
Devi accedere o registrarti per scrivere nel forum
45 risposte