Checkbox in a header cell in QTableView

后端 未结 3 806
礼貌的吻别
礼貌的吻别 2020-12-16 20:57

I want to have a simple column header with a checkbox that selects/ deselects all rows in a QTableView. Clicking the check box in the header causes either to select or desel

3条回答
  •  时光取名叫无心
    2020-12-16 21:06

    I am surprised such a hacky solution is recommend and used.

    First: The check state should be stored in the model. All the tools are already there.

    bool MyModel::setHeaderData(int index, Qt::Orientation orient, const QVariant& val, int role)
    {
      if(Qt::Vertical != orient)
        return Base::setHeaderData(index, orient, val, role);
    
      storeCheckState(index, val);
      emit headerDataChanged(orient, index, index);
      return true;
    }
    
    QVariant MyModel::headerData(int index, Qt::Orientation o, int role) const
    {
        if(Qt::Vertical != orient)
          return Base::headerData(index, o, role);
    
        switch(role)
        {
        ...
        case Qt::CheckStateRole:
          return fetchCheckState(index);
        }
    
      return Base::headerData(index, o, role);
    }
    

    Second: We toggle checked state simply by handling the click signal on the header.

    connect(header, &QHeaderView::sectionClicked, receiver
            , [receiver](int sec)
    {
      const auto index = logicalIndex(sec);
      model()->setHeaderData(index
                             , Qt::Vertical
                             , Qt::CheckState(model()->headerData(index, Qt::Vertical, Qt::CheckStateRole).toUInt()) != Qt::Checked ? Qt::Checked : Qt::Unchecked
                             , Qt::CheckStateRole);
    });
    

    Third: At this point we have fully functional checking behavior, only part missing is the visualization. The smartest way to go is to again use the model, taking advantage of the Qt::DecorationRole. Here is a dummy implementation:

    QVariant MyModel::headerData(int index, Qt::Orientation o, int role) const
    {
        if(Qt::Vertical != orient)
          return Base::headerData(index, o, role);
    
        switch(role)
        {
          case Qt::DecorationRole:
          {
            QPixmap p{12,12};
            p.fill(Qt::CheckState(headerData(index, o, Qt::CheckStateRole).toUInt()) ? Qt::green : Qt::red);
            return p;
           }
           break;
        ...
        }
    
      return Base::headerData(index, o, role);
    }
    

    Of course, one can draw a real checkbox there using the styled drawing.

    Notice, this solution does not require sub-classing and custom widgets.

    Also, the check state is decoupled from the view/UI. The only downside is fact the visuals are handled by the model, but this is optional - any way can be used to draw the check state, the one from the alternative answers included.

提交回复
热议问题