application.h:
#pragma once
#include <QApplication>
class Application : public QApplication
{
Q_OBJECT
public:
Application(int& argc, char** argv);
signals:
void requestedFile(const QString& fileName);
protected:
bool event(QEvent* event) override;
};
application.cpp:
#include "application.h"
#include <QFileOpenEvent>
Application::Application(int& argc, char** argv)
: QApplication(argc, argv)
{
}
bool Application::event(QEvent* event)
{
if (event->type() == QEvent::FileOpen) {
emit requestedFile(static_cast<QFileOpenEvent*>(event)->file());
return true;
}
return QApplication::event(event);
}
droparea.h:
#pragma once
#include <QWidget>
class QDragEnterEvent;
class QDropEvent;
class DropArea : public QWidget
{
Q_OBJECT
public:
explicit DropArea(QWidget* parent = 0);
public slots:
void appendImage(const QString& fileName);
protected:
void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override;
public:
QSize sizeHint() const override;
private:
QSize totalImageSize;
int numberOfImages;
};
droparea.cpp:
#include "droparea.h"
#include "application.h"
#include "pixmapview.h"
#include <QApplication>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QLabel>
#include <QLayout>
DropArea::DropArea(QWidget* parent)
: QWidget(parent)
{
numberOfImages = 0;
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
setAcceptDrops(true);
const auto topLayout = new QVBoxLayout(this);
topLayout->addStretch();
topLayout->setSpacing(8);
QObject::connect(qobject_cast<Application*>(qApp), &Application::requestedFile, this, &DropArea::appendImage);
setAutoFillBackground(true);
QPalette background = palette();
background.setColor(QPalette::Window, Qt::white);
setPalette(background);
}
void DropArea::appendImage(const QString& fileName)
{
const QPixmap pixmap(fileName);
if (!pixmap.isNull()) {
auto pixmapView = new PixmapView(pixmap, fileName);
numberOfImages += 1;
totalImageSize.rwidth() = qMax(totalImageSize.width(), pixmapView->width());
totalImageSize.rheight() += pixmapView->height();
auto topLayout = qobject_cast<QVBoxLayout*>(layout());
Q_ASSERT(topLayout);
int left, top, right, bottom;
topLayout->getContentsMargins(&left, &top, &right, &bottom);
const int newWidth = totalImageSize.width() + left + right;
const int newHeight = qMax(totalImageSize.height() + top + bottom + topLayout->spacing()*(numberOfImages - 1), height());
setFixedSize(newWidth, newHeight);
topLayout->insertWidget(topLayout->count() - 1, pixmapView);
}
}
void DropArea::dragEnterEvent(QDragEnterEvent* event)
{
if (event->mimeData()->hasUrls()) {
event->accept();
}
}
void DropArea::dropEvent(QDropEvent* event)
{
for (const auto& url : event->mimeData()->urls()) {
appendImage(url.path());
}
event->acceptProposedAction();
}
QSize DropArea::sizeHint() const
{
return QSize(300, 300);
}
ドロップされたファイルで QPixmap のインスタンス生成が成功したならば画像ファイルと考えます。失敗したならば何もしません。画像ファイルがドロップされたときにレイアウトの最後のスペーサーの前に画像を表示する PixmapView インスタンスを追加しています。レイアウトの最後のスペーサーは addStretch() で追加しているのでできる限り広がるため画像が上部に詰められてレイアウトされます。
pixmapview.h:
#pragma once
#include <QWidget>
class PixmapView : public QWidget
{
Q_OBJECT
public:
PixmapView(const QPixmap& pixmap, const QString& path, QWidget* parent = 0);
};
pixmapview.cpp:
#include "pixmapview.h"
#include <QLabel>
#include <QLayout>
#include <QDebug>
PixmapView::PixmapView(const QPixmap& pixmap, const QString& path, QWidget* parent)
: QWidget(parent)
{
const auto topLayout = new QVBoxLayout(this);
const auto pixmapLabel = new QLabel;
pixmapLabel->setPixmap(pixmap);
topLayout->addWidget(pixmapLabel);
topLayout->addWidget(new QLabel(path));
setFixedSize(sizeHint());
setAutoFillBackground(true);
QPalette background = palette();
background.setColor(QPalette::Window, "whitesmoke");
setPalette(background);
}
harness.h:
#pragma once
#include <QWidget>
class Harness : public QWidget
{
Q_OBJECT
public:
explicit Harness(QWidget* parent = 0);
};
harness.cpp:
#include "harness.h"
#include "droparea.h"
#include <QScrollArea>
#include <QLayout>
Harness::Harness(QWidget* parent)
: QWidget(parent)
{
const auto topLayout = new QVBoxLayout(this);
const auto dropArea = new DropArea(this);
const auto scrollArea = new QScrollArea(this);
scrollArea->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
scrollArea->resize(300, 300);
scrollArea->setWidget(dropArea);
topLayout->addWidget(scrollArea);
}
main.cpp:
#include "application.h"
#include "harness.h"
int main(int argc, char** argv)
{
Application app(argc, argv);
Harness harness;
harness.show();
return app.exec();
}
Info.plist
<!DOCTYPE plist PUBLIC
"-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>xpm</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>image/x-xpm</string>
</array>
<key>CFBundleTypeName</key>
<string>X PixMap File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSIsAppleDefaultForType</key>
<true/>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>png</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>image/png</string>
</array>
<key>CFBundleTypeName</key>
<string>Portable Network Graphics File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSIsAppleDefaultForType</key>
<true/>
</dict>
</array>
<key>CFBundleIconFile</key>
<string>appfileopen.icns</string>
<key>CFBundleExecutable</key>
<string>appleevents</string>
<key>CFBundleIdentifier</key>
<string>jp.co.reversedomainname.fileopenevent</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleExecutable</key>
<string>AppFileOpen</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
</dict>
</plist>
appfileopen.pro:
!macos {
error(Only for macOS)
}
QT += widgets
TARGET = AppFileOpen
TEMPLATE = app
SOURCES += main.cpp \
pixmapview.cpp \
application.cpp \
droparea.cpp \
harness.cpp
HEADERS += \
pixmapview.h \
application.h \
droparea.h \
harness.h
QMAKE_INFO_PLIST=Info.plist
ICON=icon/appfileopen.icns
左上のアプリケーションアイコンに PNG か XPM をドロップするとアプリケーションが起動し画像ファイルが表示されます。起動後にドロップすると画像ファイルが追加されます。
アプリケーションウィンドウに画像ファイルをドロップすると画像ファイルが追加して表示されます。Qt が扱える画像はすべて受け付けるようにしています。画像ファイル以外もドロップできますが無視して何もしません。
参考情報
QFileOpenEvent Class
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。