Как сделать кликабельные CheckBox-ы в QTreeView с моделью QFileSystemModel
Суть вот в чем. Нужно сделать простой обзорник директории относительно места расположения файла, с выводом только файлов SQL. С этим справился. Но есть отдельный момент: необходимо иметь возможность выбирать эти файлы посредством проставки галки в checkbox-е. Также должна быть возможность выбора группы файликов, выбором галкой папки, и отсутствия галки, если в папке файлов нема... Запнулся на CheckBox-ах. Вот в упор не могу въехать. Даже пробовал дочерний класс лепить, не вышло ничерта (не выкладываю, ибо чушь).
Для ЛЛ: топики Модель для QListView с чекбоксами и текстом
и
Изучил. Не понял. Мне бы код сразу рабочий, без обобщающих вставок. Ибо я человек туповатый и иносказания понимаю плохо...
Мой "код" (по сути заготовка):
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QFileSystemModel *model = new QFileSystemModel;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
model->setRootPath(QDir::currentPath());
model->setNameFilters(QStringList () << "*.sql");
model->setNameFilterDisables(false);
model->setFilter(QDir :: Files | QDir :: AllDirs | QDir :: NoDotAndDotDot);
ui->setupUi(this);
ui->treeView->setModel(model);
for (int i = 1; i < model->columnCount(); ++i)
ui->treeView->hideColumn(i);
ui->treeView->setRootIndex(model->index(QDir::currentPath()));
}
MainWindow::~MainWindow()
{
delete ui;
}
В ui-шке только QTreeView и все.
Ответы (2 шт):
Да в целом направление было правильное, и я бы все же старался разобраться в том что люди пишут ;) Вам надо реализовать свою модель с наследованием от QFileSystemModel и просто добавить в нее реализацию чекбоксов
.h
class MyFileSystemModel: public QFileSystemModel
{
Q_OBJECT
public:
MyFileSystemModel();
virtual bool setData( const QModelIndex& index, const QVariant& value, int role );
virtual Qt::ItemFlags flags( const QModelIndex & index ) const;
virtual QVariant data( const QModelIndex &index, int role )const;
signals:
void itemChecked(const QModelIndex&);
protected slots:
void onItemChecked(const QModelIndex& index);
private:
mutable QMap <qint64, Qt::CheckState> checkedItems;
};
.cpp
MyFileSystemModel::MyFileSystemModel()
{
connect(this, SIGNAL(itemChecked(const QModelIndex&)), SLOT(onItemChecked(const QModelIndex&)));
}
bool MyFileSystemModel::setData( const QModelIndex& index, const QVariant& value, int role ) {
if( role == Qt::CheckStateRole && index.column() == 0 ) {
checkedItems[ index.internalId() ] = static_cast<Qt::CheckState>( value.toInt() );
emit itemChecked(index);
emit dataChanged(index, index.sibling(0,0));
return true;
}
return QFileSystemModel::setData(index, value, role);
}
Qt::ItemFlags MyFileSystemModel::flags( const QModelIndex & index ) const {
return QFileSystemModel::flags( index ) | Qt::ItemIsUserCheckable;
}
QVariant MyFileSystemModel::data( const QModelIndex& index, int role ) const {
if( role == Qt::CheckStateRole && index.column()==0 ) {
return QVariant( checkedItems[ index.internalId() ] );
}
return QFileSystemModel::data( index, role );
}
void MyFileSystemModel::onItemChecked(const QModelIndex &index)
{
Qt::CheckState state = checkedItems [index.internalId()];
fetchMore(index);
if ( state == Qt::Checked || state == Qt::Unchecked ) {
for ( int i = 0; i < rowCount(index); i++ ) {
QModelIndex child = index.child(i, 0);
if (checkedItems [child.internalId()] != state )
setData(child, state, Qt::CheckStateRole);
}
}
QModelIndex parent = index.parent();
if (parent.isValid()) {
state = checkedItems [parent.child(0, 0).internalId()];
if (state == Qt::PartiallyChecked)
checkedItems[parent.internalId()] = state;
else {
int i = 1;
while (i < rowCount(parent) && checkedItems [parent.child(i, 0).internalId()] == state)
i++;
if (i != rowCount(index))
state = Qt::PartiallyChecked;
checkedItems [parent.internalId()] = state;
}
}
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//.......
MyFileSystemModel *model = new MyFileSystemModel;
model->setRootPath(QDir::currentPath());
model->setNameFilters(QStringList () << "*.*");
model->setNameFilterDisables(false);
model->setFilter(QDir :: Files | QDir :: AllDirs | QDir :: NoDotAndDotDot);
ui->treeView->setModel(model);
ui->treeView->setRootIndex(model->index(QDir::currentPath()));
}
Чутка допилил предыдущий ответ. Чисто, чтобы было:
void MyFileSystemModel::onItemChecked(const QModelIndex &index)
{
Qt::CheckState state = checkedItems [index.internalId()];
fetchMore(index);
if ( state == Qt::Checked || state == Qt::Unchecked ) {
for ( int i = 0; i < rowCount(index); i++ )
{
QModelIndex child = index.child(i, 0);
if (checkedItems [child.internalId()] != state )
setData(child, state, Qt::CheckStateRole);
}
}
int ch = 0;
QModelIndex parent = index.parent();
bool part = false;
for ( int i = 0; i < rowCount(parent); i++ )
{
if (checkedItems [parent.child(i, 0).internalId()] != Qt::Unchecked) ch++;
if (checkedItems [parent.child(i, 0).internalId()] == Qt::PartiallyChecked) part = true;
}
if (part || (ch>0 && ch<rowCount(parent)))
{
setData(parent, Qt::PartiallyChecked, Qt::CheckStateRole);
}
else if (ch==0)
{
if (checkedItems [parent.internalId()] != Qt::Unchecked)
setData(parent, Qt::Unchecked, Qt::CheckStateRole);
}
else if (ch==rowCount(parent))
{
if (checkedItems [parent.internalId()] != Qt::Checked)
setData(parent, Qt::Checked, Qt::CheckStateRole);
}
}