Lassen Sie uns eine kleine Anwendung schreiben, die es ermöglicht, die Drag and Drop -Methode zu verwenden, um Bilder aus dem Dateimanager in unsere Anwendung selbst zu ziehen und dort abzulegen. Damit verfügt die Anwendung über ein Bildansichtsfenster und eine Liste aller Bilder, die wir in unserer Anwendung platziert haben. Wenn Sie in diesem Fall auf ein Bild in der Liste klicken, wird das Bild, auf das wir geklickt haben, im Hauptanzeigebereich platziert. In dieser Liste wird für jedes Element ein Vorschaubild ohne Text generiert. Eine solche Vorschau wird mithilfe eines von QStyledDelegate. geerbten Delegaten generiert.
Die Anwendung wird wie folgt aussehen:
Projektstruktur
- DropEvent.pro - Projektprofil;
- main.cpp - Datei mit main-Funktion;
- widget.h - Header-Datei des Anwendungsfensters;
- widget.cpp - Quellcodedatei der Anwendung;
- imagedelegate.h - Header-Datei des Listenelement-Delegaten;
- Imagedelegate.cpp - Quellcodedatei des Listenelement-Delegaten.
Der Delegierte in diesem Projekt ist erforderlich, um den Text unter den Bildern zu entfernen. Der Punkt ist, dass QListView und QStandardItemModel verwendet werden, um Bildvorschauen anzuzeigen, die nicht die Funktionalität haben, Symbole ohne Text anzuzeigen. Es ist jedoch möglich, den Text mithilfe eines Delegaten zu entfernen, wodurch die Darstellung des Listenelements vollständig neu definiert wird.
Ich werde den Quellcode der Dateien DropEvent.pro und main.cpp nicht angeben, da beim Erstellen eines Projekts standardmäßig ein Programmcode erstellt wird.
Widget.h
In der Header-Datei des Anwendungsfensters werden wir die Methoden für die Ereignisse Drag und Drop überschreiben und auch Objekte hinzufügen, um die Schnittstelle und ein Datenmodell für Bilder zu bilden.
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPalette> #include <QDragEnterEvent> #include <QMimeData> #include <QDropEvent> #include <QScrollArea> #include <QLabel> #include <QListView> #include <QGridLayout> #include <QStandardItemModel> class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); // Метод события перетаскивания virtual void dragEnterEvent(QDragEnterEvent* event) override; // Метод события отпускания объекта с данными virtual void dropEvent(QDropEvent *event) override; private slots: // Слот для обработки кликов по элементам списка void onImagesListViewClicked(const QModelIndex& index); private: QScrollArea* m_scrollArea; // Область скроллинга изображения QLabel* m_imageLabel; // Лейбл для отображения картинок QListView* m_imagesListView; // Список с изображениями QGridLayout* m_gridLayout; // Сетка для интерфейса QStandardItemModel* m_imagesModel; // Модель данных с изображениями }; #endif // WIDGET_H
Widget.cpp
QStandardItemModel wird verwendet, um eine Liste mit Bildern zu erstellen, und QListView wird verwendet, um Modellelemente anzuzeigen. Für eine angepasste Anzeige von Elementen in der Liste wird der Delegate verwendet, da es nur durch Überschreiben der Anzeige des Erscheinungsbilds möglich ist, den Text zu entfernen. Dieser Text enthält übrigens den Pfad zur Bilddatei, die verwendet wird, um eine QPixmap zu erstellen und das Bild sowohl in der Hauptansicht als auch in Vorschauen anzuzeigen. Um den Dateipfad aus dem Datenmodell abzurufen, müssen Sie die Methode data(), verwenden und QModellndex und enum Qt::DisplayRole , das das Standardargument ist, als übergeben Argumente.
#include "widget.h" #include "ui_widget.h" #include <QStandardItem> #include "imagedelegate.h" Widget::Widget(QWidget *parent) : QWidget(parent) { setAcceptDrops(true); // разрешаем события отпускания объектов данных setMinimumWidth(640); setMinimumHeight(480); /// Настраиваем интерфейс m_gridLayout = new QGridLayout(this); m_imagesListView = new QListView(this); // Создадим модель данных для списка изображений m_imagesModel = new QStandardItemModel(m_imagesListView); m_imagesListView->setModel(m_imagesModel); // Установим модель во вьюшку для превью изображений m_imagesListView->setFixedWidth(200); // Без делегата не удастся избавиться от текста в элементе списка и настроить отображение превью m_imagesListView->setItemDelegate(new ImageDelegate(m_imagesModel, m_imagesListView)); // Настраиваем область скроллинга для текущего изображения m_scrollArea = new QScrollArea(this); m_scrollArea->setBackgroundRole(QPalette::Dark); m_imageLabel = new QLabel(this); m_scrollArea->setWidget(m_imageLabel); m_gridLayout->addWidget(m_scrollArea, 0, 0); m_gridLayout->addWidget(m_imagesListView, 0, 1); connect(m_imagesListView, &QListView::clicked, this, &Widget::onImagesListViewClicked); } Widget::~Widget() { } void Widget::dragEnterEvent(QDragEnterEvent *event) { // Обязательно необходимо допустить событие переноса данных в область окна приложения event->accept(); } void Widget::dropEvent(QDropEvent *event) { // Когда отпускаем файл в область приложения, // то забираем путь к файлу из MIME данных QString filePath = event->mimeData()->urls()[0].toLocalFile(); // Создаём изображение QPixmap pixmap(filePath); // Помещаем его в область скроллинга через QLabel m_imageLabel->setPixmap(pixmap); m_imageLabel->resize(pixmap.size()); // Добавляем элемент в список m_imagesModel->appendRow(new QStandardItem(QIcon(pixmap), filePath)); } void Widget::onImagesListViewClicked(const QModelIndex &index) { // Когда кликаем по элементу в списке, то забираем путь к файлу QPixmap pixmap(m_imagesModel->data(index).toString()); // И устанавливаем файл в область основного просмотра m_imageLabel->setPixmap(pixmap); m_imageLabel->resize(pixmap.size()); }
imagedelegate.h
Und hier ist der Delegat selbst, dessen Aufgabe es ist, das Element in der Liste anzuzeigen. Um den Pfad zur Bilddatei zu erhalten, habe ich einen Zeiger auf das Datenmodell übergeben, und über QModelIndex in der Paint-Methode erhalte ich den Pfad zum Bild.
Ein weiterer wichtiger Punkt ist die Verwendung der Methode sizeHint(). , die die Größe des Elements in der Liste anpasst. Wenn Sie darin keine Größenanpassung vornehmen, entspricht die Größe des Elements der üblichen Textzeile. Die Vorschau wird absolut schrecklich aussehen.
#ifndef IMAGEDELEGATE_H #define IMAGEDELEGATE_H #include <QStyledItemDelegate> #include <QPainter> #include <QStyleOptionViewItem> #include <QModelIndex> #include <QStandardItemModel> #include <QPixmap> #include <QDebug> class ImageDelegate : public QStyledItemDelegate { public: explicit ImageDelegate(QStandardItemModel *model, QObject *parent = nullptr); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; QStandardItemModel* m_model; }; #endif // IMAGEDELEGATE_H
Imagedelegate.cpp
Ein weiterer wichtiger Punkt ist die Verwendung von QRect aus QStyleOptionViewItem. Fakt ist, dass es nicht nur die Höhe und Breite des Elements enthält, sondern auch seine x- und y-Position in der Liste. Wenn Sie diese Koordinaten nicht berücksichtigen, können Sie sehen, dass alle Elemente an einer Stelle gezeichnet werden. Zum Beispiel in der oberen linken Ecke der Liste, wenn Sie beim Zeichnen x = 0 und y = 0 setzen.
#include "imagedelegate.h" ImageDelegate::ImageDelegate(QStandardItemModel *model, QObject *parent) : QStyledItemDelegate(parent), m_model(model) { } void ImageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { // Вместо отрисовки иконки и текста будем отрисовывать только одно изображение // с небольшими отступами в 5 пикселей QPixmap pix(m_model->data(index).toString()); QRect optionRect = option.rect; painter->drawPixmap(optionRect.x() + 5, optionRect.y() + 5, optionRect.width() - 10, optionRect.height() - 10 , pix); } QSize ImageDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { // Корректируем размеры области отображения объекта в списке QSize result = QStyledItemDelegate::sizeHint(option, index); result.setHeight(140); result.setWidth(140); return QSize(140, 140); }
А можно сразу передовать Qpixmap?
Нет, нужно сконвертировать информацию в удобоваримый mime type
Доброго времени суток.
А если нужно и изображение и текст?
Что-то потерялся немного....
// Вместо отрисовки иконки и текста будем отрисовывать только одно изображение
// с небольшими отступами в 5 пикселей
QPixmap pix(m_model->data(index).toString());
Добрый день. Посмотрите описание методов drawText у QPainter, он позволит и текст нарисовать