Verifica che gli elementi dell'interfaccia utente siano denominati correttamente

Questo argomento descrive il modo corretto per specificare i nomi degli elementi dell'interfaccia utente nelle applicazioni Microsoft Win32 in modo che Microsoft Active Accessibility possa esporre accuratamente i nomi alle applicazioni client tramite la proprietà IAccessible Name.

Le informazioni contenute in questa sezione si applicano solo a Microsoft Active Accessibility. Non si applica alle applicazioni che usano Microsoft Automazione interfaccia utente o a quelle basate su linguaggi di markup come HTML, DHTML (Dynamic HTML) o XML.

Panoramica

In Microsoft Active Accessibility ogni elemento dell'interfaccia utente in un'applicazione è rappresentato da un oggetto che espone l'interfaccia IAccessible . Le applicazioni client usano le proprietà e i metodi dell'interfaccia IAccessible per interagire con l'elemento dell'interfaccia utente e recuperare informazioni su di esso. Una delle proprietà più importanti esposte dall'interfaccia IAccessible è la proprietà Name. Le applicazioni client si basano sulla proprietà Name per trovare, identificare o annunciare un elemento dell'interfaccia utente all'utente. Se Microsoft Active Accessibility non è in grado di esporre correttamente la proprietà Name di un particolare elemento dell'interfaccia utente, le applicazioni client non saranno in grado di presentare l'elemento dell'interfaccia utente all'utente e l'elemento dell'interfaccia utente non sarà accessibile agli utenti con disabilità.

In che modo la denominazione non corretta causa problemi

Per illustrare i problemi causati dalla denominazione errata degli elementi dell'interfaccia utente, prendere in considerazione il modulo di immissione del nome illustrato nella figura seguente.

illustrazione di un modulo semplice per l'immissione di nome e cognome

Anche se gli elementi dell'interfaccia utente nel modulo hanno un aspetto corretto, l'implementazione a livello di codice non è corretta. Per un client Microsoft Active Accessibility, ad esempio un'utilità per la lettura dello schermo, la proprietà Name del controllo di modifica superiore è "Last Name:" e la proprietà Name del controllo di modifica inferiore è una stringa vuota (""). L'utilità per la lettura dello schermo leggerà il controllo di modifica superiore come "Cognome", anche se l'utente deve digitare il nome. L'utilità per la lettura dello schermo leggerà il secondo controllo di modifica come "nessun nome", quindi l'utente non avrà idea di cosa digitare nel secondo controllo di modifica. L'utilità per la lettura dello schermo non è in grado di aiutare l'utente a immettere i dati in questo modulo semplice.

Un altro problema con il modulo è che nessun tasto di scelta rapida viene assegnato a uno dei controlli di modifica. L'utente deve passare tramite tabulazioni ai controlli o usare il mouse.

Le sezioni seguenti illustrano l'origine di questi problemi e forniscono linee guida per correggerle.

Come MSAA ottiene la proprietà Name

Microsoft Active Accessibility ottiene la stringa della proprietà Name da posizioni diverse a seconda del tipo dell'elemento dell'interfaccia utente. Per la maggior parte degli elementi dell'interfaccia utente che hanno associato il testo della finestra, Microsoft Active Accessibility usa il testo della finestra come stringa della proprietà Name. Alcuni esempi di questo tipo di elemento dell'interfaccia utente includono controlli quali pulsanti, voci di menu e descrizioni comando.

Per i controlli seguenti, Microsoft Active Accessibility ignora il testo della finestra e cerca invece un'etichetta di testo statica (o etichetta casella di gruppo) immediatamente precedente al controllo nell'ordine di tabulazione.

  • Caselle combinate
  • Selezione data e ora
  • Modificare e modificare i controlli Rich Edit
  • Controlli indirizzo IP
  • Caselle di riepilogo
  • Visualizzazioni elenco
  • Indicatore di stato
  • Barre di scorrimento
  • Controlli statici con stile SS_ICON o SS_BITMAP
  • Barre di avanzamento
  • Visualizzazioni albero

Se i controlli precedenti non sono accompagnati da etichette di testo statiche o se le etichette non vengono implementate correttamente, Microsoft Active Accessibility non può fornire la proprietà Name corretta alle applicazioni client.

La maggior parte dei controlli precedenti ha effettivamente il testo della finestra associato. L'editor di risorse genera automaticamente il testo della finestra, costituito da una stringa generica, ad esempio "edit1" o "listbox3". Anche se gli sviluppatori possono sostituire il testo della finestra generata con testo più significativo, la maggior parte non lo fa mai. Poiché il testo della finestra generata non ha alcun significato per l'utente, Microsoft Active Accessibility lo ignora e usa invece l'etichetta di testo statica associata.

Come trovare e correggere i problemi di denominazione

Nel modulo di immissione del nome illustrato in How Incorrect Naming Causes Problems,the cause of the problems is that the tab order of the controls is incorrect. Esaminando l'interfaccia utente con uno strumento di test, ad esempio Inspect , vengono rilevati i problemi relativi alla gerarchia degli oggetti. La schermata seguente mostra la gerarchia di oggetti interrotta del modulo di immissione del nome visualizzato in Inspect.

screenshot dello strumento di ispezione che mostra una gerarchia di oggetti non corretta del modulo di immissione del nome

Nella schermata precedente si noti che la gerarchia di oggetti non corrisponde alla struttura dei controlli così come vengono visualizzati nell'interfaccia utente del modulo di immissione del nome. Si noti anche che Inspect ha assegnato il nome non corretto all'elemento successivo all'ultimo elemento (è il controllo di modifica per l'immissione del nome e deve essere denominato "Nome:". Infine, si noti che Inspect non è riuscito a trovare un nome per l'ultimo elemento (si tratta del controllo di modifica per l'immissione del cognome e deve avere un nome "Cognome:".

Nell'esempio seguente viene illustrato il contenuto del file di risorse per il modulo di immissione del nome. Si noti che l'ordine di tabulazioni non è coerente con la struttura logica dei controlli così come vengono visualizzati nell'interfaccia utente. Si noti inoltre che non vengono specificati tasti di scelta rapida per i due controlli di modifica.

IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,179,35,30,11,WS_GROUP
    LTEXT           "First Name:",IDC_STATIC,8,16,43,8
    LTEXT           "Last Name:",IDC_STATIC,8,33,43,8
    EDITTEXT        IDC_EDIT1,53,15,120,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT2,53,34,120,12,ES_AUTOHSCROLL
END

Per risolvere i problemi relativi al modulo di immissione del nome, è necessario modificare il file della risorsa (rc) per specificare i tasti di scelta rapida e i controlli devono essere inseriti nell'ordine seguente:

  1. Etichetta di testo statica "&First Name:".
  2. Controllo di modifica per l'immissione del nome (IDC_EDIT1).
  3. Etichetta di testo statica "&Last Name:".
  4. Controllo di modifica per l'immissione del cognome (IDC_EDIT2).
  5. Pulsante di pressione predefinito "OK".

Nell'esempio seguente viene illustrato il file di risorse corretto per il modulo di immissione del nome:

IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
    LTEXT           "&First Name:",IDC_STATIC,8,16,43,8
    EDITTEXT        IDC_EDIT1,53,15,120,12,ES_AUTOHSCROLL
    LTEXT           "&Last Name:",IDC_STATIC,8,33,43,8
    EDITTEXT        IDC_EDIT2,53,34,120,12,ES_AUTOHSCROLL
    DEFPUSHBUTTON   "OK",IDOK,179,35,30,11,WS_GROUP
END

Per apportare correzioni a un file di risorse, è possibile modificare direttamente il file oppure usare lo strumento Ordine di tabulazioni in Microsoft Visual Studio. È possibile accedere allo strumento Ordine di tabulazione in Visual Studio premendo CTRL+D oppure selezionando Ordine di tabulazione dal menu Formato .

Dopo aver corretto e ricompilato l'applicazione, l'interfaccia utente del modulo di immissione dei nomi sarà identica a quella precedente. Tuttavia, Microsoft Active Accessibility ora fornirà le proprietà Name corrette alle applicazioni client e imposta lo stato attivo correttamente quando l'utente preme i tasti di scelta rapida ALT+F o ALT+L. Inoltre, Inspect mostrerà la gerarchia degli oggetti corretta, come illustrato nella schermata seguente.

screenshot dello strumento Di esplorazione accessibile che mostra una gerarchia di oggetti corretta del modulo di immissione del nome

Come assegnare un nome corretto a una barra di rilevamento

Quando si definisce una barra di avanzamento (o un dispositivo di scorrimento), assicurarsi che l'etichetta di testo statica principale per la barra di avanzamento venga visualizzata prima della barra di avanzamento e che le etichette di testo statiche per gli intervalli minimo e massimo vengano visualizzate dopo la barra di avanzamento. Tenere presente che Microsoft Active Accessibility usa l'etichetta di testo statica che precede immediatamente un controllo come proprietà Name per il controllo. Posizionare l'etichetta di testo statica principale immediatamente prima della barra di avanzamento e le altre etichette dopo di essa, garantisce che Microsoft Active Accessibility fornisca la proprietà Name corretta a un client.

La figura seguente mostra una barra di avanzamento tipica con un'etichetta di testo statica principale denominata "Speed" e etichette di testo statiche per gli intervalli minimo ("min") e massimo ("max").

illustrazione di un controllo trackbar con un'etichetta principale e etichette per gli intervalli minimo e massimo

Nell'esempio seguente viene illustrato il modo corretto per definire una barra di avanzamento e le relative etichette di testo statiche nel file di risorse:

BEGIN
    ...

    LTEXT           "&Speed",IDC_STATIC,47,20,43,8
    CONTROL         "",IDC_SLIDER1,"msctls_trackbar32",
                    TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,
                    32,32,62,23
    LTEXT           "min",IDC_STATIC,16,37,15,8
    LTEXT           "max",IDC_STATIC,94,38,43,8

    ...
END

Come usare etichette invisibili per denominare i controlli

Non è sempre possibile o auspicabile avere un'etichetta visibile per ogni controllo. Ad esempio, talvolta l'aggiunta di etichette può causare modifiche indesiderate nell'aspetto dell'interfaccia utente. In questo caso, è possibile usare etichette invisibili. Microsoft Active Accessibility continuerà a raccogliere il testo associato a un'etichetta invisibile, ma l'etichetta non verrà visualizzata o interferirà con l'interfaccia utente visiva.

Come per le etichette visibili, un'etichetta invisibile deve precedere immediatamente il controllo nell'ordine di tabulazione. Per rendere invisibile un'etichetta in un file di risorse (rc), aggiungere NOT WS_VISIBLE o |~WS_VISIBLE alla parte di stile del controllo testo statico. Se si usa l'editor di risorse in Visual Studio, è possibile impostare la proprietà Visible su False.

Come usare l'annotazione diretta per specificare la proprietà Name

I proxy predefiniti inclusi nel componente runtime microsoft Active Accessibility, Oleacc.dll, forniscono automaticamente un oggetto IAccessible per tutti i controlli Standard di Windows. Se si personalizza un controllo Windows standard, i proxy predefiniti offrono il massimo per fornire in modo accurato tutte le proprietà IAccessible per il controllo personalizzato. È consigliabile testare accuratamente un controllo personalizzato per assicurarsi che i proxy predefiniti forniscano valori di proprietà accurati e completi. Se il test rivela valori non accurati o incompleti delle proprietà, è possibile usare la tecnica di annotazione dinamica denominata annotazione diretta per fornire valori di proprietà corretti e aggiungere quelli mancanti.

Si noti che l'annotazione dinamica non è solo per i controlli supportati dai proxy di Microsoft Active Accessibility. È anche possibile usarlo per modificare o fornire proprietà per qualsiasi controllo che fornisce la propria implementazione IAccessible .

Questa sezione è incentrata sull'uso dell'annotazione diretta per fornire un valore corretto per la proprietà Name dell'oggetto IAccessible per un controllo . È possibile usare l'annotazione diretta per fornire anche altri valori delle proprietà. Sono inoltre disponibili altre tecniche di annotazione dinamica accanto all'annotazione diretta e le funzionalità dell'API Di annotazione dinamica si estendono ben oltre quanto descritto in questa sezione. Per altre informazioni sull'annotazione dinamica, vedere API di annotazione dinamica.

Passaggi per annotare la proprietà Name

L'uso dell'annotazione diretta per modificare la proprietà Name di un controllo prevede i passaggi seguenti.

  1. Includere i file di intestazione seguenti:

    • Initguid.h
    • Oleacc.h

    Nota

    Per definire i GUID, è necessario includere Initguid.h prima di Oleacc.h nello stesso file.

     

  2. Inizializzare la libreria COM (Component Object Model) chiamando la funzione CoInitializeEx , in genere durante il processo di inizializzazione dell'applicazione.

  3. Subito dopo la creazione del controllo di destinazione (in genere durante il messaggio di WM_INITDIALOG ), creare un'istanza del gestore di annotazioni e ottenere un puntatore al puntatore IAccPropServices .

  4. Annotare la proprietà Name del controllo di destinazione usando il metodo IAccPropServices::SetHwndPropStr.

  5. Rilasciare il puntatore IAccPropServices.

  6. Prima che il controllo di destinazione venga eliminato definitivamente (in genere quando si gestisce il messaggio di WM_DESTROY ), creare un'istanza del gestore di annotazioni e ottenere un puntatore all'interfaccia IAccPropServices .

  7. Utilizzare il metodo IAccPropServices::ClearHwndProps per cancellare le annotazioni della proprietà Name dal controllo di destinazione.

  8. Rilasciare il puntatore IAccPropServices.

  9. Prima dell'uscita dell'applicazione (in genere durante l'elaborazione del messaggio WM_DESTROY ), rilasciare la libreria COM chiamando la funzione CoUninitialize .

La funzione IAccPropServices::SetHwndPropStr accetta cinque parametri. I primi tre, ovvero hwnd, idObject e idChild, combinano per identificare il controllo. Il quarto parametro, idProp, specifica l'identificatore della proprietà da modificare. Per modificare la proprietà Name, impostare idProp su PROPID_ACC_NAME. Per un elenco di altre proprietà che è possibile impostare tramite annotazione diretta, vedere Uso dell'annotazione diretta. L'ultimo parametro di SetHwndPropStr, str, è la nuova stringa da usare come proprietà Name.

Esempio di annotazione della proprietà Name

Nel codice di esempio seguente viene illustrato come utilizzare l'annotazione diretta per modificare la proprietà Name dell'oggetto IAccessible per un controllo . Per semplificare le operazioni, nell'esempio viene utilizzata una stringa hardcoded ("New Control Name") per impostare la proprietà Name. Le stringhe hardcoded non devono essere usate nella versione finale dell'applicazione perché non possono essere localizzate. Caricare invece sempre le stringhe dal file di risorse. Inoltre, l'esempio non mostra le chiamate alle funzioni CoInitializeEx e CoUninitialize .

#include <initguid.h>
#include <oleacc.h>

// AnnotateControlName - Uses direct annotation to change the Name property 
// of the IAccessible object for a control.
//
// hDlg - Handle of the dialog box that contains the control.
// hwndCtl - Handle of the control whose Name property is to be changed.
HRESULT AnnotateControlName(HWND hDlg, HWND hwndCtl)
{
    HRESULT hr;        

    IAccPropServices *pAccPropSvc = NULL;  

    // Create an instance of the annotation manager and retrieve the 
    // IAccPropServices pointer.
    hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, 
        IID_IAccPropServices, (void **) &pAccPropSvc);

    if (hr != S_OK || pAccPropSvc == NULL)
        return hr;

    // Set the Name property for the control.
    // Note: A hard-coded string is used here to keep the example simple.
    // Always use localizable string resources in your applications. 
    hr = pAccPropSvc->SetHwndPropStr(hwndCtl, OBJID_CLIENT, CHILDID_SELF, 
        PROPID_ACC_NAME, L"New Control Name");

    pAccPropSvc->Release();
    
    return hr;
}

// RemoveAnnotatedNameFromControl - Removes the annotated name from the 
// Name property of the IAccessible object for a control.
//
// hDlg - Handle of the dialog box that contains the control.
// hwndCtl - Handle of the control whose annotated name is to be removed.
HRESULT RemoveAnnotatedNameFromControl(HWND hDlg, HWND hwndCtl)
{
    HRESULT hr;

    IAccPropServices *pAccPropSvc = NULL;

    // Create an instance of the annotation manager and retrieve the 
    // IAccPropServices pointer.
    hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, 
        IID_IAccPropServices, (void **) &pAccPropSvc);

    if (hr != S_OK || pAccPropSvc == NULL)
        return hr;

    // Remove the annotated name from the Name property for the control.
    MSAAPROPID propid = PROPID_ACC_NAME;
    hr = pAccPropSvc->ClearHwndProps(hwndCtl, OBJID_CLIENT, CHILDID_SELF, 
        &propid, 1);

    // Release the annotation manager.
    pAccPropSvc->Release();

    return hr;
}