Пример "Drop Site"
Файлы:
Пример показывает, как различать различные MIME-форматы доступные в операциях перетаскивания.
Пример "Drop Site" принимает отпускания из других приложений и выводит на экран MIME-форматы, предоставляемые объектом перетаскивания.
В данном примере имеется два класса, DropArea и DropSiteWindow, и функция main(). Объект DropArea создаётся в DropSiteWindow; объект DropSiteWindow затем вызывается в функции main().
Определение класса DropArea
Класс DropArea является подклассом QLabel с открытым слотом clear() и сигналом changed().
class DropArea : public QLabel
{
Q_OBJECT
public:
DropArea(QWidget *parent = 0);
public slots:
void clear();
signals:
void changed(const QMimeData *mimeData = 0);
Кроме того, DropArea также содержит закрытый экземпляр класса QLabel и переопределения четырёх обработчиков событий QWidget:
- dragEnterEvent()
- dragMoveEvent()
- dragLeaveEvent()
- dropEvent()
Эти обработчики событий объяснены далее в реализации класса DropArea.
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dropEvent(QDropEvent *event);
private:
QLabel *label;
};
Реализация класса DropArea
В конструкторе DropArea мы устанавливаем минимальный размер равным 200x200 пикселям, стиль рамки равным QFrame::Sunken и QFrame::StyledPanel, а также мы выравниваем его содержимое по центру.
DropArea::DropArea(QWidget *parent)
: QLabel(parent)
{
setMinimumSize(200, 200);
setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
setAlignment(Qt::AlignCenter);
setAcceptDrops(true);
setAutoFillBackground(true);
clear();
}
Также мы включаем события отпускания в DropArea установив свойство acceptDrops равным true. Затем мы включаем свойство autoFillBackground и вызываем функцию clear().
Обработчик событий dragEnterEvent() вызывается когда выполняется перетаскивание и мышь входит в пределы объекта DropArea. Для примера DropSite, когда мышь входит в пределы DropArea, мы устанавливаем его текст равным "<drop content>" и подсвечиваем фон.
void DropArea::dragEnterEvent(QDragEnterEvent *event)
{
setText(tr("<drop content>"));
setBackgroundRole(QPalette::Highlight);
event->acceptProposedAction();
emit changed(event->mimeData());
}
Затем мы вызываем acceptProposedAction() на event, устанавливаем действия отпускания для предлагаемого действия. В заключение, мы испускаем сигнал changed() с данными, которые были отпущены, и информацией об их MIME-типе в качестве параметра.
Для dragMoveEvent() мы только принимаем предложенный объект QDragMoveEvent, event, с помощью acceptProposedAction().
void DropArea::dragMoveEvent(QDragMoveEvent *event)
{
event->acceptProposedAction();
}
Реализация класса DropArea функции dropEvent() извлекает mime-данные event'а и, соответственно, выводит их на экран.
void DropArea::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData();
Объект mimeData может содержать один из следующих объектов: изображение, текст HTML, обычный текст или список URLов.
if (mimeData->hasImage()) {
setPixmap(qvariant_cast<QPixmap>(mimeData->imageData()));
} else if (mimeData->hasHtml()) {
setText(mimeData->html());
setTextFormat(Qt::RichText);
} else if (mimeData->hasText()) {
setText(mimeData->text());
setTextFormat(Qt::PlainText);
} else if (mimeData->hasUrls()) {
QList<QUrl> urlList = mimeData->urls();
QString text;
for (int i = 0; i < urlList.size() && i < 32; ++i) {
QString url = urlList.at(i).path();
text += url + QString("\n");
}
setText(text);
} else {
setText(tr("Cannot display data"));
}
- Если mimeData содержит изображение, мы выведем его на экран в DropArea с помощью setPixmap().
- Если mimeData содержит HTML, мы выведем его на экран с помощью setText() и установим формат текста DropArea как Qt::RichText.
- Если mimeData содержит обычный текст, мы выведем его на экран с помощью setText() и установим формат текста DropArea как Qt::PlainText. В событии, в которомmimeData содержит URLы, мы перебираем URL списка чтобы вывести их на экран в отдельных строках.
- Если mimeData содержит другие типы объектов, мы установим текст DropArea с помощью setText() в значение "Cannot display data" чтобы проинформировать пользователя.
Затем установим роль DropArea'а, backgroundRole, в значение QPalette::Dark и примем предлагаемой действие event'а.
setBackgroundRole(QPalette::Dark);
event->acceptProposedAction();
}
Обработчик событий dragLeaveEvent() вызывается когда происходит перетаскивание и мышь покидает пределы виджета.
void DropArea::dragLeaveEvent(QDragLeaveEvent *event)
{
clear();
event->accept();
}
Для реализации DropArea мы очищаем, вызывая clear(), а затем принимаем предложенное событие.
Функция clear() устанавливает текст в DropArea в значение "<drop content>" и устанавливает backgroundRole в значение QPalette::Dark. Наконец, она испукает сигнал changed().
void DropArea::clear()
{
setText(tr("<drop content>"));
setBackgroundRole(QPalette::Dark);
emit changed();
}
Определение класса DropSiteWindow
Класс DropSiteWindow содержит конструктор и открытый слот, updateFormatsTable().
class DropSiteWindow : public QWidget
{
Q_OBJECT
public:
DropSiteWindow();
public slots:
void updateFormatsTable(const QMimeData *mimeData);
private:
DropArea *dropArea;
QLabel *abstractLabel;
QTableWidget *formatsTable;
QPushButton *clearButton;
QPushButton *quitButton;
QDialogButtonBox *buttonBox;
};
Класс также содержит закрытый экземпляр класса DropArea, dropArea, QLabel, abstractLabel, QTableWidget, formatsTable, QDialogButtonBox, buttonBox, а также два объекта QPushButton, clearButton и quitButton.
Реализация класса DropSiteWindow
В конструкторе DropSiteWindow, мы создаём экземпляр abstractLabel и устанавливаем его свойство wordWrap равным true. Также мы вызываем функцию adjustSize() чтобы привести размер abstractLabel'а в соответствие с его содержимым.
DropSiteWindow::DropSiteWindow()
{
abstractLabel = new QLabel(tr("This example accepts drags from other "
"applications and displays the MIME types "
"provided by the drag object."));
abstractLabel->setWordWrap(true);
abstractLabel->adjustSize();
Далее мы создаём экземпляр класса dropArea и соединяем его сигнал changed() со слотом DropSiteWindow'а updateFormatsTable().
dropArea = new DropArea;
connect(dropArea, SIGNAL(changed(const QMimeData *)),
this, SLOT(updateFormatsTable(const QMimeData *)));
Теперь мы устанавливаем объект QTableWidget, formatsTable. Его горизонтальный заголовок устанавливается используя объект QStringList, labels. Количество колонок устанавливается равным двум, а таблица - нередактируемой. Также, горизонтальный заголовок formatTable'а форматируется чтобы обеспечить растяжение его второго столбца на всё доступное дополнительное пространство.
QStringList labels;
labels << tr("Format") << tr("Content");
formatsTable = new QTableWidget;
formatsTable->setColumnCount(2);
formatsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
formatsTable->setHorizontalHeaderLabels(labels);
formatsTable->horizontalHeader()->setStretchLastSection(true);
Два объект QPushButton, clearButton и quitButton, создаются и добавляются в объект buttonBox класса QDialogButtonBox. Мы используем QDialogButtonBox, чтобы убедиться, что кнопки присутствуют в компоновке, которая согласовывается со стилем платформы.
clearButton = new QPushButton(tr("Clear"));
quitButton = new QPushButton(tr("Quit"));
buttonBox = new QDialogButtonBox;
buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
connect(quitButton, SIGNAL(pressed()), this, SLOT(close()));
connect(clearButton, SIGNAL(pressed()), dropArea, SLOT(clear()));
Сигналы clicked() для quitButton и clearButton присоединяются к close() и clear(), соответственно.
Для компоновки мы используем QVBoxLayout, mainLayout, чтобы разместить наши виджеты вертикально. Также мы устанавливаем заголовок окна в "Drop Site" и минимальный размер равным 350x500 пикселям.
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(abstractLabel);
mainLayout->addWidget(dropArea);
mainLayout->addWidget(formatsTable);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Drop Site"));
setMinimumSize(350, 500);
}
Мы переходим к функции updateFormatsTable(). Эта функция обновляет formatsTable, выводя на экран MIME-форматы объекта, отпускаемого на объект DropArea. Сначала мы устанавливаем свойство QTableWidget'а, rowCount, равным 0. Затем мы проверяем правильность, чтобы убедиться, что объект QMimeData передан в правильный объект.
void DropSiteWindow::updateFormatsTable(const QMimeData *mimeData)
{
formatsTable->setRowCount(0);
if (!mimeData)
return;
Раз уж мы уверены, что mimeData правилен, мы перебираем поддерживаемые им форматы используя ключевое слово foreach. Ключевое слово имеет следующий формат:
foreach(переменная, контейнер)
В нашем примере, format - переменная, а контейнер - QStringList, полученный из mimeData->formats().
Замечание: Функция formats() возвращает объект QStringList, содержащий все форматы, поддерживаемые mimeData.
foreach (QString format, mimeData->formats()) {
QTableWidgetItem *formatItem = new QTableWidgetItem(format);
formatItem->setFlags(Qt::ItemIsEnabled);
formatItem->setTextAlignment(Qt::AlignTop | Qt::AlignLeft);
В каждой итерации мы создаём QTableWidgetItem, formatItem и устанавливаем его флаги равными Qt::ItemIsEnabled, а его выравнивание текста - в Qt::AlignTop и Qt::AlignLeft.
Объект QString object, text, настраивается для вывода на экран данных, согласно содержимого format. Мы вызываем функцию {QString}'а, simplified(), на text, чтобы получить строку, которая не имеет дополнительного пробела перед, после или между словами.
QString text;
if (format == "text/plain") {
text = mimeData->text().simplified();
} else if (format == "text/html") {
text = mimeData->html().simplified();
} else if (format == "text/uri-list") {
QList<QUrl> urlList = mimeData->urls();
for (int i = 0; i < urlList.size() && i < 32; ++i) {
QString url = urlList.at(i).path();
text.append(url + " ");
}
} else {
QByteArray data = mimeData->data(format);
for (int i = 0; i < data.size() && i < 32; ++i) {
QString hex = QString("%1").arg(uchar(data[i]), 2, 16,
QChar('0'))
.toUpper();
text.append(hex + " ");
}
}
Если format содержит список URLов, мы перебираем их, используя пробелы как разделители. С другой стороны, если format содержит изображение, мы выводим на экран данные, преобразовав текст в шестнадцатеричный вид.
int row = formatsTable->rowCount();
formatsTable->insertRow(row);
formatsTable->setItem(row, 0, new QTableWidgetItem(format));
formatsTable->setItem(row, 1, new QTableWidgetItem(text));
}
formatsTable->resizeColumnToContents(0);
}
Так как text настроен для содержания в себе соответствующих данных, мы вставляем и format, и text в formatsTable с помощью setItem(). В заключение, мы вызываем resizeColumnToContents() на первом столбце formatsTable'а.
Функция main()
В функции main() мы создаём экземпляр DropSiteWindow и вызываем его функцию show().
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
DropSiteWindow window;
window.show();
return app.exec();
}
|