[原创]探讨多个QRadioButtons的AutoExclusive的问题
在写代码的过程中, 遇到一个问题:
原来有一个UI文件, 将5个RadioButton分成2组, 前三个(例如: radioBtn1,radioBtn2, radioBtn3)和后两个(radioBtn4, radioBtn5)各放在一个VeticallyLayout里. QT Designer中的截图如下所示:
在代码里, 两组都可以独立工作, 互不干扰. 以下为例:
void testFun()
{
...
radioBtn1->setChecked(false);
radioBtn2->setChecked(true);
radioBtn3->setChecked(false);
...
radioBtn4->setChecked(true);
radioBtn5->seteChecked(false);
...
}
程序运行后可以看到, radioBtn2和radioBtn4是选中的.
后来我修改了UI文件, 将两组又放在了一个VeticallyLayout里, 如下图所示:
代码未变, 但是运行后发现, 上面3个始终选不中. 只有下面2个是可以正常work的. 百思不得其解...中间的解决过程费了不少脑细胞, 又是仔细比较.ui文件, 又是找人帮忙, 最终在一位牛人点解下回到起点: 求助QT Qssistant.
在QT Assistant中关于QRadioButton, 写有这样的话:
A QRadioButton is an option button that can be switched on (checked) or off (unchecked). Radio buttons typically present the user with a "one of many" choice. In a group of radio buttons only one radio button at a time can be checked; if the user selects another button, the previously selected button is switched off.
Radio buttons are autoExclusive by default. If auto-exclusive is enabled, radio buttons that belong to the same parent widget behave as if they were part of the same exclusive button group. If you need multiple exclusive button groups for radio buttons that belong to the same parent widget, put them into a QButtonGroup.
不难看出什么意思了吧? 同属于一个相同的父widget的radiobuttons是autoExclusive的.
在我的代码中, radioBtn2虽然是被选中的, 但是之后的radioBtn4将其冲掉了. 这种情形, 只能老老实实用QButtonGroup(parent is QObject)或者QGroupBox(parent is QWidget)来将两组分开了.
代码如下:
// in ctor
{
ui.setupUi(this);
...
// use QButtonGroup to excluse from the two QRadioButtons below.
QButtonGroup *btnGroup = new QButtonGroup(this);
btnGroup->addButton(ui.radAllConnections);
btnGroup->addButton(ui.radListedConnections);
btnGroup->addButton(ui.radNoTrust);
...
}
但是有个问题, the same parent widget是说同一个父widget, QLayout不是QWidget的子类啊????? 在另外一个高人点解下, 发现, 原来的UI中, 虽然放在了两个Vertically Layou中, 但是, 其实是放在了一个QWidget中. 查看UI文件的code可以看到:
verticalLayout_3 = new QVBoxLayout();
layoutWidget2 = new QWidget(settings_firewall_page); //这是radAllConnections, radListedConnections和radNoTrust的parent Widget.
layoutWidget2->setObjectName(QString::fromUtf8("layoutWidget2"));
layoutWidget2->setGeometry(QRect(120, 440, 144, 96));
verticalLayout_4 = new QVBoxLayout(layoutWidget2);
verticalLayout_3 = new QVBoxLayout();
verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3"));
radAllConnections = new QRadioButton(layoutWidget2);
radAllConnections->setObjectName(QString::fromUtf8("radAllConnections"));
QSizePolicy sizePolicy5(QSizePolicy::Preferred, QSizePolicy::Preferred);
sizePolicy5.setHorizontalStretch(0);
sizePolicy5.setVerticalStretch(0);
sizePolicy5.setHeightForWidth(radAllConnections->sizePolicy().hasHeightForWidth());
radAllConnections->setSizePolicy(sizePolicy5);
verticalLayout_3->addWidget(radAllConnections);
radListedConnections = new QRadioButton(layoutWidget2);
radListedConnections->setObjectName(QString::fromUtf8("radListedConnections"));
sizePolicy5.setHeightForWidth(radListedConnections->sizePolicy().hasHeightForWidth());
radListedConnections->setSizePolicy(sizePolicy5);
verticalLayout_3->addWidget(radListedConnections);
radNoTrust = new QRadioButton(layoutWidget2);
radNoTrust->setObjectName(QString::fromUtf8("radNoTrust"));
sizePolicy5.setHeightForWidth(radNoTrust->sizePolicy().hasHeightForWidth());
radNoTrust->setSizePolicy(sizePolicy5);
verticalLayout_3->addWidget(radNoTrust);
verticalLayout_4->addLayout(verticalLayout_3);
/*****************************/
layoutWidget3 = new QWidget(settings_firewall_page); //radPingOn和radPingOff的parent Widget.
layoutWidget3->setObjectName(QString::fromUtf8("layoutWidget3"));
layoutWidget3->setGeometry(QRect(120, 310, 141, 111));
verticalLayout = new QVBoxLayout(layoutWidget3);
verticalLayout_2 = new QVBoxLayout();
verticalLayout_2->setSpacing(10);
verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2"));
radPingOn = new QRadioButton(layoutWidget3);
radPingOn->setObjectName(QString::fromUtf8("radPingOn"));
sizePolicy5.setHeightForWidth(radPingOn->sizePolicy().hasHeightForWidth());
radPingOn->setSizePolicy(sizePolicy5);
verticalLayout_2->addWidget(radPingOn);
radPingOff = new QRadioButton(layoutWidget3);
radPingOff->setObjectName(QString::fromUtf8("radPingOff"));
sizePolicy5.setHeightForWidth(radPingOff->sizePolicy().hasHeightForWidth());
radPingOff->setSizePolicy(sizePolicy5);
verticalLayout_2->addWidget(radPingOff);
verticalLayout->addLayout(verticalLayout_2);
这两组RadioButton的parent Widget分别是layoutWidget2和layoutWidget3. 因此, 它们不属于the same parent widget, 可以实现各自的autoExclusive.
后来我修改的时候, 将这两组RadioButton又放在了一个VerticallyLayout中, 然后与其他的widgets一起, 放在了同一个Page上(QWidget). 此时生成的ui代码是:
...
void setupUi(QWidget *settings_firewall_page)
{
...
verticalLayout_6 = new QVBoxLayout(settings_firewall_page); //这是5个RadioButtons的parent widget.
...
verticalLayout_3 = new QVBoxLayout();
verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3"));
radAllConnections = new QRadioButton(settings_firewall_page);
radAllConnections->setObjectName(QString::fromUtf8("radAllConnections"));
QSizePolicy sizePolicy4(QSizePolicy::Preferred, QSizePolicy::Preferred);
sizePolicy4.setHorizontalStretch(0);
sizePolicy4.setVerticalStretch(0);
sizePolicy4.setHeightForWidth(radAllConnections->sizePolicy().hasHeightForWidth());
radAllConnections->setSizePolicy(sizePolicy4);
verticalLayout_3->addWidget(radAllConnections);
radListedConnections = new QRadioButton(settings_firewall_page);
radListedConnections->setObjectName(QString::fromUtf8("radListedConnections"));
sizePolicy4.setHeightForWidth(radListedConnections->sizePolicy().hasHeightForWidth());
radListedConnections->setSizePolicy(sizePolicy4);
verticalLayout_3->addWidget(radListedConnections);
radNoTrust = new QRadioButton(settings_firewall_page);
radNoTrust->setObjectName(QString::fromUtf8("radNoTrust"));
sizePolicy4.setHeightForWidth(radNoTrust->sizePolicy().hasHeightForWidth());
radNoTrust->setSizePolicy(sizePolicy4);
verticalLayout_3->addWidget(radNoTrust);
verticalLayout_4->addLayout(verticalLayout_3);
...
verticalLayout_5->addLayout(verticalLayout_4);
...
verticalLayout_2 = new QVBoxLayout();
verticalLayout_2->setSpacing(10);
verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2"));
radPingOn = new QRadioButton(settings_firewall_page);
radPingOn->setObjectName(QString::fromUtf8("radPingOn"));
sizePolicy4.setHeightForWidth(radPingOn->sizePolicy().hasHeightForWidth());
radPingOn->setSizePolicy(sizePolicy4);
verticalLayout_2->addWidget(radPingOn);
radPingOff = new QRadioButton(settings_firewall_page);
radPingOff->setObjectName(QString::fromUtf8("radPingOff"));
sizePolicy4.setHeightForWidth(radPingOff->sizePolicy().hasHeightForWidth());
radPingOff->setSizePolicy(sizePolicy4);
verticalLayout_2->addWidget(radPingOff);
verticalLayout->addLayout(verticalLayout_2);
...
verticalLayout_5->addLayout(verticalLayout);
...
horizontalLayout->addLayout(verticalLayout_5);
...
verticalLayout_6->addLayout(horizontalLayout);
...
}
可以看出, 这5个RadioButton的parent Widget都变成了同一个settings_firewall_page!
因此, 这5个之间才是真正autoExclusive的. TrollTech的SE这样处理, 可能是基于优化ui文件的考量吧, 我还没有更深的认识. 哪位知道的朋友可以告知. 谢谢先!
个人总结: 安全起见, 最好是在QT Designer里将两组分别放在一个QGroupBox里, 或者在source codes里, 用QButtonGroup将其分组.
PS: 原创文章, 转载请注明出处, 谢谢!