Photoshop layer like QTreeWidget Qt6 C++ - Help needed.
-
Hello,
I wanted to create a photoshop layer like system, but as im still learning im kinda struggeling. I first tried using a delegate but as i was stuck i switched to declaring the controls in the item directly.
What i want:
One layer should consist of [Icon, LineEdit, Checkbox]. Each layer should have a height of 40px, should highlight on hover over and should be groupable (be able to be put as child widget of another, just like with layers in photoshop). Here is an picture of how such layers should look like:So far i created a custom QWidget subclass which i set for my QTreeWidgetItem to achieve this layout. However hovering does not work good and the custom controls get lost once dragging my custom widget below another QTreeWidgetItem (grouping).
Here is my cutomwidget.cpp:
#include "ViewLayerCustomItem.h" #include <QHBoxLayout> #include <QLabel> #include <QLineEdit> #include <QCheckBox> #include <QPixmap> #include <QPalette> #include <QStyle> #include <QApplication> ViewLayerCustomItem::ViewLayerCustomItem(QWidget *parent) : QWidget(parent) { // Erstellen Sie ein Layout für das benutzerdefinierte Widget. QHBoxLayout* layout = new QHBoxLayout(); QLabel* iconLabel = new QLabel(); iconLabel->setPixmap(QPixmap("://resource/quick.png").scaled(32, 32, Qt::KeepAspectRatio)); layout->addWidget(iconLabel); QLineEdit* lineEdit = new QLineEdit(); layout->addWidget(lineEdit); lineEdit->setReadOnly(false); lineEdit->setFrame(false); lineEdit->setPlaceholderText("<Empty>"); QCheckBox* checkBox = new QCheckBox(""); layout->addWidget(checkBox); setLayout(layout); } void ViewLayerCustomItem::enterEvent(QEnterEvent *event) { QString hoverStyle = "background-color: #E6F7FF; color: #000000;"; setStyleSheet(hoverStyle); } void ViewLayerCustomItem::leaveEvent(QEvent *event) { setStyleSheet(""); }
treewidget.cpp:
#include "ViewLayerList.h" #include <QHBoxLayout> #include <QCheckBox> #include <QLabel> #include <QMouseEvent> #include "SignalManager.h" #include <QHeaderView> #include <QPushButton> #include "ViewLayerCustomItem.h" ViewLayerList::ViewLayerList(CustomGraphicsScene *scene, QWidget *parent) : QTreeWidget{parent}, scene_durchgereicht(scene) { this->setHeaderHidden(true); this->setRootIsDecorated(true); this->setFocusPolicy(Qt::NoFocus); QTreeWidgetItem* item = new QTreeWidgetItem(this); ViewLayerCustomItem *customWidget = new ViewLayerCustomItem(); this->setItemWidget(item, 0, customWidget); this->addTopLevelItem(item); QTreeWidgetItem *item2 = new QTreeWidgetItem(this); this->addTopLevelItem(item2); this->setDragDropMode(QAbstractItemView::InternalMove); this->setSelectionMode(QAbstractItemView::ExtendedSelection); this->setDragEnabled(true); this->setAcceptDrops(true); this->setDropIndicatorShown(true); }
Any help is appreciated so much. Have been struggeling with this for so many days on my own now, but guess im just to noobie still. :)
-
Hi and welcome to devnet,
You should rather check QStyledItemDelegate. This allows you to render exactly what you want. You can also implement custom interaction such as clicking on the checkbox. Bonus: you already have support for the drag and drop part though you will have to implement the grouping part yourself.
-
@SGaist Thank you very much. <3 Really appreciate that. Actually i tried QStyledItemDelegate but than got stuck cause of the highlighting and grouping part.
Here is what my text delegate code looked like:
delegate.cpp:
#include "ViewLayerItemDelegate.h" #include <QStyledItemDelegate> #include <QPainter> #include <QApplication> 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); 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); } void ViewLayerItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor); 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); } 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 { LineEditCheckBoxWidget widget; 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.resize(option.rect.size()); QPixmap pixmap(widget.size()); widget.render(&pixmap); painter->drawPixmap(option.rect, pixmap); }
and here is my delegate.h:
#ifndef VIEWLAYERITEMDELEGATE_H #define VIEWLAYERITEMDELEGATE_H #include <QStyledItemDelegate> #include <QModelIndex> #include <QObject> #include <QSize> #include <QLineEdit> #include <QStandardItemModel> #include <QCheckBox> #include <QFormLayout> // Definieren Sie das benutzerdefinierte Widget class LineEditCheckBoxWidget : public QWidget { Q_OBJECT public: QLineEdit *lineEdit; QCheckBox *checkBox; LineEditCheckBoxWidget(QWidget *parent = nullptr) : QWidget(parent) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setContentsMargins(10,0,20,0); layout->setSpacing(0); lineEdit = new QLineEdit(this); checkBox = new QCheckBox(this); layout->addWidget(lineEdit); layout->addStretch(1); layout->addWidget(checkBox); } }; class ViewLayerItemDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit ViewLayerItemDelegate(QObject *parent = nullptr); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; #endif // VIEWLAYERITEMDELEGATE_H
´
and thats how i called it in my treeview subclass:
/* mydelegate = new ViewLayerItemDelegate(this); model = new QStandardItemModel(10,1,this); for(int row = 0; row < 10; ++row) { for(int col = 0; col < 1; ++col) { QModelIndex index = model->index(row, col, QModelIndex()); model->setData(index, 0); } } this->setModel(model); this->setItemDelegate(mydelegate); */
How to go about the highlighting on hover over? How to go about the grouping I have actually no good glue.
-
Any hints on how to get the highlighting working? I guess i somehow have to do this from my treeview.
EDIT: i found this post, similar to what i want but i just can't get i working for my case. Please can anyone with a little more knowledge help me here:
evileg - highlighting QTableView -
@StudentScripter For the grouping you have to use an adequate data structure.
As for hovering, IIRC, you have to have mouse tracking enabled on the view.