screen reader not picking up panel, or looping with tab key?

Hello list,
I know most of you aren't screen reader users, but perhaps some of you
are familiar with them at least? In my dialog, tab works
normally--moving from control to control, and looping at the last one,
returning to the first. In my panel, though (loaded into a notebook
which is in a frame), tab stops moving at the last control. I can
shift-tab, but nothing loops. Stranger still, object review mode
(which should let me explore all controls, not just the focusable
ones) doesn't seem to realize my panel is there at all. It picks up
the tab bar where my two tabs are, as well as the system menu and
other standard window controls, but it can't see the content of the
selected tab.

Is this a known problem with WX and/or NVDA (the screen reader), or is
there something I need to do to get this app to be more usable?
Tabbing isn't a big deal, but I'd like to be able to examine my UI for
disabled buttons, static text labels, and other non-focusable controls
that tab will skip. Thanks.

Alex, when I last worked with wxPython development, both jaws and NVEDA seemed to work fine with it, but, haven't worked with tab panels, and has been a little while since did much with wx for real - current issue is trying to get it running under 3.5.1 32-bit, running on a 64 bit windows 10 machine, but anyway.

Stay well

Jacob Kruger
Blind Biker
Skype: BlindZA
"Roger Wilco wants to welcome you...to the space janitor's closet..."

···

On 2016-02-04 8:25 PM, Alex Hall wrote:

Hello list,
I know most of you aren't screen reader users, but perhaps some of you
are familiar with them at least? In my dialog, tab works
normally--moving from control to control, and looping at the last one,
returning to the first. In my panel, though (loaded into a notebook
which is in a frame), tab stops moving at the last control. I can
shift-tab, but nothing loops. Stranger still, object review mode
(which should let me explore all controls, not just the focusable
ones) doesn't seem to realize my panel is there at all. It picks up
the tab bar where my two tabs are, as well as the system menu and
other standard window controls, but it can't see the content of the
selected tab.

Is this a known problem with WX and/or NVDA (the screen reader), or is
there something I need to do to get this app to be more usable?
Tabbing isn't a big deal, but I'd like to be able to examine my UI for
disabled buttons, static text labels, and other non-focusable controls
that tab will skip. Thanks.

Alex Hall wrote:

In my panel, though (loaded into a notebook which is in a frame), tab
stops moving at the last control. I can shift-tab, but nothing loops.
Stranger still, object review mode (which should let me explore all
controls, not just the focusable ones) doesn't seem to realize my
panel is there at all.

Doesn't sound like a wx issue. There might not be many screen reader
users here, or on the wxWidgets lists, but there are plenty that
understand the importance of tab navigation so this would've been picked
up as a bug already. There are also a number of WX-based apps I use on
a daily basis which have a panel inside a notebook, and screen reader
access works fine.

It's more likely that, for whatever reason, your panel isn't being added
to its parent properly. This is usually the cause of such issues.
Unfortunately, without code, it's impossible to say anything further.
If you can, try to get into the habbit of posting code that reproduces
the problem from the very beginning, especially for something like this.

···

--
James Scholes
http://twitter.com/JamesScholes

Sure, here's some code. I'm glad it works generally, as that means
it's me and not the technology. Thus, it can be fixed!

My Notebook is set up like this:

class ADJMFrame(wx.Frame):

def __init__(self, parent, title="AutoDist Job Manager", size=(700,
500), useHighContrast=False, jobsList=):
  super(ADJMFrame, self).__init__(parent, title=title, size=size)

  self.logger = logging.getLogger(globals.appName+"."+__name__+".ADJMFrame")

  notebook = wx.Notebook(self)
  jobsPanel = JobsListManager(notebook, "Jobs", reformattedJobsList,
["Job Name", "Status", "Time Last Run", "Time to Next Run"],
useHighContrast=useHighContrast)
  tablesPanel = DBTablesListManager(notebook, "Tables", tablesList,
["Table Name"], schemas, showEditButton=False,
useHighContrast=useHighContrast)

  notebook.AddPage(jobsPanel, jobsPanel.title)
  notebook.AddPage(tablesPanel, tablesPanel.title)

  if useHighContrast:
   self.SetBackgroundColour("black")

  self.Center()
  self.Show(True)
#end def __init__

Here's part of the __init__ for the panels. I have two types there,
but they both subclass ListManager, so I'll give that one. I've
removed the "self.var=var" stuff for brevity.

class ListManager(wx.Panel):
"""This is the base class for ListManager objects. It takes an array
of arrays and displays each sub-array as a row in a wx.listCtrl, using
the array of columnHeaders as headers. Subclasses should implement the
initUI() method to position/color things, add columns, sort data, and
so on. Remember that this is a wx.Panel, not a wx.Frame."""

def __init__(self,
   parent, #the panel's parent
   title, #string that will be the panel's title
   choices, #an array of arrays, where each array is a row and each
item is a value
   columnHeaders, #an array of strings to use as column headers
   showAddButton=False, #true if you want an 'Add' button shown
   addButtonLabel = None, #string that will be the "add" button's label
   showEditButton = True,
   editButtonLabel = None,
   showDeleteButton=False,
   deleteButtonLabel = None,
   buttonSize=(80, 30),
   useHighContrast = False, #true to use ridiculous, but easy-to-see, colors
   selectedIndex = 0, #an integer, 0-len(choices)-1, that is the index
of the item you want focused when this widget is created
  ):
  super(ListManager, self).__init__(parent)

  self.logger = logging.getLogger(globals.appName+"."+__name__+"."+title)
  self.logger.debug("Initializing.")

  self.addButtonLabel = "&Add" if addButtonLabel == None else addButtonLabel
  self.editButtonLabel = "&Edit" if editButtonLabel == None else editButtonLabel
  self.deleteButtonLabel = "&Delete" if deleteButtonLabel == None else
deleteButtonLabel

  self.items_listControl = wx.ListCtrl(self, id=wx.ID_ANY,
style=wx.LC_REPORT, size=(-1, -1))
  self.add_button = wx.Button(self, wx.ID_ANY, label =
self.addButtonLabel, size=self.buttonSize)
  self.edit_button = wx.Button(self, id=wx.ID_ANY,
label=self.editButtonLabel, size=self.buttonSize)
  self.delete_button = wx.Button(self, id=wx.ID_ANY,
label=self.deleteButtonLabel, size=self.buttonSize)
  self.add_button.Enable(self.showAddButton)
  self.edit_button.Enable(self.showEditButton)
  self.delete_button.Enable(self.showDeleteButton)

  #set the headers
  #now set the data

  self.items_listControl.Bind(wx.EVT_LIST_ITEM_SELECTED,
self.updateSelectedIndex)

  self.blueColor = "#8888ff"
  self.greenColor = "#88ff88"
  self.fireEngineRedColor = "#f62817"

#end def __init__

Finally, this is all kicked off by main.py calling this method:
def initGUI(jobsList, useHighContrast=False):
mainFrame = ADJMFrame(None, globals.appName, (900, 700),
useHighContrast, jobsList)

···

On 2/4/16, James Scholes <james@jls-radio.com> wrote:

Alex Hall wrote:

In my panel, though (loaded into a notebook which is in a frame), tab
stops moving at the last control. I can shift-tab, but nothing loops.
Stranger still, object review mode (which should let me explore all
controls, not just the focusable ones) doesn't seem to realize my
panel is there at all.

Doesn't sound like a wx issue. There might not be many screen reader
users here, or on the wxWidgets lists, but there are plenty that
understand the importance of tab navigation so this would've been picked
up as a bug already. There are also a number of WX-based apps I use on
a daily basis which have a panel inside a notebook, and screen reader
access works fine.

It's more likely that, for whatever reason, your panel isn't being added
to its parent properly. This is usually the cause of such issues.
Unfortunately, without code, it's impossible to say anything further.
If you can, try to get into the habbit of posting code that reproduces
the problem from the very beginning, especially for something like this.
--
James Scholes
x.com

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alex Hall wrote:

  notebook = wx.Notebook(self)
  jobsPanel = JobsListManager(notebook, "Jobs", reformattedJobsList,
["Job Name", "Status", "Time Last Run", "Time to Next Run"],
useHighContrast=useHighContrast)

You're setting your notebook as the parent of your panels. That's
probably what's causing the problem. I see that that is how it's done
in the official wxPython notebook demo, but it doesn't make much sense
to me. A notebook is a list of tabs, but hierarchically, the content of
those tabs is not a direct descendant of the tab control itself.

Perhaps try setting the parent of your pannels to the same parent as the
notebook, and creating an event handler to switch to the appropriate
panel on tab change.

···

--
James Scholes
http://twitter.com/JamesScholes

Changing the parent to "self" (meaning my wx.Frame subclass is the
parent of everything), I get an error when I call notebook.AddPage. It
seems that to add pages, the pages *must* be a descendant of the
notebook to which they're being added.

···

On 2/8/16, James Scholes <james@jls-radio.com> wrote:

Alex Hall wrote:

  notebook = wx.Notebook(self)
  jobsPanel = JobsListManager(notebook, "Jobs", reformattedJobsList,
["Job Name", "Status", "Time Last Run", "Time to Next Run"],
useHighContrast=useHighContrast)

You're setting your notebook as the parent of your panels. That's
probably what's causing the problem. I see that that is how it's done
in the official wxPython notebook demo, but it doesn't make much sense
to me. A notebook is a list of tabs, but hierarchically, the content of
those tabs is not a direct descendant of the tab control itself.

Perhaps try setting the parent of your pannels to the same parent as the
notebook, and creating an event handler to switch to the appropriate
panel on tab change.
--
James Scholes
x.com

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alex Hall wrote:

Changing the parent to "self" (meaning my wx.Frame subclass is the
parent of everything), I get an error when I call notebook.AddPage. It
seems that to add pages, the pages *must* be a descendant of the
notebook to which they're being added.

Okay, but does your frame not have a panel? Your notebook probably
shouldn't be a direct child of the frame. You can have panels within
panels, and in general, all controls should be on a panel. If you're
adding your notebook control directly to a frame, then adding panels to
that, that could also be causing your tab navigation issues.

In other words, add a top-level panel to your frame, add your notebook
to that, then your notebook page panels to the notebook. Then there
will be no part of the window that isn't part of a panel.

···

--
James Scholes
http://twitter.com/JamesScholes

James Scholes wrote:

You're setting your notebook as the parent of your panels. That's
probably what's causing the problem. I see that that is how it's done
in the official wxPython notebook demo, but it doesn't make much sense
to me. A notebook is a list of tabs, but hierarchically, the content of
those tabs is not a direct descendant of the tab control itself.

I disagree. The notebook control is more than just the tabs -- it also
manages the visibility of those panels, hiding one and showing the
next. It makes perfect sense for them to be child controls of the
notebook itself.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

As was suggested, I've added a panel to my frame subclass, and made my
notebook a child of the panel. Object navigation appears to still be
broken.

def __init__(self, parent, title="AutoDist Job Manager", size=(700,
500), useHighContrast=False, jobsList=):
  super(ADJMFrame, self).__init__(parent, title=title, size=size)

  self.logger = logging.getLogger(globals.appName+"."+__name__+".ADJMFrame")

  panel = wx.Panel(self)
  notebook = wx.Notebook(panel)

  jobsPanel = JobsListManager(notebook, "Jobs", reformattedJobsList,
["Job Name", "Status", "Time Last Run", "Time to Next Run"],
useHighContrast=useHighContrast)
  tablesPanel = DBTablesListManager(notebook, "Tables", tablesList,
["Table Name"], schemas, showEditButton=False,
useHighContrast=useHighContrast)

  notebook.AddPage(jobsPanel, jobsPanel.title)
  notebook.AddPage(tablesPanel, tablesPanel.title)

  if useHighContrast:
   self.SetBackgroundColour("black")

  mainSizer = wx.BoxSizer()
  mainSizer.Add(notebook, 1, wx.EXPAND)
  panel.SetSizer(mainSizer)

  self.Center()
  self.Show(True)

···

On 2/8/16, Tim Roberts <timr@probo.com> wrote:

James Scholes wrote:

You're setting your notebook as the parent of your panels. That's
probably what's causing the problem. I see that that is how it's done
in the official wxPython notebook demo, but it doesn't make much sense
to me. A notebook is a list of tabs, but hierarchically, the content of
those tabs is not a direct descendant of the tab control itself.

I disagree. The notebook control is more than just the tabs -- it also
manages the visibility of those panels, hiding one and showing the
next. It makes perfect sense for them to be child controls of the
notebook itself.

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.