您的位置:首页 > 编程语言 > Qt开发

Qt控件焦点切换

2017-05-25 17:29 891 查看
人们日常切换控件,例如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 控件 焦点