私は何か基本的なことをしようとしています:あなたはQTreeView
です。第1の深度はフォルダのみであり、第2の深度はファイルのみである。私は各項目の隣にチェックされた状態のチェックボックスを持っています。ファイルはチェックされているかチェックされていないか、フォルダによってはファイルによっては部分的にチェックされることもあります。私はまったく自然だと思います。QTreeViewでcheckedstatus継承を維持する
QStandardItemModel
を使用し、カスタムサブクラスQStandardItem
:DescriptionFileItem
を入力する必要がありました。たぶん、それは悪い考えでした。もし簡単な方法で私を啓発してください。
シグナルとスロットを使用して、ファイルのCheckStateChanged
信号が、その包含フォルダのスロットUpdateCheckedStateOnChildStateChanged
に接続されるようにしました。これは私のDescriptionFileItem
がQObject
から継承することを必要としました(私はQStandardItem
がQObject
から継承しなかったことに驚いた)。 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);
}
}
ありがとう、これは実際にはるかに良いアプローチです。参考のため、以下の最終コードを掲載します。 'case parent-> rowCount():'は問題がありました(スイッチではconstではなく、実はそれは問題です.. 'child(i)')はポインタと親子伝播を返します。私はまだ、私の信号/スロットの接続が以前にはうまくいかなかった理由について少し戸惑っています(しかし、私はデザインが劣っていたことに同意しますが)誰かがコメントをしてくれれば躊躇しないでください。 – Sam
私はセマンティックエラーのカップルがあったことには驚かない - 私は修正するように編集しました。あなたの信号/スロットの接続がうまくいかないのは確かですが、実行時のデバッグ出力は何が間違っているのかを正確に伝えます。また、常にQObject :: connectからの戻り値をチェックする必要があります。そうすれば、接続に問題があるかどうかをすぐに知ることができます。 –
次回はそれをチェックします。ありがとう! – Sam