当前位置: 首页 > 工具软件 > QCheckBox > 使用案例 >

QCheckBox使用时候的一个注意点

吕皓
2023-12-01

项目中需要使用一个QCheckBox来控制某些界面的显隐,并且在不满足条件的情况下,需要将CheckBox的值恢复到原先的状态。
如CheckBox本身控制着远端设备的启停,从unchecked状态点击,按理说会启动设备,并将CheckBox状态变为checked。但是如果在启动的过程中失败了,这个时候需要恢复CheckBox的状态。
这就是项目的需求。

为了实现状态的恢复,特意设计了一个recover函数,最开始的一版使用的是setChecked()函数,如下:

void recoverState(bool checked)
{
	// 注意,此处使用的是setChecked函数
	ui.checkBox->setChecked(checked);

	ui.widget1->setVisible(checked);
	ui.widget2->setVisible(checked);
}

结果就发现,界面在多次点击的状态下出现了紊乱,简而言之就是checked状态和界面的显隐不匹配(界面的显隐是通过stateChanged信号控制的)。
在调试中发现,虽然此时通过setChecked函数将其状态设置为false了,但是其checkState的值仍然是Qt::Checked,这就是造成显隐状态不一致的原因

这就把我整懵了,百思不得其解的情况下我就去扒了源码,摘录如下:
setChecked的源码:

void QAbstractButton::setChecked(bool checked)
{
    Q_D(QAbstractButton);
    if (!d->checkable || d->checked == checked) {
        if (!d->blockRefresh)
            checkStateSet();
        return;
    }

    if (!checked && d->queryCheckedButton() == this) {
        // the checked button of an exclusive or autoexclusive group cannot be  unchecked
#if QT_CONFIG(buttongroup)
        if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
            return;
        if (d->group)
            d->group->d_func()->detectCheckedButton();
#else
        if (d->autoExclusive)
            return;
#endif
    }

    QPointer<QAbstractButton> guard(this);

    d->checked = checked;
    if (!d->blockRefresh)
        checkStateSet();
    d->refresh();

    if (guard && checked)
        d->notifyChecked();
    if (guard)
        d->emitToggled(checked);


#ifndef QT_NO_ACCESSIBILITY
    QAccessible::State s;
    s.checked = true;
    QAccessibleStateChangeEvent event(this, s);
    QAccessible::updateAccessibility(&event);
#endif
}

setCheckState源码:

*/
void QCheckBox::setCheckState(Qt::CheckState state)
{
    Q_D(QCheckBox);
    if (state == Qt::PartiallyChecked) {
        d->tristate = true;
        d->noChange = true;
    } else {
        d->noChange = false;
    }
    d->blockRefresh = true;
    setChecked(state != Qt::Unchecked);
    d->blockRefresh = false;
    d->refresh();
    if ((uint)state != d->publishedState) {
        d->publishedState = state;
        emit stateChanged(state);
    }
}

由源码可以看出,setChecked是QAbstractButton的方法,而setCheckState是QCheckBox的方法,在setCheckState中调用了setChecked。
而我实在没有看出通过直接调用setChecked的方式,这就导致CheckBox的状态和其checkState不一致的情况(通过界面操作是不影响的,这里说的是通过代码来控制)

因此,如果想要通过代码的来控制QCheckBox的状态,在涉及到影响其他控件的情况下,最好采用setCheckState的方式来进行管理

修改之后的代码如下:

void recoverState(bool checked)
{
	// 换为setCheckState的方式
	ui.cbWlan->setCheckState(checked ? Qt::Checked : Qt::Unchecked);

	ui.widget1->setVisible(checked);
	ui.widget2->setVisible(checked);
}
 类似资料: