Skip to main content

An accessible, editable data grid for wxPython rendered as a real ARIA grid in a WebView (arrow-key cell navigation, in-cell editing, row selection, context menus) that reads correctly in NVDA and JAWS.

Project description

wx-accessible-grid

An accessible, editable data grid for wxPython that a blind person can actually use. Native wx.grid.Grid reads poorly or not at all in NVDA and JAWS, and a hand-built grid of <div>s is worse. This library takes the approach proven by its sibling wx-accessible-webview: render a real, semantic ARIA grid into a WebView and let the screen reader follow it like any web data table, then layer spreadsheet-style keyboard behavior on top.

It is built for data entry, not a spreadsheet engine. There are no formulas. What there is, is every control you actually edit data with, fully keyboard-operable and announced correctly.

What you get

  • Arrow keys move a single focused cell, not the document. Moving across a row speaks the column header. Moving down a column speaks the row header. Only the focused cell is read, so a grid with thousands of rows stays fast instead of making the screen reader re-read the whole table on every keystroke.
  • F2 or Enter edits a cell in place with the right control for the data: edit box, combo box, checkbox, slider, or stepper. Enter commits, Escape cancels.
  • Space, or Ctrl+Space, selects a row. Delete deletes the selection. The context menu key, or Shift+F10, fires a callback so you can show a native menu.
  • Pass row_select=True to add a real checkbox at the start of every row, so selecting rows for a bulk operation (move, reorder, edit a region) is visible and discoverable, not just a keystroke. The host reads grid.selected_rows(), acts through the model, and calls grid.refresh().
  • Editing round-trips through your model, so the value the screen reader confirms is the validated, normalized one, never the raw keystrokes. If an edit is rejected the user hears why and the editor reopens so they can fix it.
  • Only one page of rows is ever in the DOM, but aria-rowcount keeps the user's sense of "row N of many" correct. Arrow past the bottom and the next page loads and navigation just keeps going.

Install

pip install wx-accessible-grid

That pulls in wxPython and wx-accessible-webview.

Use it

Subclass GridModel to describe your columns and provide the data, then drop an AccessibleGrid into a sizer.

import wx
from wx_accessible_grid import AccessibleGrid, GridModel, Column, SetResult
from wx_accessible_grid import TEXT, COMBO, CHECKBOX, SLIDER, STEPPER, NONE

class ChannelModel(GridModel):
    def __init__(self, rows):
        self._rows = rows
        self._cols = [
            Column("num", "#", editor=NONE, is_row_header=True),
            Column("name", "Name", editor=TEXT),
            Column("mode", "Mode", editor=COMBO, choices=["FM", "AM", "USB"]),
            Column("active", "Active", editor=CHECKBOX),
            Column("volume", "Volume", editor=SLIDER, min=0, max=100, step=1),
            Column("priority", "Priority", editor=STEPPER, min=0, max=10),
        ]

    def columns(self):
        return self._cols

    def row_count(self):
        return len(self._rows)

    def display(self, row, column):
        if column == "num":
            return str(row + 1)
        val = self._rows[row][column]
        return "Yes" if (column == "active" and val) else "No" if column == "active" else str(val)

    def edit_value(self, row, column):
        # the form the editor wants, when it differs from the shown text
        if column == "active":
            return "true" if self._rows[row]["active"] else "false"
        return self.display(row, column)

    def set_cell(self, row, column, value):
        # validate and normalize here; what you return is what gets announced
        self._rows[row][column] = value
        return SetResult(True, display=value, message=f"{column} updated")

grid = AccessibleGrid(panel, ChannelModel(rows), label="Memory channels",
                      page_size=100)
sizer.Add(grid.control, 1, wx.EXPAND)

The dev extra (pip install "wx-accessible-grid[dev]") adds pytest for the model and renderer tests, which run without wx.

The editors

  • TEXT: a single-line edit box. Type, then Enter to commit.
  • COMBO: a drop-down of fixed choices, which also stands in for a radio group. Arrow through the list, Enter to commit.
  • CHECKBOX: a boolean toggle. Space toggles it, Enter commits.
  • SLIDER: a range control adjusted with the arrow keys.
  • STEPPER: a number spinner. Type a value or step it with the arrows.
  • NONE: read-only, for ids and computed columns. Not editable.

edit_value gives the editor its starting value when that differs from the displayed text (a checkbox wants true/false, a slider wants a bare number, even if the cell shows Yes or 146.520 MHz).

Keyboard

  • Arrows: move the focused cell. Home / End: first / last cell in the row. Ctrl+Home / Ctrl+End: first / last cell in the grid. Page Up / Page Down: previous / next page.
  • F2 or Enter: edit the focused cell. Enter: commit. Escape: cancel.
  • Space or Ctrl+Space: select or unselect the row.
  • Delete: delete the selected rows, or the focused row if none are selected.
  • Context menu key or Shift+F10: ask the host for a row menu.

How it works

The grid is a <table role="grid"> with <th scope="col"> column headers, a <th scope="row"> row header, and <td role="gridcell"> cells, rendered into an AccessibleWebView. A roving tabindex gives exactly one cell focus at a time, which puts the screen reader in focus mode so it reads that cell and the headers that changed, not the whole table. A small vanilla-JS runtime, installed once, handles navigation, editing, and selection, and talks to Python over the WebView bridge. Your GridModel does the validation and persistence on the Python side.

Status

Version 0.1.0, first release, built for VRP (the accessible radio programmer) and extracted as a reusable library. Tested on macOS WebView with VoiceOver and in unit tests for the model and renderer. NVDA and JAWS verification on Windows WebView2 is the next milestone; reports welcome.

License

MIT. A Community Access open-source project, created by Taylor Arndt.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wx_accessible_grid-0.1.0.tar.gz (23.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wx_accessible_grid-0.1.0-py3-none-any.whl (20.6 kB view details)

Uploaded Python 3

File details

Details for the file wx_accessible_grid-0.1.0.tar.gz.

File metadata

  • Download URL: wx_accessible_grid-0.1.0.tar.gz
  • Upload date:
  • Size: 23.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wx_accessible_grid-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d96d2ce65e0347ba5db0974ef03a295bb07143249a62c6d409dfd1ff1b94cbdd
MD5 d447161720715ad4b02503c79cb56a83
BLAKE2b-256 9c0b4ba1e17bd4d44e05f96d56e87fd6c552a3e0a3451f29ae997fa5c5d6224a

See more details on using hashes here.

File details

Details for the file wx_accessible_grid-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: wx_accessible_grid-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wx_accessible_grid-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4336bf35d0d3b079bd08e1b24acb407c788e7e216d5f0d9bb1c8bc5195b56990
MD5 282612770ee350edcc7279695fa9705e
BLAKE2b-256 17f23b1e95541443eaef05a3a57696ea4075d682be53f4e05030e42bce42836a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page