QStyledItemDelegate how to force close the editor?
-
I have an QTreeView and when doubleclicking the editor opens.
I want it so when i double click on a certain point of my QTreeview that the editor is closed directly for the index where the index was created.In short im searching for a way to prevent opening the editor when double clicking on a certain position of my item. But still the editor should open when clicking elsewhere.
How could this be done? Thanks.
Doubleclicking the checkbox currently is triggering the createEditor of my delegate i only want the editor to be created when double clicking above the lineEdit. Here is my code:delegate.cpp:
#include "ViewLayerItemDelegate.h" #include <QStyledItemDelegate> #include <QPainter> #include <QApplication> #include <QItemSelectionModel> #include <QMouseEvent> #include "ViewLayerList.h" #include <QTimer> ViewLayerItemDelegate::ViewLayerItemDelegate(QObject *parent) : QStyledItemDelegate{parent} { } QWidget *ViewLayerItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { qDebug() << "Editor created"; LineEditCheckBoxWidget *editor = new LineEditCheckBoxWidget(parent); // Verbinden Sie das textChanged() Signal des LineEdits mit Ihrem Slot connect(editor->lineEdit, &QLineEdit::textChanged, this, &ViewLayerItemDelegate::onLineEditTextChanged); //Ein Timer um direkt die Editierung des LineEdit zu ermöglichen QTimer::singleShot(0, editor->lineEdit, SLOT(setFocus())); return editor; } void ViewLayerItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor); // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString(); bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool(); widget->lineEdit->setText(lineEditvalue); widget->checkBox->setChecked(checkBoxValue); widget->setFocus(); widget->lineEdit->setFocus(Qt::MouseFocusReason); // Editor aktivieren widget->lineEdit->setStyleSheet("background: white"); widget->iconLabel->setAttribute(Qt::WA_TranslucentBackground); //widget->setStyleSheet("background: white"); // Setzen Sie den bearbeiteten Index const_cast<ViewLayerItemDelegate*>(this)->setCurrentlyEditedIndex(index); } void ViewLayerItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor); // Speichern Sie die Werte der SpinBox und CheckBox im Modell QString lineEditvalue = widget->lineEdit->text(); bool checkBoxValue = widget->checkBox->isChecked(); model->setData(index, lineEditvalue, Qt::EditRole); model->setData(index, checkBoxValue ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); qDebug() << "Model data set"; // Setzen Sie den bearbeiteten Index zurück const_cast<ViewLayerItemDelegate*>(this)->setCurrentlyEditedIndex(QModelIndex()); } void ViewLayerItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry(option.rect); } QSize ViewLayerItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = QStyledItemDelegate::sizeHint(option, index); size.setHeight(40); // Setzen Sie hier die gewünschte Höhe // Ändern Sie die Einrückung basierend auf dem Level des Items (z.B., hier um 20 Pixel). int indentationLevel = index.column(); // Hier als Beispiel die Einrückung basierend auf der Spalte. size.rwidth() -= indentationLevel * 40; // Die Einrückung um 20 Pixel erhöhen. return size; } void ViewLayerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); // Überprüfen Sie, ob der aktuelle Index bearbeitet wird if (index == currentlyEditedIndex) { return; } // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString(); bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool(); // Laden Sie das Icon und skalieren Sie es QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Berechnen Sie die Position für das Icon int centerY = option.rect.top() + option.rect.height() / 2; int iconY = centerY - scaledPixmap.height() / 2; QPoint iconPos = QPoint(option.rect.left() + 10, iconY); // Zeichnen Sie das Pixmap mit dem QPainter painter->drawPixmap(iconPos, scaledPixmap); // Berechnen Sie die Position und Größe für das LineEdit QRect lineEditRect = option.rect; lineEditRect.setLeft(iconPos.x() + scaledPixmap.width() + 10); // Adjust as needed lineEditRect.setRight(option.rect.right() - 10-35); // Adjust as needed // Erstellen Sie ein QStyleOptionFrame für das LineEdit QStyleOptionFrame lineEditOption; lineEditOption.lineWidth = 1; // Setzen Sie die Liniendicke auf 1 lineEditOption.rect = lineEditRect; // Zeichnen Sie das LineEdit QApplication::style()->drawControl(QStyle::CE_ShapedFrame, &lineEditOption, painter); // Überprüfen Sie, ob der Text leer ist und zeichnen Sie den Platzhaltertext // Zeichnen Sie den Text des LineEdits, considering truncation // Überprüfen Sie, ob der Text leer ist und zeichnen Sie den Platzhaltertext if (lineEditvalue.isEmpty()) { painter->drawText(lineEditOption.rect.adjusted(2, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, "<Empty>"); } else { // Hier wird die maximale Breite des Texts festgelegt, bevor er abgeschnitten wird int maxTextWidth = lineEditRect.width(); // Berechnen Sie die Größe des Texts QFontMetrics fm(painter->font()); QString displayedText = fm.elidedText(lineEditvalue, Qt::ElideRight, maxTextWidth - 10); painter->drawText(lineEditOption.rect.adjusted(2, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, displayedText); } // Berechnen Sie die Position und Größe für die CheckBox QRect checkBoxRect = option.rect; checkBoxRect.setLeft(lineEditRect.right() +35- 22); // Adjust as needed checkBoxRect.setRight(option.rect.right() - 10); // Adjust as needed // Erstellen Sie ein QStyleOptionButton für die CheckBox QStyleOptionButton checkBoxOption; checkBoxOption.state = checkBoxValue ? QStyle::State_On : QStyle::State_Off; checkBoxOption.rect = checkBoxRect; /* //CODE NUR ZUM VISUELLEN DEBUGGEN DER BEREICHE: // Zeichnen Sie ein rotes Rechteck um das LineEdit QPen redPen(Qt::red); painter->setPen(redPen); painter->drawRect(lineEditRect); // Zeichnen Sie ein rotes Rechteck um das LineEdit QPen bluePen(Qt::blue); painter->setPen(bluePen); painter->drawRect(checkBoxRect); */ // Zeichnen Sie die CheckBox QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxOption, painter); } bool ViewLayerItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if(event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); if (const QTreeView* view = qobject_cast<const QTreeView*>(option.widget)) { const QRect itemRect = view->visualRect(index); ClickPosition = mouseEvent->position() - itemRect.topLeft(); // press position in item's coords //QRect itemRect = option.rect; qDebug() << "Click position: " << ClickPosition; qDebug() << "Item Rect: " <<itemRect; if(ClickPosition.x() >= itemRect.width()-35 && ClickPosition.x() <= itemRect.width()-20) { // Invert the state of the checkbox bool value = index.data(Qt::CheckStateRole).toBool(); model->setData(index, !value, Qt::CheckStateRole); emit SendCloseEditorToViewLayerList(index); } } } // Standardverhalten beibehalten für andere Ereignisse return QStyledItemDelegate::editorEvent(event, model, option, index); } // Slot-Implementierung void ViewLayerItemDelegate::onLineEditTextChanged(const QString &text) { // Hier können Sie die gewünschte Aktion ausführen, wenn der Text im LineEdit bearbeitet wird qDebug() << "LineEdit text changed to:" << text; } void LineEditCheckBoxWidget::mousePressEvent(QMouseEvent *event) { qDebug() << "Test clicked"; this->lineEdit->setStyleSheet("background: transparent;"); QWidget::mousePressEvent(event); } void ViewLayerItemDelegate::setCurrentlyEditedIndex(const QModelIndex &index) { currentlyEditedIndex = index; }
-
Christian Ehrlicher Lifetime Qt Championreplied to StudentScripter on last edited by Christian Ehrlicher
I don't see a way to achieve this in the delegate - I would override QAIV::edit() and add the appropriate checks in there.
-
@Christian-Ehrlicher i have overwritten the edit event but how do i prevent or close the createEditor of my delegate? I tried leaving out the call for the edit event in this case, but sadly this way my delegates editevent logic isnt working anymore when clicking on this area.
bool ViewLayerList::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) { if (event && (event->type() == QEvent::MouseButtonPress)) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); QPoint clickPosition = mouseEvent->pos(); qDebug() << "EVENT CLICKPOS: " << clickPosition; QRect itemRect = this->visualRect(index); qDebug() << "Item size: " << itemRect.size(); if(clickPosition.x() >= itemRect.width()-30 && clickPosition.x() <= itemRect.width()) { qDebug() << "Kein Editor erstellt"; }else if(clickPosition.x() < itemRect.width()-30){ return QTreeView::edit(index, trigger, event); } } }
Alternatively i would like to close the editor here: (Have a look at the comment)
#include "ViewLayerItemDelegate.h" #include <QStyledItemDelegate> #include <QPainter> #include <QApplication> #include <QItemSelectionModel> #include <QMouseEvent> #include "ViewLayerList.h" #include <QTimer> ViewLayerItemDelegate::ViewLayerItemDelegate(QObject *parent) : QStyledItemDelegate{parent} { } QWidget *ViewLayerItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { qDebug() << "Editor created"; LineEditCheckBoxWidget *editor = new LineEditCheckBoxWidget(parent); // Verbinden Sie das textChanged() Signal des LineEdits mit Ihrem Slot connect(editor->lineEdit, &QLineEdit::textChanged, this, &ViewLayerItemDelegate::onLineEditTextChanged); //Ein Timer um direkt die Editierung des LineEdit zu ermöglichen QTimer::singleShot(0, editor->lineEdit, SLOT(setFocus())); return editor; } void ViewLayerItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor); // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString(); bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool(); widget->lineEdit->setText(lineEditvalue); widget->checkBox->setChecked(checkBoxValue); //widget->setFocus(); //widget->lineEdit->setFocus(Qt::MouseFocusReason); // Editor aktivieren widget->lineEdit->setStyleSheet("background: white"); widget->iconLabel->setAttribute(Qt::WA_TranslucentBackground); //widget->setStyleSheet("background: white"); // Setzen Sie den bearbeiteten Index const_cast<ViewLayerItemDelegate*>(this)->setCurrentlyEditedIndex(index); } void ViewLayerItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor); // Speichern Sie die Werte der SpinBox und CheckBox im Modell QString lineEditvalue = widget->lineEdit->text(); bool checkBoxValue = widget->checkBox->isChecked(); model->setData(index, lineEditvalue, Qt::EditRole); model->setData(index, checkBoxValue ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); qDebug() << "Model data set"; // Setzen Sie den bearbeiteten Index zurück const_cast<ViewLayerItemDelegate*>(this)->setCurrentlyEditedIndex(QModelIndex()); } void ViewLayerItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry(option.rect); } QSize ViewLayerItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = QStyledItemDelegate::sizeHint(option, index); size.setHeight(40); // Setzen Sie hier die gewünschte Höhe return size; } void ViewLayerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); // Überprüfen Sie, ob der aktuelle Index bearbeitet wird if (index == currentlyEditedIndex) { return; } // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString(); bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool(); // Laden Sie das Icon und skalieren Sie es QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Berechnen Sie die Position für das Icon int centerY = option.rect.top() + option.rect.height() / 2; int iconY = centerY - scaledPixmap.height() / 2; QPoint iconPos = QPoint(option.rect.left() + 10, iconY); // Zeichnen Sie das Pixmap mit dem QPainter painter->drawPixmap(iconPos, scaledPixmap); // Berechnen Sie die Position und Größe für das LineEdit QRect lineEditRect = option.rect; lineEditRect.setLeft(iconPos.x() + scaledPixmap.width() + 10); // Adjust as needed lineEditRect.setRight(option.rect.right() - 10-35); // Adjust as needed // Erstellen Sie ein QStyleOptionFrame für das LineEdit QStyleOptionFrame lineEditOption; lineEditOption.lineWidth = 1; // Setzen Sie die Liniendicke auf 1 lineEditOption.rect = lineEditRect; // Zeichnen Sie das LineEdit QApplication::style()->drawControl(QStyle::CE_ShapedFrame, &lineEditOption, painter); // Überprüfen Sie, ob der Text leer ist und zeichnen Sie den Platzhaltertext // Zeichnen Sie den Text des LineEdits, considering truncation // Überprüfen Sie, ob der Text leer ist und zeichnen Sie den Platzhaltertext if (lineEditvalue.isEmpty()) { painter->drawText(lineEditOption.rect.adjusted(2, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, "<Empty>"); } else { // Hier wird die maximale Breite des Texts festgelegt, bevor er abgeschnitten wird int maxTextWidth = lineEditRect.width(); // Berechnen Sie die Größe des Texts QFontMetrics fm(painter->font()); QString displayedText = fm.elidedText(lineEditvalue, Qt::ElideRight, maxTextWidth - 10); painter->drawText(lineEditOption.rect.adjusted(2, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, displayedText); } // Berechnen Sie die Position und Größe für die CheckBox QRect checkBoxRect = option.rect; checkBoxRect.setLeft(lineEditRect.right() +35- 22); // Adjust as needed checkBoxRect.setRight(option.rect.right() - 10); // Adjust as needed // Erstellen Sie ein QStyleOptionButton für die CheckBox QStyleOptionButton checkBoxOption; checkBoxOption.state = checkBoxValue ? QStyle::State_On : QStyle::State_Off; checkBoxOption.rect = checkBoxRect; /* //CODE NUR ZUM VISUELLEN DEBUGGEN DER BEREICHE: // Zeichnen Sie ein rotes Rechteck um das LineEdit QPen redPen(Qt::red); painter->setPen(redPen); painter->drawRect(lineEditRect); // Zeichnen Sie ein rotes Rechteck um das LineEdit QPen bluePen(Qt::blue); painter->setPen(bluePen); painter->drawRect(checkBoxRect); */ // Zeichnen Sie die CheckBox QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxOption, painter); } bool ViewLayerItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if(event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); if (const QTreeView* view = qobject_cast<const QTreeView*>(option.widget)) { const QRect itemRect = view->visualRect(index); ClickPosition = mouseEvent->position() - itemRect.topLeft(); // press position in item's coords //QRect itemRect = option.rect; qDebug() << "Click position: " << ClickPosition; qDebug() << "Item Rect: " <<itemRect; if(ClickPosition.x() >= itemRect.width()-35 && ClickPosition.x() <= itemRect.width()-20) { // Invert the state of the checkbox bool value = index.data(Qt::CheckStateRole).toBool(); model->setData(index, !value, Qt::CheckStateRole); //CLOSE THE EDITOR HERE!!!!!!!!!!!!!!!!!!! } } } // Standardverhalten beibehalten für andere Ereignisse return QStyledItemDelegate::editorEvent(event, model, option, index); }
-
@StudentScripter said in QStyledItemDelegate how to force close the editor?:
but sadly this way my delegates editevent logic isnt working anymore when clicking on this area.
What does this mean?
clickPosition is relative to the view, not relative to the current cell (how should it be?).