QButtonGroup不允许选择的替代方案? 我写了一个代码> QT< /Cord>——基于C++的应用程序。我有许多按钮,我想相互排斥-一次只能切换一个。我通常使用a来实现这一点——它提供了一种很好的逻辑方法来管理按钮集。当一个人被按下时,先前被按下的那个人就没有被按下,这正是我想要的行为

QButtonGroup不允许选择的替代方案? 我写了一个代码> QT< /Cord>——基于C++的应用程序。我有许多按钮,我想相互排斥-一次只能切换一个。我通常使用a来实现这一点——它提供了一种很好的逻辑方法来管理按钮集。当一个人被按下时,先前被按下的那个人就没有被按下,这正是我想要的行为,qt,radio-button,Qt,Radio Button,然而,这一次,我想让团队完全不受约束。不幸的是,QButtonGroup似乎不允许这样做: 独家:布尔 此属性保存按钮组是否为独占 如果此属性为true,则只能选择组中的一个按钮 随时检查。用户可以单击任何按钮进行检查 它,并且该按钮将替换现有的一个作为选中项 组中的按钮 在独占组中,用户无法取消选中当前选中的组 点击按钮相反,组中的另一个按钮必须是 单击以设置该组的“新建选中”按钮 当然,有很多方法可以解决这个问题。我想知道是否有一个预先制作的替代品来代替QButtonGroup,允许这种行为

然而,这一次,我想让团队完全不受约束。不幸的是,
QButtonGroup
似乎不允许这样做:

独家:布尔

此属性保存按钮组是否为独占

如果此属性为true,则只能选择组中的一个按钮 随时检查。用户可以单击任何按钮进行检查 它,并且该按钮将替换现有的一个作为选中项 组中的按钮

在独占组中,用户无法取消选中当前选中的组 点击按钮相反,组中的另一个按钮必须是 单击以设置该组的“新建选中”按钮

当然,有很多方法可以解决这个问题。我想知道是否有一个预先制作的替代品来代替
QButtonGroup
,允许这种行为,这样1)我就不会重新发明轮子,2)我可以保持惯用的
qt
,使项目管理在未来变得更容易


有什么建议吗?

为了完整起见,我想在这里发布一个可能的解决方案,因为我刚刚解决了这个问题。请注意以下代码对Qt3有效。它也可以用于Qt4和Qt5,因为它不会使用很多东西

所以,我假设我有一个小部件CustomWidget,其中包含按钮(CustomButton类型),并且只有一个按钮可以打开。如果单击小部件中的另一个按钮,则当前打开的按钮将关闭,新单击的按钮将打开

CustomWidget中包含的CustomButtons都以以下方式包含在QButtonGroup中:

QButtonGroup* m_ButtonGroup = new QButtonGroup(this);
m_ButtonGroup->hide();
m_ButtonGroup->insert(Btn1);
m_ButtonGroup->insert(Btn2);
m_ButtonGroup->insert(Btn3);
m_ButtonGroup->setExclusive(true);
void CustomButton ::mousePressEvent(QMouseEvent* a_Event)
{
  if(group() && isToggleButton())
  {
    CustomButton* selectedButton(dynamic_cast<CustomButton*>(group()->selected()));
    if(selectedButton)
    {
      if(selectedButton->name() == name())
      {
        group()->setExclusive(false);
        toggle();
        group()->setExclusive(true);
        return;
      }
    }
  }
  QToolButton::mousePressEvent(a_Event);
}
这里,Btn1、Btn2和Btn3属于CustomButton类型

class CustomButton : public QToolButton
{
    Q_OBJECT

  public:
    CustomButton (QWidget* apo_parent = 0, const char* as_name = 0);
    virtual ~CustomButton ();

  protected:
    virtual void mousePressEvent(QMouseEvent* a_Event);
};
您要特别实现的方法是mousePressEvent。如果其主体以以下方式实施:

QButtonGroup* m_ButtonGroup = new QButtonGroup(this);
m_ButtonGroup->hide();
m_ButtonGroup->insert(Btn1);
m_ButtonGroup->insert(Btn2);
m_ButtonGroup->insert(Btn3);
m_ButtonGroup->setExclusive(true);
void CustomButton ::mousePressEvent(QMouseEvent* a_Event)
{
  if(group() && isToggleButton())
  {
    CustomButton* selectedButton(dynamic_cast<CustomButton*>(group()->selected()));
    if(selectedButton)
    {
      if(selectedButton->name() == name())
      {
        group()->setExclusive(false);
        toggle();
        group()->setExclusive(true);
        return;
      }
    }
  }
  QToolButton::mousePressEvent(a_Event);
}
void CustomButton::mousePressEvent(QMouseEvent*a_事件)
{
if(group()&&istogleButton())
{
CustomButton*selectedButton(动态转换(组()->selected());
如果(已选择按钮)
{
如果(selectedButton->name()==name())
{
group()->setExclusive(false);
切换();
group()->setExclusive(true);
返回;
}
}
}
QToolButton::mousePressEvent(一个事件);
}

然后,该小部件会按照您的意愿运行。

在Qt5中,我使用了与Laurent Michel类似的解决方案,但使用了release事件而不是press事件:

// Allow to uncheck button in exclusive group
void CustomButton::mouseReleaseEvent(QMouseEvent* a_Event) {
    if(group()->checkedId()==group()->id(this)) {
        if(isDown()) group()->setExclusive(false);
    }
    QToolButton::mouseReleaseEvent(a_Event);
    group()->setExclusive(true);
}

另一个类似于前面答案的解决方案,但是使用
nextCheckState()
,这对我来说似乎是更自然的扩展点:

void MyButton::setSemiExclusive(bool value)
{
  mSemiExclusive = value;
}

void MyButton::nextCheckState()
{
  if (mSemiExclusive)
  {
    if (auto g = group())
    {
      auto old = g->exclusive();
      if (g->checkedButton() != this)
        g->setExclusive(true);

      QAbstractButton::nextCheckState();
      g->setExclusive(old);
      return;
    }
  }

  QAbstractButton::nextCheckState();
}

这取决于关联的
QButtonGroup
已将
exclusive
设置为false。

如果不想扩展button类,也可以通过使用信号(Qt5,Python)来实现:


我的解决方案是派生QButtonGroup,将其设置为非独占内部,并自行管理状态

class myQButtonGroup : public QButtonGroup
{
    Q_OBJECT

public:
    explicit myQButtonGroup(QObject *parent = Q_NULLPTR) : QButtonGroup(parent) {
        _bExclusive = true;
        QButtonGroup::setExclusive(false);
        connect(this, SIGNAL(buttonClicked(QAbstractButton *)), SLOT(buttonClicked(QAbstractButton *)));
    }

    void setExclusive(bool bExclusive) { _bExclusive = bExclusive; }
    bool exclusive() const { return _bExclusive; }

protected slots:
    void buttonClicked(QAbstractButton *button) {
        if (_bExclusive) {
            // just uncheck all other buttons regardless of the state of the clicked button
            QList<QAbstractButton *> buttonlist = buttons();
            for (auto iBtn = buttonlist.begin(); iBtn != buttonlist.end(); ++iBtn) {
                QAbstractButton *pBtn = *iBtn;
                if (pBtn && pBtn != button && pBtn->isCheckable()) pBtn->setChecked(false);
            }
        }
    }

protected:
    bool _bExclusive;
};
类myQButtonGroup:public QButtonGroup
{
Q_对象
公众:
显式myQButtonGroup(QObject*parent=Q_NULLPTR):QButtonGroup(parent){
_beexclusive=true;
QButtonGroup::setExclusive(false);
连接(此,信号(按钮点击(QAbstractButton*)),插槽(按钮点击(QAbstractButton*));
}
void setExclusive(bool beexclusive){{u beexclusive=beexclusive;}
bool exclusive()常量{return\u beexclusive;}
受保护插槽:
无效按钮单击(QAbstractButton*按钮){
如果(排除){
//只需取消选中所有其他按钮,而不管单击按钮的状态如何
QList buttonlist=按钮();
对于(auto-iBtn=buttonlist.begin();iBtn!=buttonlist.end();++iBtn){
QAbstractButton*pBtn=*iBtn;
如果(pBtn&&pBtn!=按钮&pBtn->ischeckeble())pBtn->setChecked(false);
}
}
}
受保护的:
布尔(bool)除外;;
};

AFAIK没有。特别是在这种情况下,获得功能所需的代码非常少。如果希望在事件过滤器/鼠标按下事件中全部取消选择按钮组,并且发送者对象与当前按下的按钮相同,则只需关闭按钮组的独占属性。三年后,但我今天注意到,当使用autoexclusive而不是QButtonGroup和Qt4.8.6时,我可以取消选择所选的单选按钮。不确定这是否是一个bug。