Saturday, June 14, 2014

Well, that was easy -- I think

The issue with the focus-in was bugging me during the night. Lying in the dark with my eyes closed, debugging. Not productive! But got up this morning and modified the event handler in my editview, the one that up until a little while ago read:

    def eventFilter(self, obj, event):
        if event.type() == QEvent.KeyPress :
            return self._editorKeyPressEvent(event)
        if event.type() == QEvent.FocusIn :
            self.focusser()
        return False

Slight digression here. Because the actual QPlainTextEditor is part of a layout created with the Qt Designer, there is no way to add any kind of event handler to it. In particular no way to add an overriding keyPressEvent() method, which this editor needs in order to support things like the go-to-bookmark and zoom-font keystrokes. Also no way to provide an overriding focusInEvent() handler which I needed as a signal that it was time to display all the "panels" associated with that particular book (or so I thought).

So instead, the editview module, after initializing its Designer-written UI, installs an "event filter" on it, the above code. An event filter is a "man in the middle" that returns True if it has dealt with the event, or False to say, send it along to the original address for handling. All events directed to the UI widgets—the editor and the line-number and page-name widgets—pass through this code first. It picks off the key presses and looks for special keys, returning False for those it didn't handle.

It also used the FocusIn event as a sign it should call the focussing function it was passed by the Book when instantiated. (Which calls the main window, which displays all the related panels, long story.)

That's what I found yesterday wasn't reliably working. When the editview was created and assigned to a QTabWidget tab, it got a FocusIn. Then it got no more of those until the user manually clicked in the editor. Even if you brought another tab to the front, hiding this one, then brought it back: no events unless it had received at least one real click. You could tell it was in this state because the QPlainTextEdit widget did not display a blinking cursor. After a click, it would. Or, I found out, after a tab key. If you press tab an unpredictable number of times, eventually the new editview would get a FocusIn. I'd tried adding calls to self.setFocus(Qt.TabFocusReason) in several places during initialization, to no avail.

So what I did this morning was add to the above code a call to a routine I'd written some time back, to display the event stream. Here's the event sequence, after opening two books, but before clicking in either of them. Just clicking the tabs to alternate between the two editviews, the events are:

2two_test.txt event type  Show 
2two_test.txt event type  UpdateLater 
2two_test.txt event type  Paint 
2two_test.txt event type  Hide 
3three_test.txt event type  Show 
3three_test.txt event type  UpdateLater 
3three_test.txt event type  Paint 
3three_test.txt event type  Hide 

After having manually clicked in each widget, the one last clicked upon gets FocusOut and FocusIn events, but the others don't. All told, it seems that the FocusIn event is nowhere near as consistent or reliable as I'd assumed. There are no doubt various window-system-related issues that I'm not aware of. (And given that thought, very probably there are platform differences as well!)

What the event trace printout does show to be reliable, is the Show and Hide events. So I simply changed my event filter to say, if event.type() == QEvent.Show... and things began to work the way I expect them to.

No comments: