2

私は何か基本的なことをしようとしています:あなたはQTreeViewです。第1の深度はフォルダのみであり、第2の深度はファイルのみである。私は各項目の隣にチェックされた状態のチェックボックスを持っています。ファイルはチェックされているかチェックされていないか、フォルダによってはファイルによっては部分的にチェックされることもあります。私はまったく自然だと思います。QTreeViewでcheckedstatus継承を維持する

QStandardItemModelを使用し、カスタムサブクラスQStandardItemDescriptionFileItemを入力する必要がありました。たぶん、それは悪い考えでした。もし簡単な方法で私を啓発してください。

シグナルとスロットを使用して、ファイルのCheckStateChanged信号が、その包含フォルダのスロットUpdateCheckedStateOnChildStateChangedに接続されるようにしました。これは私のDescriptionFileItemQObjectから継承することを必要としました(私はQStandardItemQObjectから継承しなかったことに驚いた)。 emitDataChanged()は、私のモデルのdataChanged()信号をトリガーしていないようです...

モデルのdataChanged信号を直接使用すると、どちらも動作しませんでした。コールは保護されていますので、サブクラス化しないと使用できません(誰かがそれを正しく手助けできなければ、私の次の動きだと思います)。

現時点では、信号 - >スロット接続が動作しません。理由はわかりません。コンパイルとリンクの作業は大丈夫です。ここにコードがあります。あなたは私の間違いを簡単に見つけます。私はいくつかのコメントされた行を残しているので、以前の試みで間違ったことを見ることができます。あなたのご意見ありがとうございます!

#ifndef DESCRIPTIONFILEITEM_H 
#define DESCRIPTIONFILEITEM_H 

#include <QStandardItem> 
#include <Qt> 

class DescriptionFileItem : public QObject, public QStandardItem 
{ 
    Q_OBJECT 

public: 
    explicit DescriptionFileItem(const QString & text, bool isFileName=false, QObject* parent = 0); 

    void setData (const QVariant & value, int role = Qt::UserRole + 1); 

    QVariant data(int role = Qt::UserRole + 1) const; 

    QString text; 
    Qt::CheckState checkedState; 
    bool isFileName; 

signals: 
    void CheckStateChanged(); 

public slots: 
    void UpdateCheckedStateOnChildStateChanged(); 

}; 

#endif // DESCRIPTIONFILEITEM_H 

対応の.cpp:

#include "DescriptionFileItem.h" 

DescriptionFileItem::DescriptionFileItem(const QString & text, bool isFileName, QObject* parent): 
    QObject(parent),QStandardItem(text) 
{ 
    this->isFileName = isFileName; 
    checkedState = Qt::Checked; 
} 

void DescriptionFileItem::setData (const QVariant & value, int role){ 

    if(role == Qt::CheckStateRole){ 
     Qt::CheckState newCheckState = (Qt::CheckState)value.toInt(); 
     checkedState = newCheckState; 
     if(isFileName){ 
      if(newCheckState == Qt::Unchecked || newCheckState == Qt::Checked){ 
       for(int i = 0; i<rowCount(); i++){ 
        DescriptionFileItem* child = (DescriptionFileItem*)QStandardItem::child(i); 
        QModelIndex childIndex = child->index(); 
        child->model()->setData(childIndex,newCheckState, Qt::CheckStateRole); 
        //child->setCheckState(newCheckState); 
        //child->setData(newCheckState,Qt::CheckStateRole); 
       } 
       /*if(rowCount()>1){ 
        emit this->model()->dataChanged(this->child(0)->index(),this->child(rowCount()-1)->index()); 
       }else{ 
        emit this->model()->dataChanged(this->child(0)->index(),this->child(0)->index()); 
       }*/ 
      } 
     }else{ 
      emit CheckStateChanged(); 
     } 
     //emit this->model()->dataChanged(this->index(),this->index()); 
    }else{ 
     QStandardItem::setData(value,role); 
    } 
} 

QVariant DescriptionFileItem::data(int role) const{ 
    if (role == Qt::CheckStateRole){ 
      return checkedState; 
    } 
    return QStandardItem::data(role); 
} 

void DescriptionFileItem::UpdateCheckedStateOnChildStateChanged() 
{ 
    Qt::CheckState min = Qt::Checked; 
    Qt::CheckState max = Qt::Unchecked; 
    Qt::CheckState childState; 
    for(int i = 0; i<rowCount(); i++){ 
     DescriptionFileItem* child = (DescriptionFileItem*)QStandardItem::child(i); 
     childState = (Qt::CheckState) child->data(Qt::CheckStateRole).toInt(); 
     min = min>childState ? childState: min; 
     max = max<childState ? childState: max; 
    } 
    if(min >= max) 
     setData(min, Qt::CheckStateRole); 
    else 
     setData(Qt::PartiallyChecked, Qt::CheckStateRole); 
} 

、接続/木の構築:

 DescriptionFileItem* descFileStdItem = new DescriptionFileItem(descriptionFileName, true); 
     descFileStdItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsTristate); 
     descriptionFileSIModel.appendRow(descFileStdItem); 
     typedef pair<string,int> indexType; 
     foreach(indexType index,dataFile->indexes){ 
      DescriptionFileItem* key_xItem = new DescriptionFileItem(index.first.c_str()); 
      descFileStdItem->appendRow(key_xItem); 
      key_xItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled); 
      QObject::connect(key_xItem,SIGNAL(CheckStateChanged()),descFileStdItem,SLOT(UpdateCheckedStateOnModelDataChanged())); 
     } 

EDIT:最終的な答え、STUのおかげ

(下記参照)
void DataLoadWidget::ModelItemChanged(QStandardItem *item) 
{ 
    QStandardItem* parent = item->parent(); 
    if(parent == 0){ 
     //folder state changed--> update children if not partially selected 
     Qt::CheckState newState = item->checkState(); 
     if(newState != Qt::PartiallyChecked){ 
      for (int i = 0; i < item->rowCount(); i++) 
      { 
       item->child(i)->setCheckState(newState); 
      } 
     } 
    } 
    else{//child item changed--> count parent's children that are checked 
     int checkCount = 0; 
     for (int i = 0; i < parent->rowCount(); i++) 
     { 
      if (parent->child(i)->checkState() == Qt::Checked) 
       checkCount++; 
     } 

     if(checkCount == 0) 
      parent->setCheckState(Qt::Unchecked); 
     else if (checkCount == parent->rowCount()) 
      parent->setCheckState(Qt::Checked); 
     else 
      parent->setCheckState(Qt::PartiallyChecked); 
    } 
} 

答えて

1

あなたの質問を誤解していない限り、あなたの解決策は大規模に複雑すぎるようです。これは、デフォルトのQStandardItemModel実装で簡単に行うことができます。

このようなことはどうですか(エラー処理が省略されています)?

QObject::connect(model, SIGNAL(itemChanged(QStandardItem*)), someObject, SLOT(modelItemChanged(QStandardItem*))); 

そして、シグナルハンドラで:

void modelItemChanged(QStandardItem* item) 
{ 
    QStandardItem* parent = item->parent(); 
    int checkCount = 0; 
    int rowCount = parent->rowCount(); 

    for (int i = 0; i < rowCount; i++) 
    { 
     if (parent->child(i)->checkState() == Qt::Checked) 
      checkCount++; 
    } 

    switch (checkCount) 
    { 
    case 0: 
     parent->setCheckState(Qt::Unchecked); 
     break; 
    case rowCount: 
     parent->setCheckState(Qt::Checked); 
     break; 
    default: 
     parent->setCheckState(Qt::PartiallyChecked); 
    } 
} 

これは決して最適であるが、それはあなたの目的には十分かもしれません。

+0

ありがとう、これは実際にはるかに良いアプローチです。参考のため、以下の最終コードを掲載します。 'case parent-> rowCount():'は問題がありました(スイッチではconstではなく、実はそれは問題です.. 'child(i)')はポインタと親子伝播を返します。私はまだ、私の信号/スロットの接続が以前にはうまくいかなかった理由について少し戸惑っています(しかし、私はデザインが劣っていたことに同意しますが)誰かがコメントをしてくれれば躊躇しないでください。 – Sam

+0

私はセマンティックエラーのカップルがあったことには驚かない - 私は修正するように編集しました。あなたの信号/スロットの接続がうまくいかないのは確かですが、実行時のデバッグ出力は何が間違っているのかを正確に伝えます。また、常にQObject :: connectからの戻り値をチェックする必要があります。そうすれば、接続に問題があるかどうかをすぐに知ることができます。 –

+0

次回はそれをチェックします。ありがとう! – Sam

関連する問題