c++ - 如何将父小部件焦点重定向到子小部件?

标签 c++ qt user-interface widget focus

有一个名为FloatingPointPropertyEditor的简单类。它继承自 QWidget,并包含一个带有 float 验证器的 QLineEdit 实例。

class FloatingPointPropertyEditor : public QWidget
{
    Q_OBJECT

    // ...

private:
    QLineEdit* m_lineEdit;
};

问题是我必须将 FloatingPointPropertyEditor 实例的焦点重定向到内部 QLineEdit 实例,并选择其中的所有文本。也就是说,当FloatingPointPropertyEditor获得焦点时,用户已经可以在QLineEdit实例中输入文本,而无需之前单击它。您能解释一下我该怎么做吗?

最佳答案

来自 Qt。文档。关于 QWidget::focusPolicy :

focusPolicy : Qt::FocusPolicy

This property holds the way the widget accepts keyboard focus

The policy is Qt::TabFocus if the widget accepts keyboard focus by tabbing, Qt::ClickFocus if the widget accepts focus by clicking, Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if it does not accept focus at all.

You must enable keyboard focus for a widget if it processes keyboard events. This is normally done from the widget's constructor. For instance, the QLineEdit constructor calls setFocusPolicy(Qt::StrongFocus).

If the widget has a focus proxy, then the focus policy will be propagated to it.

关于提到的焦点代理,关于 QWidget::setFocusProxy() :

void QWidget::setFocusProxy(QWidget *w)

Sets the widget's focus proxy to widget w. If w is nullptr, the function resets this widget to have no focus proxy.

Some widgets can "have focus", but create a child widget, such as QLineEdit, to actually handle the focus. In this case, the widget can set the line edit to be its focus proxy.

setFocusProxy() sets the widget which will actually get focus when "this widget" gets it. If there is a focus proxy, setFocus() and hasFocus() operate on the focus proxy.


TL;DR:

默认焦点策略QWidgetQt::NoFocus ,默认为QLineEditQt::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)

Snapshot of testQWidgetFocus

Snapshot of testQWidgetFocus (after pressing Tab)

Snapshot of testQWidgetFocus (after pressing Tab)

输出:(在 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)

Snapshot of testQWidgetFocus (in X11)

Snapshot of testQWidgetFocus (after pressing Tab)

Snapshot of testQWidgetFocus (after pressing Tab)

注意:

我更改了涉及的焦点策略QPushButton 。因此,它在 Tab 跳转中被跳过(但仍然可以通过鼠标单击使用)。在不改变其焦点策略的情况下,它也被考虑在 Tab 跳转中。


构建脚本:

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

关于c++ - 如何将父小部件焦点重定向到子小部件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57865905/

相关文章:

c++ - 窗口中的QT窗口?

delphi - Firemonkey:TBitmap.Canvas 绘图方法没有可见结果。我究竟做错了什么?

c++ - 自定义字符串文字

c++ - 指针和文字常量

python - 如何将Qt图形场景项保存在文件中并再次打开它?

java - 如何让按钮不被点击?

html - 将输入元素放置在页面右侧

c++ - 使用 DRY 原则重构逻辑

c++ - 如果将 POD 包装在类中,是否会产生相同的效果?

c++ - 为什么 Qt 不鼓励图像本地化?