When I TAB
around a form with labels and line edits I don't see QLabel
s getting any focus; the focus rightly passes to the line edit next to it i.e. to the QWidget
that is label.nextInFocusChain()
.
What I originally want: in a QLineEdit.editingFinished
's slot I want to set focus to the next (in TAB order) line edit. I do self.sender().nextInFocusChain().setFocus()
; instead of a line edit, its label, the one next in focus chain, gets focus.
When QLabel.setFocus()
is called, focus is on the label itself; doing another TAB
sets the focus to the expected line edit after it. Why is this the case? Why isn't the focus not set to the widget after it? Why is the focus not set like the TAB
key does?
I checked the focus policy of the labels; they Qt.NoFocus
(default). I also set the textInteractionFlags
of the label to Qt.NoTextInteraction
in vain.
Setting the line edit as the label's focus-proxy does what I want, but I'm not convinced this is the correct solution; or there's a gap in my understanding.
#!/usr/bin/env python3
import sys
from PySide2.QtWidgets import QApplication, QLineEdit, QWidget, \
QFormLayout, QPushButton, QMainWindow, QLabel
from PySide2.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
txtName = QLineEdit('')
txtAge = QLineEdit('')
self.lblAge = QLabel('&Age')
self.lblAge.setBuddy(txtAge)
# This or (default) Qt.LinksAccessibleByMouse doesn't help.
# self.lblAge.setTextInteractionFlags(Qt.NoTextInteraction)
btnNext = QPushButton('N&ext')
btnNext.clicked.connect(self.moveFocus)
formLayout = QFormLayout()
formLayout.addRow('&Name', txtName)
formLayout.addRow(self.lblAge, txtAge)
formLayout.addRow(btnNext)
window = QWidget()
window.setLayout(formLayout)
self.setCentralWidget(window)
def moveFocus(self):
self.lblAge.setFocus()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
I'm on ArchLinux with Xfce4 desktop environment using Qt5's official Python bindings i.e. PySide2.
The focus policy of widgets only tells whether the widget will accept focus after user interaction; in fact, the documentation says, for example, that "the widget accepts keyboard focus by tabbing" or "by clicking".
When a label is set for a buddy it doesn't mean that it can get focus, nor that it's part of the focus chain, and neither it will set the focus on that buddy when it actually receives it (programmatically or not): the only purpose of the buddy feature is to set the focus on the buddy when its shortcut is triggered.
Calling setFocus()
explicitly, though, will always make the widget get focus, even if its policy is NoFocus
, and that's because the call has been done programmatically, and it didn't get the focus from user interaction. Plus, the widget must be able to receive a focus in event, even if it ignores it, and that's exactly how focus proxies work.
In fact, when focus is changed by user interaction (including window activation), Qt does not call setFocus()
at all; instead, it sends a QFocusEvent to the target widget, which would eventually be propagated to the parent(s) in the object tree.
It's unclear why you're trying to set the focus based on the label, but if you really need to do that, then you have the following options:
setFocus()
for that;focusInEvent()
, and do the above;With the subclass approach you can even override the mousePressEvent
handler so that when the user clicks the label, it will automatically set the focus on the buddy.
The same can be done by setting the widget as focus proxy of the label and then setting the focus policy of the label to ClickFocus
.