Skip to content

Sluggishness while using a screenreader (NVDA) #9

@vincent-lg

Description

@vincent-lg

Hi,

I'm grateful for your work. Allowing async/await in wxPython is great.

Unfortunately, while testing, I find a pretty strange sluggishness which I'm unable to explain. Is it because I'm running on Windows? Or because I'm using only the keyboard (as a screen reader users)? Keyboard events would generate and I can understand, for every key I press, four or five events could be sent... actually more than that. Still, that doesn't sound like a lot of event. Yet, I find a performance of about 200ms each time I press a key, enough to be perceptible. I've simplified your example to a very simple window with only three widgets (two list boxes and one text entry). You can see the problem when typing quickly in the text area, or when changing from widget to widget using the tab key (not the mouse).

import wx
import time

from wxasync import AsyncBind, WxAsyncApp, StartCoroutine
import asyncio
from asyncio.events import get_event_loop

ASYNC_VERSION = True

class BasicFrame(wx.Frame):
    def __init__(self, parent=None, id=-1, title=""):
        wx.Frame.__init__(self, parent, id, title, size=(800,800))
        self.wx_panel = wx.Panel(self)
        self.wx_sizer = wx.BoxSizer(wx.VERTICAL)
        self.left = wx.ListBox(self.wx_panel, name="list1")
        self.wx_sizer.Add(self.left)
        self.right = wx.ListBox(self.wx_panel, name="list2")
        self.wx_sizer.Add(self.right)
        self.text = wx.TextCtrl(self.wx_panel, name="Username")
        self.wx_sizer.Add(self.text)
        self.wx_panel.SetSizerAndFit(self.wx_sizer)

        # Fills the lists
        self.left.Append("One")
        self.left.Append("Two")
        self.left.Append("Three")
        self.right.Append("First")
        self.right.Append("Second")

def main():
    class MyApp(wx.App):

        def OnInit(self):
            frame = BasicFrame(title="test")
            frame.Show(True)
            self.SetTopWindow(frame)

            return True

    app = MyApp(0)
    app.MainLoop()
    # del app

def main_async():
    # see https://github.com/sirk390/wxasync
    app = WxAsyncApp()
    frame = BasicFrame(title="test")
    frame.Show(True)
    app.SetTopWindow(frame)
    loop = get_event_loop()
    loop.run_until_complete(app.MainLoop())

if __name__ == "__main__":
    if ASYNC_VERSION:
        main_async()
    else:
        main()

What's causing this delay? I'm not sure. Obviously, if decreasing asyncio.sleep in the main loop to something smaller, this lag decreases and slowly (incredibly slowly) disappears if a small value is set. But then the problem of a small value is the CPU goes up and up to compensate. Lots of overhead. So I was puzzling over this problem and I still don't find a solution. Obviously, it would be helpful if the loop could instead send its events to be processed to an asynchronous loop, for instance. The coroutine responsible for reading the loop would just block until an event is available. But we're still dealing with the same problem: wxPython and another event loop don't get along so well, except if you don't mind the CPU overhead.

But from seeing the code I can't decide what's causing the delay in particular. 5ms for a sleep is definitely not huge. Again, a key press (particularly the tab key which encourages to switch between widgets, hence triggering lots of events) might fire tens of events... but that's still not enough, in theory, to be perceptible by the user. Any help on this would be appreciated!

Thanks in advance,

Vincent

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions