如何将父小部件焦点重定向到子小部件?
Posted
技术标签:
【中文标题】如何将父小部件焦点重定向到子小部件?【英文标题】:How to redirect parent widget focus to a child widget? 【发布时间】:2019-09-10 07:24:12 【问题描述】:有一个名为FloatingPointPropertyEditor
的简单类。它继承自 QWidget
并包含一个带有浮点数验证器的 QLineEdit
实例。
class FloatingPointPropertyEditor : public QWidget
Q_OBJECT
// ...
private:
QLineEdit* m_lineEdit;
;
问题是我必须将FloatingPointPropertyEditor
实例的焦点重定向到内部QLineEdit
实例并选择其中的所有文本。也就是说,当FloatingPointPropertyEditor
获得焦点时,用户已经可以在QLineEdit
实例中输入文本,而无需之前单击它。你能解释一下我该怎么做吗?
【问题讨论】:
不能从QLineEdit
继承FloatingPointPropertyEditor
?
@Scheff 我想在将来在FloatingPointPropertyEditor
中添加其他小部件,例如QPushButton
。所以这个编辑器可能是一个复杂的小部件。
【参考方案1】:
来自 Qt。博士。关于QWidget::focusPolicy
:
focusPolicy : Qt::FocusPolicy
此属性保存小部件接受键盘焦点的方式
如果小部件通过 Tab 键接受键盘焦点,则策略为 Qt::TabFocus,如果小部件通过单击接受焦点,则为 Qt::ClickFocus,如果两者都接受,则为 Qt::StrongFocus,如果同时接受,则为 Qt::NoFocus(默认值)它根本不接受焦点。
如果小部件处理键盘事件,您必须为它启用键盘焦点。这通常由小部件的构造函数完成。例如,QLineEdit 构造函数调用 setFocusPolicy(Qt::StrongFocus)。
如果小部件有焦点代理,则焦点策略将传播给它。
关于提到的焦点代理,关于QWidget::setFocusProxy()
:
void QWidget::setFocusProxy(QWidget *w)
将小部件的焦点代理设置为小部件 w。如果 w 为 nullptr,则该函数将此小部件重置为没有焦点代理。
一些小部件可以“拥有焦点”,但会创建一个子小部件(例如 QLineEdit)来实际处理焦点。在这种情况下,小部件可以将行编辑设置为其焦点代理。
setFocusProxy() 设置小部件,当“这个小部件”获得它时,它实际上将获得焦点。如果有焦点代理,setFocus() 和 hasFocus() 对焦点代理进行操作。
TL;DR:
QWidget
的默认焦点策略是Qt::NoFocus
,QLineEdit
的默认焦点策略是Qt::StrongFocus
。有了这个,它应该可以开箱即用(尽管关于setFocusProxy()
的文档使这个恕我直言不明显)。
可以肯定的是,我做了一个小演示testQWidgetFocus.cc
:
#include <QtWidgets>
class Editor: public QWidget
private:
QHBoxLayout _qHBox;
QLineEdit _qEdit;
QPushButton _qBtn0;
public:
Editor(QWidget *pQParent = nullptr):
QWidget(pQParent),
_qBtn0(">|<")
_qHBox.addWidget(&_qEdit, 1);
_qBtn0.setFocusPolicy(Qt::NoFocus);
_qHBox.addWidget(&_qBtn0);
setLayout(&_qHBox);
// signal handler
connect(&_qBtn0, &QPushButton::clicked,
[&](bool) _qEdit.clear(); );
virtual ~Editor() = default;
Editor(const Editor&) = delete;
Editor& operator=(const Editor&) = delete;
;
int main(int argc, char **argv)
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QWidget qWinMain;
QFormLayout qForm;
QLineEdit qEdit1;
qForm.addRow("QLineEdit:", &qEdit1);
Editor qEdit2;
qForm.addRow("Editor:", &qEdit2);
qDebug() << "qEdit2.focusPolicy():" << qEdit2.focusPolicy();
qDebug() << "qEdit2.focusProxy():" << qEdit2.focusProxy();
Editor qEdit3;
qForm.addRow("Editor:", &qEdit3);
qWinMain.setLayout(&qForm);
qWinMain.show();
return app.exec();
输出:(编译于 VS2017,Qt 5.13)
Qt Version: 5.13.0
qEdit2.focusPolicy(): Qt::NoFocus
qEdit2.focusProxy(): QWidget(0x0)
⇄
⇄
输出:(用cygwin64编译)
$ g++ --version
g++ (GCC) 7.4.0
$ qmake-qt5 testQWidgetFocus.pro
$ make && ./testQWidgetFocus
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQWidgetFocus.o testQWidgetFocus.cc
g++ -o testQWidgetFocus.exe testQWidgetFocus.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
qEdit2.focusPolicy(): Qt::FocusPolicy(NoFocus)
qEdit2.focusProxy(): QWidget(0x0)
⇄
⇄
注意:
我更改了涉事QPushButton
的关注策略。因此,它在跳格中被跳过(但仍然可以通过鼠标单击使用)。在不改变其焦点策略的情况下,它也被考虑在 Tab-jumping 中。
构建脚本:
CMakeLists.txt
:
project(QWidgetFocus)
cmake_minimum_required(VERSION 3.10.0)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Qt5Widgets CONFIG REQUIRED)
include_directories("$CMAKE_SOURCE_DIR")
add_executable(testQWidgetFocus
testQWidgetFocus.cc)
target_link_libraries(testQWidgetFocus
Qt5::Widgets)
# define QT_NO_KEYWORDS to prevent confusion between of Qt signal-slots and
# other signal-slot APIs
target_compile_definitions(testQWidgetFocus PUBLIC QT_NO_KEYWORDS)
testQWidgetFocus.pro
:
SOURCES = testQWidgetFocus.cc
QT += widgets
【讨论】:
以上是关于如何将父小部件焦点重定向到子小部件?的主要内容,如果未能解决你的问题,请参考以下文章
如何在颤动中从父小部件调用子小部件的initState()方法