I have a list of items displayed in a QTableWidget, each one corresponding to a specific folder.
Next to this, I have a QTreeView, with a QFileSystemModel. When I select an item from the QTableWidget, it calls a slot (shown below) in order to display the corresponding folder content.
void MyWidget::diplayFolder(int row)
{
if (auto item = table->item(row, 1))
{
QString correspondingDirectory = item->text();
if (QDir(correspondingDirectory).exists())
{
// treeModel => QFileSystemModel
// tree => QTreeView
treeModel->setRootPath("");
treeModel->setRootPath(correspondingDirectory);
tree->setRootIndex(treeModel->index(correspondingDirectory));
}
else
{
qDebug() << "Reset tree => do not display anything!";
// treeModel->setRootPath("");
// tree->reset();
}
}
}
If the directory does not exist, I don't want to display anything. However, when I try to set an empty root path or reset the view, it show all my computer drives.
How can I reset or clear the QTreeView ?
Had a similar issue. Im not quite sure how i solved it, because it was a long time ago. I think it should work if you set the QTreeview a nullptr as model. So when the QDir exists you set a new QFileSystemModel otherwise you call:
tree->setModel(nullptr);
Hope this helps you.
EDIT:
If your doing it this way the header is deleted too.
Related
Is it possible to have more states for QCheckbox than Qt::Checked and Qt::Unchecked?
I have a QTreeWidget and if an Item is checked I want the parent to show a filled checkbox (some state like "Child checked") and the children should then have a state like "parent checked". If latter would be too complex to achieve I think the normal Qt::Checked would also work fine. But how to achieve the first? Here is my code how I am currently adding items with checkboxes:
QTreeWidgetItem* Options::folderMonitoringCreateTreeCheckbox(QDir *dir, bool state, QTreeWidget *parent)
{
QString text = dir->absolutePath().section('/', -1, -1, QString::SectionSkipEmpty);
QTreeWidgetItem *newItem = new QTreeWidgetItem(parent);
newItem->setText(0,text);
newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable);
newItem->setCheckState(0, Qt::Unchecked);
newItem->setToolTip(0, dir->absolutePath());
return newItem;
}
Here is a Screenshot for what I want to achieve (screenshot taken from MediaMonkey):
Thank you!
I think you are looking for Qt::PartiallyChecked, the description of it says:
The item is partially checked. Items in hierarchical models may be partially checked if some, but not all, of their children are checked.
I have QTreeView with some items and search QLineEdit with connected slot on textEdited signal.
With this code:
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(messagesModel);
proxyModel->setFilterFixedString(text);
ui.treeView->setModel(proxyModel);
text filtering is ok, but when I clicked on QTreeView QStandardItems checkboxes (after proxy model assigned to QTreeView), I have the program crashes in slot, that connected to this QTreeView original model (before proxy was assigned).
What is the right way to processing item checkbox clicks? Need I use new connect/slot to processing model changes, or I can use the same code for original model with some changes? I just need to hide filtered items in QTreeView. In QTreeWidget is hide() method, does QTreeView has something like this, or QSortFilterProxyModel - is what I need? Thx!
UPD crashed in slot, connected to treeView:
auto item = messagesModel->itemFromIndex(index); // item is NULL because proxyModel is set for TreeView now
if(item->whatsThis().isEmpty()) return; // error below
#ifndef QT_NO_WHATSTHIS
inline QString whatsThis() const {
return qvariant_cast<QString>(data(Qt::WhatsThisRole));
}
inline void setWhatsThis(const QString &whatsThis);
#endif
because I set proxyModel to treeView, but messagesModel have whatsThis...
I changed my code with that:
QStandardItem* item;
if(ui.leFilter->text().isEmpty())
item = messagesModel->itemFromIndex(index);
else
item = messagesModel->itemFromIndex(proxyModel->mapToSource(index));
if(item->whatsThis().isEmpty()) return;
and it works. Is that correct way? Proxy model is member of my UI class ... not local.
UPD how can I update source model when checkbox checked in proxyModel?
UPD 2 I have load "original" model for QtreeView and show it. When I edit text in QListEdit, I use proxyModel (code from 1st post). When text edited, I have check checkboxes in QtreeView (now proxyModel is active) and at this step all is ok. But when I do some changes in UI, in QTreeView set the original model and it has no changes that was made for proxyModel. How can I notify and update items in source Model with new data from proxyModel?
UPD3 Yes, source model is also modified ... I have just clear it)
I'm trying to do exclusive checkboxes as a QListView items. I'm using QStandardItemModel as a model with QStandardItem's.
I'm adding items to the list dynamically and set it checkable:
QStandardItem *item = new QStandardItem(treeView->model()->data(index).toString());
item->setCheckable(true);
m_categoriesModel->appendRow(item);
I tried connect all items to QSignalMapper but QStandardItem doesn't have checked(bool) signal (basically it does not have any).
Is there any way to solve the problem?
You can always make it in the way described below. Firstly connect the clicked signal of ListView to the slot which will handle your items click. Secondly inside of the slot you can get the item from QModelIndex and check the state of the item. Below is pseudo code:
For example, in constructor of ListView:
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(_handleItemClicked(QModelIndex)));
Slot of ListView:
void ListView::_handleItemClicked(QModelIndex index)
{
QStandardItem* item = _model->itemFromIndex(index);
if( item->checkState() == Qt::Checked) qDebug() << "Checked!";
}
There actually is a class for exactly doing this: QButtonGroup
It's easy to use:
QButtonGroup *group = new QButtonGroup(this);
group->setExclusive(true);//now only one will be checked at a time
//add all buttons
group->addButton(this->ui->myFirstCheckbox);
//...
... at least for manually added buttons. Of course you can use it for the model too, but it would require you to find all the checkbox elements inside the view...
I'm making a simple file explorer and I ran into some problems with Qt. I want to show the user a tree view of files on his computer, but I also want to be able to select multiple files/directories and do something with them later on (by selecting checkboxes or multiple select using ctrl+left click or shift+left click). I've placed the QTreeView element and set up a model to it (QFileSystemModel). It gives me a good tree view, but I can't modify the headers (column names) or add my own column with checkbox in every row (for example). Qt is new to me, I've searched for few good hours for some tips/solutions, but nothing is working with QFileSystemModel. Is there anything I can do to get this working?
The code is short and simple:
QString lPath = "C:/";
QString rPath = "C:/";
leftTree_model = new QFileSystemModel(this);
rightTree_model = new QFileSystemModel(this);
leftTree_model->setRootPath(lPath);
rightTree_model->setRootPath(rPath);
//i have actually 2 tree views that work the same
ui->leftTree->setModel(leftTree_model); //ui->leftTree is the first tree view
ui->rightTree->setModel(rightTree_model); //the second
Use something of the following:
CheckStateRole to add checkboxes to your model. To do this, you inherit your custom item model (which you're going to use) from the QFileSystemModel, and reimplement the data() method, where you return bool values for CheckStateRole. You will also need the QAbstractItemModel::setData method to handle changes. You can also check the docs for QAbstractItemModel to see how to change header texts (headerData())
Change the selection mode of your view to allow multiple selections
EDIT:
here's a sample code to inherit from the model
class MyFancyModel : public QFileSystemModel
{
public:
MyFancyModel(QObject* pParent = NULL) : QFileSystemModel(pParent)
{
}
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole ) const
{
if (role == Qt::CheckStateRole)
{
// stub value is true
return true; // here you will return real values
// depending on which item is currently checked
}
return QFileSystemModel::data(index, role);
}
};
I have a QTreeWidgetItem added to a QTreeWidget:
QTreeWidgetItem* item = new QTreeWidgetItem(ui->trwPairs);
item->setFlags(item->flags() | Qt::ItemIsEditable);
If the item is edited, I want to do a few checks on the new value:
Pairs::Pairs(QWidget *parent) :
QWidget(parent),
ui(new Ui::Pairs)
{
ui->setupUi(this);
connect(this->ui->trwPairs, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(Validate(QTreeWidgetItem*,int)));
}
void Pairs::Validate(QTreeWidgetItem* item, int column)
{
if (item->text(column).toInt() < 1)
{
QMessageBox::critical(this, "Error", QString("Node ID ") + item->text(column) + " is invalid.");
ui->trwPairs->editItem(item, column);
}
}
Naturally, if it's less than 1, it catches it, and gives me the message box. However, printed to cerr is edit: editing failed and the item is not in edit mode. What am I missing?
Stepping through it in the debugger reveals the following:
In quabstractitemview.cpp line false is returned on line 3953. Somehow it looks like your item is still in editing state and you are trying to edit it again or something.
bool QAbstractItemViewPrivate::shouldEdit(QAbstractItemView::EditTrigger trigger,
const QModelIndex &index) const
{
// ..
if (state == QAbstractItemView::EditingState)
return false;
}
IIRC I had a similar problem with tables with multiple lines per cell. Check out the classes QAbstractItemDelegate views have item delegates which allow you to control which editor is used and how it behaves. I believe by default the QLineEdit is used. Editors like QLineEdit can have validators which control how the data is validated, in your case reject it if the numerical value is < 0. But I think you have to use the model / view classes and implement your own model for that. The Qt documentation for QTreeWidget::setItemWidget(..) says:
This function should only be used to display static content in the place of a tree widget item. If you want to display custom dynamic content or implement a custom editor widget, use QTreeView and subclass QItemDelegate instead.
I am not sure however if there is a simpler way to do this using the widget classes.
The problem could be, that you are setting the flags for your items in a very strange way.
Simply enable both item-selection, and edit:
item->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
I had a similar issue where I was attempting to edit the subsequent column upon receiving the itemChanged signal. Based on Nils' analysis that the item was still in the edit state, I changed the signal connection type to QueuedConnection, which allowed the item to leave the state before re-entering it.
I had a similar problem where I'd get the 'edit: editing failed' error when invoking edit() via a shortcut key. I was passing currentIndex() to edit(), but I wasn't checking that the correct column of the selected row was current. I only had the first column editable, so if I had clicked the row (but in any other column) and then invoked my edit key I'd get the error.
I was able to solve my problem by passing the result of sibling(currentIndex().row(), 0) to edit() instead.