Qt控件焦点切换

人们日常切换控件,例如QQ登陆的账号和密码输入框就可以通过Tab键切换焦点。
这里写图片描述
图1 qq切换焦点
Qt中QWidget提供了一个静态方式实现该效果
其中也包含介绍使用

[static] void QWidget::setTabOrder(QWidget *first, QWidget *second)
Puts the second widget after the first widget in the focus order.
Note that since the tab order of the second widget is changed, you should order a chain like this:

  setTabOrder(a, b); // a to b
  setTabOrder(b, c); // a to b to c
  setTabOrder(c, d); // a to b to c to d

not like this:

  // WRONG
  setTabOrder(c, d); // c to d
  setTabOrder(a, b); // a to b AND c to d
  setTabOrder(b, c); // a to b to c, but not c to d

If first or second has a focus proxy, setTabOrder() correctly substitutes the proxy.

实现效果如下
这里写图片描述
图2 Tab切换焦点
主要部分源码

    QPushButton *p = new QPushButton("按钮");
    QLineEdit *l = new QLineEdit("输入框");
    QCheckBox *c =  new QCheckBox("复选框");
    QComboBox *b = new QComboBox;
    setTabOrder(p, l);
    setTabOrder(l, c);
    setTabOrder(c, b);

当然也可以让控件屏蔽焦点的使用,或者接受响应其他类型的焦点方式
主要使用

void setFocusPolicy(Qt::FocusPolicy policy)

其中Qt::FocusPolicy 这个枚举类型定义了一个控件可以用来获取键盘焦点的各种策略。

ConstantValueDescription
Qt::TabFocus0x1the widget accepts focus by tabbing.
Qt::ClickFocus0x2the widget accepts focus by clicking.
Qt::StrongFocusTabFocus | ClickFocus | 0x8he widget accepts focus by both tabbing and clicking. On macOS this will also be indicate that the widget accepts tab focus when in ‘Text/List focus mode’.
Qt::WheelFocusStrongFocus | 0x4like Qt::StrongFocus plus the widget accepts focus by using the mouse wheel.
Qt::NoFocus0the widget does not accept focus.

例如设置
QCheckBox为NoFouse

c->setFocusPolicy(Qt::NoFocus);

效果如下
这里写图片描述
图3 复选框设置NoFocuse
函数

[slot] void QWidget::setFocus() //可通过信号槽方式设置
This is an overloaded function. 
Gives the keyboard input focus to this widget (or its focus proxy) if this widget or one of its parents is the active window.

可直接设置焦点

接下来可以看一下Qt是怎么实现焦点切换的,查看qwidget.cpp源码

void QWidget::setTabOrder(QWidget* first, QWidget *second)
{
    //如果这两个控件都设置为没有焦点则不进行焦点设置,如图3中所示
    if (!first || !second || first->focusPolicy() == Qt::NoFocus || second->focusPolicy() == Qt::NoFocus)
        return;

    /******************************************************************
            QWidget *QWidget::window() const
        {
            QWidget *w = const_cast<QWidget *>(this);
            QWidget *p = w->parentWidget();
            while (!w->isWindow() && p) {
                w = p;
                p = p->parentWidget();
            }
            return w;
        }
    ******************************************************************/
    //查看当前控件“祖先”(ancestor widget)窗口,见上面代码
    if (Q_UNLIKELY(first->window() != second->window())) {
        qWarning("QWidget::setTabOrder: 'first' and 'second' must be in the same window");
        return;
    }

    //找到first或其子类中焦点的控件(不是很懂)
    QWidget *fp = first->focusProxy();
    if (fp) {
        QList<QWidget *> l = first->findChildren<QWidget *>();
        for (int i = l.size()-1; i >= 0; --i) {
            QWidget * next = l.at(i);
            if (next->window() == fp->window()) {
                fp = next;
                if (fp->focusPolicy() != Qt::NoFocus)
                    break;
            }
        }
        first = fp;
    }

    if (fp == second)
        return;

    if (QWidget *sp = second->focusProxy())
        second = sp;

    //双向链表存储焦点触发控件顺序
//    QWidget *fp = first->d_func()->focus_prev;
    QWidget *fn = first->d_func()->focus_next;

    if (fn == second || first == second)
        return;

    QWidget *sp = second->d_func()->focus_prev;
    QWidget *sn = second->d_func()->focus_next;

    fn->d_func()->focus_prev = second;
    first->d_func()->focus_next = second;

    second->d_func()->focus_next = fn;
    second->d_func()->focus_prev = first;

    sp->d_func()->focus_next = sn;
    sn->d_func()->focus_prev = sp;

    //查错
    Q_ASSERT(first->d_func()->focus_next->d_func()->focus_prev == first);
    Q_ASSERT(first->d_func()->focus_prev->d_func()->focus_next == first);

    Q_ASSERT(second->d_func()->focus_next->d_func()->focus_prev == second);
    Q_ASSERT(second->d_func()->focus_prev->d_func()->focus_next == second);
}
Qt中,方向键可以用于控制焦点在不同控件之间切换。在默认情况下,焦点可以通过Tab键在控件之间切换,而方向键可以改变焦点的默认行为。 当用户按下方向键时,Qt会根据当前焦点所在的控件和按下的方向键来确定下一个焦点应该是哪个控件。例如,如果当前焦点在一个文本框中,按下向下方向键,焦点可能会切换到下一个可接受焦点控件,例如下一个文本框或者一个按钮。同样地,按下向上、向左或者向右方向键时,焦点会在可接受焦点控件之间切换。 在Qt中,可以通过重写控件的focusInEvent()或者focusOutEvent()函数来处理焦点切换时的事件。在这些事件中,可以根据需要来修改控件的样式或者执行其他自定义操作。可以利用Qt的事件过滤器机制来拦截和处理特定的焦点切换事件。 此外,Qt还提供了一些属性和函数来控制焦点切换的顺序和规则。使用QWidget的setFocusPolicy()函数可以设置控件接受焦点的策略,例如设置为Qt::StrongFocus表示控件可以接受焦点,并且方向键可以改变焦点。此外,可以使用QWidget的setTabOrder()函数来设置控件之间的Tab键切换顺序,从而影响焦点切换时的方向键切换行为。 总之,Qt提供了灵活而强大的机制来处理方向键控制焦点的功能,开发者可以根据自己的需求来定制焦点切换的行为和样式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值