Memastikan bahwa Elemen UI Diberi Nama dengan Benar

Topik ini menjelaskan cara yang benar untuk menentukan nama elemen UI di aplikasi Microsoft Win32 Anda sehingga Microsoft Active Accessibility dapat mengekspos nama secara akurat ke aplikasi klien melalui properti Nama IAccessible.

Informasi di bagian ini hanya berlaku untuk Aksesibilitas Aktif Microsoft. Ini tidak berlaku untuk aplikasi yang menggunakan Microsoft UI Automation atau yang didasarkan pada bahasa markup seperti HTML, HTML Dinamis (DHTML), atau XML.

Gambaran Umum

Dalam Microsoft Active Accessibility, setiap elemen UI dalam aplikasi diwakili oleh objek yang mengekspos antarmuka IAccessible . Aplikasi klien menggunakan properti dan metode antarmuka IAccessible untuk berinteraksi dengan elemen UI dan untuk mengambil informasi tentangnya. Salah satu properti terpenting yang diekspos oleh antarmuka IAccessible adalah properti Nama. Aplikasi klien mengandalkan properti Nama untuk menemukan, mengidentifikasi, atau mengumumkan elemen UI kepada pengguna. Jika Microsoft Active Accessibility tidak dapat mengekspos properti Nama dengan benar dari elemen UI tertentu, aplikasi klien tidak akan dapat menyajikan elemen UI tersebut kepada pengguna, dan elemen UI tidak akan dapat diakses oleh pengguna dengan disabilitas.

Bagaimana Penamaan yang Salah Menyebabkan Masalah

Untuk mengilustrasikan masalah yang disebabkan oleh penamaan elemen UI yang salah, pertimbangkan formulir entri nama yang diperlihatkan dalam ilustrasi berikut.

illustration of a simple form for entering first and last name

Meskipun elemen UI dalam bentuk terlihat oke, implementasi terprogram salah. Untuk klien Aksesibilitas Aktif Microsoft seperti pembaca layar, properti Nama dari kontrol edit atas adalah "Nama Belakang:", dan properti Nama kontrol edit bawah adalah string kosong (""). Pembaca layar akan membaca kontrol edit teratas sebagai "Nama Belakang", meskipun pengguna diharapkan mengetikkan nama depan. Pembaca layar akan membaca kontrol edit kedua sebagai "tanpa nama", sehingga pengguna tidak akan tahu apa yang harus diketik ke kontrol edit kedua. Pembaca layar tidak dapat membantu pengguna memasukkan data ke dalam bentuk sederhana ini.

Masalah lain dengan formulir adalah tidak ada kunci pintasan yang ditetapkan ke salah satu kontrol edit. Pengguna dipaksa untuk tab ke kontrol atau menggunakan mouse.

Bagian berikut menjelaskan sumber masalah ini dan memberikan panduan untuk memperbaikinya.

Cara MSAA Mendapatkan Properti Nama

Microsoft Active Accessibility mendapatkan string properti Nama dari lokasi yang berbeda tergantung pada jenis elemen UI. Untuk sebagian besar elemen UI yang memiliki teks jendela terkait, Microsoft Active Accessibility menggunakan teks jendela sebagai string properti Nama. Contoh jenis elemen UI ini termasuk kontrol seperti tombol, item menu, dan tipsalat.

Untuk kontrol berikut, Microsoft Active Accessibility mengabaikan teks jendela dan sebaliknya mencari label teks statis (atau label kotak grup) segera sebelum kontrol dalam urutan tab.

  • Kotak Kombo
  • Pemilih Tanggal dan Waktu
  • Kontrol Edit dan Edit Kaya
  • Kontrol Alamat IP
  • Kotak Daftar
  • Tampilan Daftar
  • Bilah Kemajuan
  • Scrollbars
  • Kontrol statis yang memiliki gaya SS_ICON atau SS_BITMAP
  • Bilah trek
  • Tampilan Pohon

Jika kontrol sebelumnya tidak disertai dengan label teks statis, atau jika label tidak diimplementasikan dengan benar, Microsoft Active Accessibility tidak dapat menyediakan properti Nama yang benar untuk aplikasi klien.

Sebagian besar kontrol sebelumnya benar-benar memiliki teks jendela terkait. Editor sumber daya secara otomatis menghasilkan teks jendela, yang terdiri dari string generik seperti "edit1" atau "listbox3". Meskipun pengembang dapat mengganti teks jendela yang dihasilkan dengan teks yang lebih bermakna, yang paling tidak pernah dilakukan. Karena teks jendela yang dihasilkan tidak memiliki arti untuk pengguna, Microsoft Active Accessibility mengabaikannya dan menggunakan label teks statis yang menyertainya sebagai gantinya.

Cara Menemukan dan Memperbaiki Masalah Penamaan

Dalam formulir entri nama yang diperlihatkan dalam Cara Penamaan Yang Salah Menyebabkan Masalah, penyebab masalahnya adalah urutan tab kontrol salah. Memeriksa UI dengan alat pengujian seperti Inspect akan mengungkapkan masalah dengan hierarki objek. Cuplikan layar berikut menunjukkan hierarki objek rusak dari formulir entri nama saat muncul di Inspeksi.

screen shot of the inspect tool showing an incorrect object hierarchy of the name entry form

Pada cuplikan layar sebelumnya, perhatikan bahwa hierarki objek tidak cocok dengan struktur kontrol saat muncul di antarmuka pengguna formulir entri nama. Perhatikan juga bahwa Inspect telah menetapkan nama yang salah ke item berikutnya ke terakhir (ini adalah kontrol edit untuk memasukkan nama depan dan harus bernama "Nama Depan:". Terakhir, perhatikan bahwa Inspeksi tidak dapat menemukan nama untuk item terakhir (ini adalah kontrol edit untuk memasukkan nama belakang dan harus memiliki nama "Nama Belakang:".

Contoh berikut menunjukkan konten file sumber daya untuk formulir entri nama. Perhatikan bahwa urutan tab tidak konsisten dengan struktur logis kontrol saat muncul di antarmuka pengguna. Perhatikan juga bahwa tidak ada kunci pintasan yang ditentukan untuk dua kontrol edit.

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

Untuk memperbaiki masalah dengan formulir entri nama, file sumber daya (.rc) harus diedit untuk menentukan pintasan keyboard, dan kontrol harus ditempatkan dalam urutan berikut:

  1. Label teks statis "&First Name:".
  2. Kontrol edit untuk memasukkan nama depan (IDC_EDIT1).
  3. Label teks statis "&Nama Belakang:".
  4. Kontrol edit untuk memasukkan nama belakang (IDC_EDIT2).
  5. Tombol tekan default "OK".

Contoh berikut menunjukkan file sumber daya yang dikoreksi untuk formulir entri nama:

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

Untuk melakukan koreksi pada file sumber daya, Anda dapat mengedit file secara langsung, atau Anda dapat menggunakan alat Urutan Tab di Microsoft Visual Studio. Anda dapat mengakses alat Urutan Tab di Visual Studio dengan menekan CTRL+D, atau dengan memilih Urutan Tab dari menu Format.

Setelah mengoreksi dan membangun kembali aplikasi, UI formulir entri nama akan terlihat sama seperti sebelumnya. Namun, Microsoft Active Accessibility sekarang akan menyediakan properti Nama yang benar untuk aplikasi klien, dan akan mengatur fokus dengan benar ketika pengguna menekan pintasan keyboard ALT+F atau ALT+L. Selain itu, Inspeksi akan menampilkan hierarki objek yang benar, seperti yang ditunjukkan oleh cuplikan layar berikut.

screen shot of the accessible explorer tool showing a correct object hierarchy of the name entry form

Cara Memberi Nama Trackbar dengan Benar

Saat menentukan trackbar (atau slider), pastikan bahwa label teks statis utama untuk trackbar muncul sebelum trackbar, dan bahwa label teks statis untuk rentang minimum dan maksimum muncul setelah trackbar. Ingatlah bahwa Microsoft Active Accessibility menggunakan label teks statis yang segera mendahului kontrol sebagai properti Nama untuk kontrol. Menempatkan label teks statis utama segera sebelum trackbar, dan label lain setelahnya, memastikan bahwa Microsoft Active Accessibility menyediakan properti Nama yang benar kepada klien.

Ilustrasi berikut menunjukkan trackbar khas dengan label teks statis utama yang disebut "Kecepatan", dan label teks statis untuk rentang minimum ("min") dan maksimum ("maks").

illustration of a trackbar control that has a main label and labels for the minimum and maximum ranges

Contoh berikut menunjukkan cara yang benar untuk menentukan trackbar dan label teks statisnya dalam file sumber daya:

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

Cara Menggunakan Label Tak Terlihat ke Kontrol Nama

Tidak selalu mungkin atau diinginkan untuk memiliki label yang terlihat untuk setiap kontrol. Misalnya, terkadang menambahkan label dapat menyebabkan perubahan yang tidak diinginkan dalam tampilan UI. Dalam hal ini, Anda dapat menggunakan label yang tidak terlihat. Microsoft Active Accessibility masih akan mengambil teks yang terkait dengan label yang tidak terlihat, tetapi label tidak akan muncul, atau mengganggu UI visual.

Seperti halnya label yang terlihat, label yang tidak terlihat harus segera mendahului kontrol dalam urutan tab. Untuk membuat label tidak terlihat dalam file sumber daya (.rc), tambahkan NOT WS_VISIBLE atau |~WS_VISIBLE ke bagian gaya kontrol teks statis. Jika Anda menggunakan Editor Sumber Daya di Visual Studio, Anda dapat mengatur properti Terlihat ke False.

Cara Menggunakan Anotasi Langsung untuk Menentukan Properti Nama

Proksi default yang disertakan dalam komponen runtime Microsoft Active Accessibility, Oleacc.dll, secara otomatis menyediakan objek IAccessible untuk semua kontrol Windows standar. Jika Anda menyesuaikan kontrol Windows standar, proksi default melakukan yang terbaik untuk menyediakan semua properti IAccessible secara akurat untuk kontrol yang disesuaikan. Anda harus menguji kontrol yang disesuaikan secara menyeluruh untuk memastikan bahwa proksi default memberikan nilai properti yang akurat dan lengkap. Jika pengujian mengungkapkan nilai properti yang tidak akurat atau tidak lengkap, Anda mungkin dapat menggunakan teknik Anotasi Dinamis yang disebut anotasi langsung untuk memberikan nilai properti yang benar dan menambahkan nilai yang hilang.

Perhatikan bahwa Anotasi Dinamis bukan hanya untuk kontrol yang didukung oleh proksi Aksesibilitas Aktif Microsoft. Anda juga dapat menggunakannya untuk memodifikasi atau menyediakan properti untuk kontrol apa pun yang menyediakan implementasi IAccessible sendiri.

Bagian ini berfokus pada penggunaan anotasi langsung untuk memberikan nilai yang benar untuk properti Nama objek IAccessible untuk kontrol. Anda juga dapat menggunakan anotasi langsung untuk menyediakan nilai properti lain. Selain itu, teknik Anotasi Dinamis lainnya selain anotasi langsung tersedia, dan fitur dan kemampuan API Anotasi Dinamis jauh melampaui apa yang dijelaskan di bagian ini. Untuk informasi selengkapnya tentang Anotasi Dinamis, lihat API Anotasi Dinamis.

Langkah-langkah untuk Membuat Anotasi Properti Nama

Menggunakan anotasi langsung untuk mengubah Properti Nama kontrol melibatkan langkah-langkah berikut.

  1. Sertakan file header berikut:

    • Initguid.h
    • Oleacc.h

    Catatan

    Untuk menentukan GUID, Anda harus menyertakan Initguid.h sebelum Oleacc.h dalam file yang sama.

     

  2. Inisialisasi pustaka Model Objek Komponen (COM) dengan memanggil fungsi CoInitializeEx , biasanya selama proses inisialisasi aplikasi.

  3. Segera setelah kontrol target dibuat (biasanya selama pesan WM_INITDIALOG), buat instans manajer anotasi dan dapatkan pointer ke pointer IAccPropServices-nya.

  4. Anotasi Properti Nama kontrol target dengan menggunakan metode IAccPropServices::SetHwndPropStr.

  5. Lepaskan pointer IAccPropServices .

  6. Sebelum kontrol target dihancurkan (biasanya saat menangani pesan WM_DESTROY), buat instans manajer anotasi dan dapatkan pointer ke antarmuka IAccPropServices-nya.

  7. Gunakan metode IAccPropServices::ClearHwndProps untuk menghapus anotasi properti Nama dari kontrol target.

  8. Lepaskan pointer IAccPropServices .

  9. Sebelum aplikasi Anda keluar (biasanya saat memproses pesan WM_DESTROY ), rilis pustaka COM dengan memanggil fungsi CoUninitialize .

Fungsi IAccPropServices::SetHwndPropStr mengambil lima parameter. Tiga pertama—hwnd, idObject, dan idChild—gabungkan untuk mengidentifikasi kontrol. Parameter keempat, idProp, menentukan pengidentifikasi properti yang akan diubah. Untuk mengubah properti Nama, atur idProp ke PROPID_ACC_NAME. (Untuk daftar properti lain yang dapat Anda atur melalui anotasi langsung, lihat Menggunakan Anotasi Langsung.) Parameter terakhir SetHwndPropStr, str, adalah string baru yang digunakan sebagai properti Nama.

Contoh Anotasi Properti Nama

Contoh kode berikut menunjukkan cara menggunakan anotasi langsung untuk mengubah properti Nama objek IAccessible untuk kontrol. Untuk mempermudah hal-hal, contohnya menggunakan string yang dikodekan secara permanen ("Nama Kontrol Baru") untuk mengatur properti Nama. String yang dikodekan secara permanen tidak boleh digunakan dalam versi akhir aplikasi Anda karena tidak dapat dilokalkan. Sebagai gantinya, selalu muat string dari file sumber daya Anda. Selain itu, contoh tidak menunjukkan panggilan ke fungsi CoInitializeEx dan 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;
}