combobox steal keyboard from main window in pyqt - focus

I'm writing a small pyqt program. I want the main window to to react to arrow movement. I added an event to my MainGui class, keyPressEvent, that handle this. The event work fine as long as I don't press certain buttons such as Key_Up or Key_Down are directed to my (currently only) QComboBox and not to my mainGui. I tried to give the focus to mainGui after each paintEvent but then I need to double click on buttons/comboBox.
Then I tried to use the MousePressEvent to check if a certain element is under the mouse. This work fine with the comboBox, but not with the button.
So, how can I direct key events to the mainGui or give the focus to QButtons?

I used eventFilter to identify when the mouse enter the QPushButton and give it focus:
def eventFilter(self,source,event):
if event.type() == QtCore.QEvent.HoverMove:
if self.execButton.underMouse():
self.execButton.setFocus()
self.keepFocus=False
else :
self.keepFocus=True
keepFocus is a flag I initialized in the __init__ function of the class. I added this part at the paintEvent function
if self.keepFocus:
self.setFocus()
else:
self.keepFocus = True
Now, I keep the focus at the MainGui and I only give it to the button when the mouse hove over it. If I do another action (like pressing a mouse button or a keyboard key) the focus is given back to the MainGui. This will create some buggy filling (For example, I need to press twice a keyboard key before the first response) but this is workable.

Related

When typing at the end of the editmask, it will pass the number to the left side until it reaches the last one

Good afternoon,
I'm doing a project in delphi that uses editmask. I'm using the phone mask.
When clicking on edit to write the phone number, it goes to the last field on the right, so it is necessary to go back with the backspace to the beginning of the edit on the left.
i would like to find a way that when the user typed the number in the last field on the right, it was passed to the left. So on until you complete the phone field. It would be possible?
Using an example of what it would look like:
I couldn't think of a way to do it
The component is called TMaskEdit.
Just like anything that bases on TEdit putting the focus onto the control will by default put the text cursor at the end of its content
via keyboard, should .AutoSelect be FALSE and
via mouse if clicking behind any text (by default the text is aligned to the left).
You should have experienced this with the other components already. If you want the text cursor to always be at a certain position upon focusing the control, then do that in such an event handler:
for keyboard use OnEnter:
procedure TForm1.MaskEdit1Enter(Sender: TObject);
begin
(Sender as TMaskEdit).SelStart:= 1; // Second position
end;
and for mouse use OnClick with the same code.
It even works unbound to how the property .AutoSelect is set.
Using Backspace is the worst choice input wise, as it always deletes potential content and needs to be pressed several times to go to the first position. Why not using the Home key instead?

Voiceover not focusing on next form field

I have a long HTML form that I am trying to make accessible to Voiceover. When I click into a field, interact with it, and then click Done on the keyboard, after a short delay Voiceover is focusing on what appears to be the field most centered on the screen rather than the next element. I tried adding explicit tabindex to all the fields and this did not help. It is not always reproducable, it sometimes works as expected.
Is this expected behavior for Voiceover? Would a user not expect "Done" to take them to the next field (seems like maybe a dumb question since there is also a "Next" button, which works fine)? But as a sighted user I know the "Done" button when I am interacting with a field just means I am done with that field and want to go on to the next action, field whatever.
"Done" dismisses editing mode on VoiceOver. A VoiceOver user would not expect that tapping "done" moves the VO cursor.

Disable keyboard shortcut (delphi)

I created a form in Delphi.
Say I have a Form with a speedbutton with label "&Add" (underline A, as a keyboard shortcut), and a dbgrid (read-only state) (or other control like TButton).
Then I changed the focus to Dbgrid (dbgrid got a focus) (or to TButton).
Every time I press the a key on the dbgrid, the onClick method on the speedbutton triggers.
Sometime I need to disable it for a while for a reason, and then i enable it again.
How to disable the speedbutton shortcut?
And then how to enable it again?
The form is pressing the button when you press A because the button has expressed interest in that key, and nothing else on your form is accepting keystrokes. If you had an edit box on your form, and it had the input focus, then the button would not be triggered.
You can make a control indicate that it wants to receive keystrokes when it has the focus, but that generally happens when writing a custom control, where you have some idea of what the new control class should do when it receives keyboard input.
If you don't want the button to be triggered, you can disable it. Another option is to alter the OnClick event handler to check other conditions (such as whether the grid has focus) before performing the usual click-handling code.
You could disable the shortcut by changing the speed button's label from &Add to Add. Change it back when you need to enable the shortcut again.
Please note that specifying an accelerator character like that enables two shortcuts, one is just the key prefaced with the & and the other the same key with Alt. So, in your case they would be A and Alt+A. In the same way, eliminating the accelerator disables both shortcuts. So, keep in mind that with this method of disabling the shortcut you would be unable to trigger the button neither with A nor with Alt+A.

TStringGrid dirty hack - Restricting the selection to one single row

I have a heavily modified control based on TStringGrid. I want to allow the user to make selections in this grid but restrict the selection one single row (the current row).
Implementation:
When the user presses the left mouse button I am using a dirty hack: On OnMouseDown event I capture the mouse cursor and keep it on the current row. The user can move the mouse device up and down on its pad but the cursor will not go up or down. It will stay on the current row. When the user releases the button (OnMouseUp event), I release the capture.
However, this hack is as I said very dirty. There are several problems. For example, if the user presses the left mouse button (LMB) and then without releasing that button it presses the right button, the associated pop-up menu will pop but the mouse capture will never be released. So, the mouse will be locked in a screen region until the user will has the brilliant idea to click the LMB one more time to unlock the mouse. This may be a bug in D7. There is a separate post about it here: TStringGrid - OnMouseUp is not called!
There is a elegant way to do this?
Edit:
OnSelectCell is not working. OnSelectCell event is called only once when you click the cell. If you keep the button pressed and move the mouse to expand the selection, OnSelectCell will not be called again.
Indeed MoveCurrent appears only in TCustomGrid.MouseDown.
Use the OnSelectCell event and set the CanSelect var parameter depending on whether the ARow parameter is what you want.
A nice solution
Check the options property on TStringGrid
There is an Option called 'goRangeSelect'
Set this to false using the object inspector
Or programatically this can be done by
StringGrid1.Options - [goRangeSelect];
This answer is not elegant at all, but it works.
My solution is NOT to use the PopupMenu property of the StringGrid. Instead I implemented my own PopUpMenu property. Works almost perfect. There is on small problem, the bottom of the pop-up menu appears next to the cursor and not its top.

Check if Mouse LButton is down?

How do I check if the Left button of my mouse is currently pressed down/dragging something(I preffer the first possibility).
I tried Mouse.IsDraging,but no result.
NOTE: I handle mouse messages in my application so its no problem if its a WM,just share a way to accomplish my task.
There is a Windows API function GetAsyncKeyState(), which despite its name is also usable to get the state of the mouse buttons. The linked documentation directly contains the answer to your question:
The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling GetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped.
The result type is short, to check for the most significant bit just test whether the value is negative.
OnMouseMove(UINT nFlags, CPoint point)
{
m_LButtonPressed=nFlags & MK_LBUTTON;
CWnd::OnMouseMove(nFlags, point);
}

Resources