Qt6で作るコミックビューワー
2022/02/23 categories:Qt6| tags:Qt6|Qt6.2.3|C++|
以前作成したPyQt5のコミックビューワーっぽいアプリをC++に書き換えてみました。
実装した主な機能
- フォルダ内の本(フォルダ)を読み込み
- 本のフォルダ内の1つ目の画像を縮小してサムネイルとして表示
- 本のサムネイルをクリックすると1ページ目を表示
- ページを表示中に左右にスワイプしてページを移動
動作の様子は以下の通りです。
フォルダを読み込むダイアログ
フォルダを読み込むダイアログは、QFileDialog::getExistingDirectory()を使うを簡単に実装できますが、getExistingDirectory()は単一のフォルダしか選択できません。フォルダを複数選択できるダイアログを表示するためには、setOption()でDontUseNativeDialogをtrueにして、ダイアログの子ウィジェットからファイルの一覧を表示するQTreeViewを検索して、そのQTreeViewのSelectionModeをMultiSelectionに設定することで、フォルダを複数選択できるダイアログを表示できるようです。コードは以下の通りです。
QFileDialog dialog(this, "Open Folder", "D:/Qt/my_program/test_data");
dialog.setFileMode(QFileDialog::Directory);
dialog.setOption(QFileDialog::ShowDirsOnly);
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
dialog.setStyle(QStyleFactory::create("Fusion"));
QTreeView *tree = dialog.findChild<QTreeView *>();
tree->setSelectionMode(QAbstractItemView::MultiSelection);
QListView *listView = dialog.findChild<QListView *>("sidebar");
listView->hide();
if (!dialog.exec()) return;
QStringList folderNames = dialog.selectedFiles();
このプログラムでは、選択したフォルダを本棚と見立てて左側に本棚のボタンを追加します。本棚のボタンをクリックすると、その本棚内にある本の一覧を表示します。動作の様子は以下の通りです。
QGraphicsViewをスワイプして
スワイプの判定は簡単な処理でそれっぽく動作するコードを書きましたが、QGestureを使うとジェスチャーを扱うことができるようです。今回書いたコードは以下のような処理にしました。
- mousePressEventの時に、クリックした位置をclickPosとして取得
- mouseReleaseEventの時に、リリースした位置をreleasePosとして取得
- releasePosとclickPosの差分の絶対値を計算して、閾値以上ならスワイプとする
- スワイプした時の上記差分について、x>yなら横にスワイプとする、逆なら縦にスワイプとする
- 差分の正負を比較して、スワイプ方向を決定して、QGraphicsViewからシグナルを発行
コードは以下の通りです。
void PageView::mouseReleaseEvent(QMouseEvent *event)
{
releasePos = event->pos();
if (event->button() == Qt::LeftButton)
{
int dx = releasePos.x() - clickPos.x();
int dy = releasePos.y() - clickPos.y();
if ((abs(dx) > 50) || (abs(dy) > 50))
{
if (qFabs(dx) > qFabs(dy))
{
if (dx > 0) { emit PageView::rightFlicked(); }
else { emit PageView::leftFlicked(); }
}
else
{
if (dy > 0) { emit PageView::downFlicked(); }
else { emit PageView::upFlicked(); }
}
}
}
}
QGraphicsViewをスワイプした時の動作の様子は以下の通りです。
QScrollAreaをドラッグでスクロール
タッチパネルでの操作を想定して、本の一覧を表示しているQScrollAreaをドラッグした場合にスクロールするような処理を実装しました。デフォルトのQScrollAreaではスクロールバーを移動するかマウスホイールを回すことでスクロールできますが、QScrollAreaをクリックしたままマウスを移動させた場合にQScrollAreaをスクロールするという処理にしています。ただし、これだけでは本のサムネイルをクリックしたままマウスを移動してもスクロールできないので、サムネイルを0.2秒以上クリックした場合は同様のスクロールの処理を行うようにしました。これで実用上あまり困らない処理にできました。
void ScrollArea::mousePressEvent(QMouseEvent *event)
{
this->x0 = event->pos().x();
this->y0 = event->pos().y();
}
void ScrollArea::mouseMoveEvent(QMouseEvent *event)
{
emit this->mouseMoved(event->pos().x() - this->x0, event->pos().y() - this->y0);
this->x0 = event->pos().x();
this->y0 = event->pos().y();
}
void MainWindow::scrollArea_mouseMoved(int dx, int dy)
{
int x = ui->scrollArea->horizontalScrollBar()->value() + dx;
if (0 <= x and x <= ui->scrollArea->horizontalScrollBar()->maximum())
ui->scrollArea->horizontalScrollBar()->setValue(x);
int y = ui->scrollArea->verticalScrollBar()->value() + dy;
if (0 <= y and y <= ui->scrollArea->verticalScrollBar()->maximum())
ui->scrollArea->verticalScrollBar()->setValue(y);
}
void ThumbnailView::mouseReleaseEvent(QMouseEvent *event)
{
if (!this->isMoving)
{
emit ThumbnailView::clicked();
}
return QGraphicsView::mouseReleaseEvent(event);
}
void ThumbnailView::mousePressEvent(QMouseEvent *event)
{
this->x0 = event->pos().x();
this->y0 = event->pos().y();
this->isMoving = false;
QTimer::singleShot(200, this, &ThumbnailView::clickTimeout);
}
void ThumbnailView::mouseMoveEvent(QMouseEvent *event)
{
if (this->isMoving)
{
emit this->mouseMoved(event->pos().x() - this->x0, event->pos().y() - this->y0);
this->x0 = event->pos().x();
this->y0 = event->pos().y();
}
}
void ThumbnailView::clickTimeout()
{
this->isMoving = true;
}
QScrollAreaをドラッグでスクロールした様子は以下の通りです。
所感
C++はほとんど書いたことがありませんでしたが、Pythonで書いたコードをC++ではどのように書くか調べていくうちにそれぞれの言語の違いが少しだけわかってきました。また、Pythonとは違ってexeとしてビルドできるのが良いですね。Pythonではnuitkaでexe化したりしましたが、うまくexe化できないことが多くありました。しかしc++ではビルドにそれほど困らないのでやっぱりguiアプリをpythonで作るのはいろいろ制約が多いなと思いました。
ソースコード
main.cpp
ここをクリックして展開
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
ここをクリックして展開
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "toggletoolbutton.h"
#include <QMainWindow>
#include <QGraphicsScene>
#include <QtWidgets>
#include <QtCore>
#include <QPixmap>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QList<QList<QString>> books;
QList<QString> pages;
int bookshelf_number = -1;
int book_number = -1;
int page_number = -1;
void set_page();
private slots:
void on_addFolderButton_clicked();
void ToggleToolButton_clicked(int number);
void Book_clicked(int number);
void pageView_leftFlicked();
void pageView_rightFlicked();
void scrollArea_mouseMoved(int dx, int dy);
};
#endif // MAINWINDOW_H
mainwindow.cpp
ここをクリックして展開
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "book.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pageView, &PageView::leftFlicked, this, &MainWindow::pageView_leftFlicked);
connect(ui->pageView, &PageView::rightFlicked, this, &MainWindow::pageView_rightFlicked);
connect(ui->scrollArea, &ScrollArea::mouseMoved, this, &MainWindow::scrollArea_mouseMoved);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::scrollArea_mouseMoved(int dx, int dy)
{
int x = ui->scrollArea->horizontalScrollBar()->value() + dx;
if (0 <= x and x <= ui->scrollArea->horizontalScrollBar()->maximum())
ui->scrollArea->horizontalScrollBar()->setValue(x);
int y = ui->scrollArea->verticalScrollBar()->value() + dy;
if (0 <= y and y <= ui->scrollArea->verticalScrollBar()->maximum())
ui->scrollArea->verticalScrollBar()->setValue(y);
}
void MainWindow::set_page()
{
QPixmap pixmap = QPixmap(this->pages[this->page_number]);
QRectF rect = QRectF(pixmap.rect());
this->ui->pageView->scene()->clear();
this->ui->pageView->scene()->addPixmap(pixmap);
this->ui->pageView->scene()->setSceneRect(rect);
this->ui->pageView->fitInView(this->ui->pageView->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
}
void MainWindow::pageView_leftFlicked()
{
if (this->page_number > 0)
{
this->page_number--;
this->set_page();
}
}
void MainWindow::pageView_rightFlicked()
{
if (this->page_number < this->pages.size() - 1)
{
this->page_number++;
this->set_page();
}
}
void MainWindow::ToggleToolButton_clicked(int number)
{
// toggle folder buttons
this->bookshelf_number = number;
for (int i = 0; i < this->ui->folderLayout->count(); i++)
{
if (i == this->bookshelf_number) { continue; }
QLayoutItem *item = this->ui->folderLayout->itemAt(i);
ToggleToolButton* button2 = dynamic_cast<ToggleToolButton*>(item->widget());
button2->setChecked(false);
}
// delete all books
for (int i = 0; i < this->ui->bookLayout->count(); i++)
{
this->ui->bookLayout->itemAt(i)->widget()->deleteLater();
}
// append books from folder
QList<QString> books2 = this->books[this->bookshelf_number];
for (int i = 0; i < books2.size(); i++)
{
QDir bookDir = QDir(books2[i]);
QFileInfoList fileInfoList2 = bookDir.entryInfoList(QDir::Files|QDir::NoDotAndDotDot);
QString firstPagePath = fileInfoList2[0].absoluteFilePath();
Book* book = new Book(bookDir.dirName(), firstPagePath, i);
connect(book, &Book::clicked, this, &MainWindow::Book_clicked);
connect(book, &Book::mouseMoved, this, &MainWindow::scrollArea_mouseMoved);
this->ui->bookLayout->addWidget(book, i / 3, i % 3, 1, 1);
}
this->ui->stackedWidget->setCurrentIndex(0);
}
void MainWindow::Book_clicked(int number)
{
// get pages
this->book_number = number;
this->pages.clear();
QString bookPath = this->books[this->bookshelf_number][this->book_number];
QFileInfoList fileInfoList = QDir(bookPath).entryInfoList(QDir::Files|QDir::NoDotAndDotDot);
for (int i = 0; i < fileInfoList.size(); i++)
{
QFileInfo fileInfo = fileInfoList[i];
QString pagePath = fileInfo.absoluteFilePath();
this->pages.append(pagePath);
}
// set page
this->page_number = 0;
this->set_page();
// folder button unchecked
QLayoutItem *item = this->ui->folderLayout->itemAt(this->bookshelf_number);
ToggleToolButton* button = dynamic_cast<ToggleToolButton*>(item->widget());
button->setChecked(false);
this->ui->stackedWidget->setCurrentIndex(1);
}
void MainWindow::on_addFolderButton_clicked()
{
// get folders
QFileDialog dialog(this, "Open Folder", "D:/Qt/my_program/test_data");
dialog.setFileMode(QFileDialog::Directory);
dialog.setOption(QFileDialog::ShowDirsOnly);
dialog.setOption(QFileDialog::DontUseNativeDialog, true);
dialog.setStyle(QStyleFactory::create("Fusion"));
QTreeView *tree = dialog.findChild<QTreeView *>();
tree->setSelectionMode(QAbstractItemView::MultiSelection);
QListView *listView = dialog.findChild<QListView *>("sidebar");
listView->hide();
if (!dialog.exec()) return;
QStringList folderNames = dialog.selectedFiles();
for (int i = 0; i < folderNames.size(); i++)
{
QString folder_name = folderNames[i];
QDir bookshelfFolder(folder_name);
QFileInfoList fileInfoList1 = bookshelfFolder.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
// append folder button
int number = this->ui->folderLayout->count();
ToggleToolButton* button = new ToggleToolButton(number);
button->setText( bookshelfFolder.dirName() );
connect(button, &ToggleToolButton::clicked2, this, &MainWindow::ToggleToolButton_clicked);
this->ui->folderLayout->addWidget(button);
// get book paths in bookshelf folder
QList<QString> bookPaths;
for (int i = 0; i < fileInfoList1.size(); i++)
{
QFileInfo fileInfo1 = fileInfoList1[i];
QString bookPath = fileInfo1.absoluteFilePath();
QFileInfoList fileInfoList2 = QDir(bookPath).entryInfoList(QDir::Files|QDir::NoDotAndDotDot);
if (fileInfoList2.size() == 0) { continue; }
bookPaths.append(bookPath);
}
this->books.append(bookPaths);
}
}
mainwindow.ui
ここをクリックして展開
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Comic reader</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget{
background-color: rgb(10, 10, 10);
color: rgb(200, 200, 200);
font-size: 20px;
}
QPushButton {
background-color: rgb(30, 30, 30);
border-style: solid;
border-width: 2px;
border-color: rgb(50, 50, 50);
}
QPushButton:hover {
background-color: rgb(80, 80, 80);
}
QScrollBar:vertical {
background-color: rgb(30, 30, 30);
color: rgb(80, 80, 80);
}
QScrollBar:handle:vertical{
background-color: rgb(30, 30, 30);
}
QScrollBar:add-line:vertical{
background-color: rgb(30, 30, 30);
}
QScrollBar:sub-line:vertical{
background-color: rgb(30, 30, 30);
}
QToolButton{
background-color: rgb(30, 30, 30);
}
QToolButton:ckecked{
background-color: rgb(80, 80, 80);
}
QToolButton:hover{
background-color: rgb(50, 50, 50);
}</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="text">
<string>Folders</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="folderLayout">
<property name="spacing">
<number>2</number>
</property>
</layout>
</item>
<item>
<widget class="QToolButton" name="addFolderButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="text">
<string>Add folder</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="ScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>682</width>
<height>532</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QGridLayout" name="bookLayout"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="PageView" name="pageView">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>32</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>PageView</class>
<extends>QGraphicsView</extends>
<header location="global">pageview.h</header>
</customwidget>
<customwidget>
<class>ScrollArea</class>
<extends>QScrollArea</extends>
<header location="global">scrollarea.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
book.h
ここをクリックして展開
#ifndef BOOK_H
#define BOOK_H
#include <QWidget>
#include <QGraphicsScene>
namespace Ui {
class Book;
}
class Book : public QWidget
{
Q_OBJECT
private:
Ui::Book *ui;
QImage *image;
QGraphicsScene *scene;
int number;
public:
explicit Book(QString title, QString image_path, int number, QWidget *parent = nullptr);
~Book();
signals:
void clicked(int number);
void mouseMoved(int dx, int dy);
private slots:
void on_mouseMoved(int dx, int dy);
};
#endif // BOOK_H
book.cpp
ここをクリックして展開
#include "book.h"
#include "ui_book.h"
Book::Book(QString title, QString image_path, int _number, QWidget *parent) :
QWidget(parent),
ui(new Ui::Book)
{
ui->setupUi(this);
this->ui->label->setText(title);
number = _number;
QPixmap pixmap = QPixmap(image_path).scaledToHeight(300);
QRectF rect = QRectF(pixmap.rect());
this->ui->thumbnailView->scene()->addPixmap(pixmap);
this->ui->thumbnailView->scene()->setSceneRect(rect);
this->ui->thumbnailView->fitInView(this->ui->thumbnailView->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
connect(this->ui->thumbnailView, &ThumbnailView::clicked, this, [this]{ emit this->clicked(number); });
connect(this->ui->thumbnailView, &ThumbnailView::mouseMoved, this, &Book::on_mouseMoved);
}
Book::~Book()
{
delete ui;
}
void Book::on_mouseMoved(int dx, int dy)
{
emit this->mouseMoved(dx, dy);
}
book.ui
ここをクリックして展開
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Book</class>
<widget class="QWidget" name="Book">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>200</width>
<height>200</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="ThumbnailView" name="thumbnailView">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ThumbnailView</class>
<extends>QGraphicsView</extends>
<header location="global">thumbnailview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
scrollarea.h
ここをクリックして展開
#ifndef SCROLLAREA_H
#define SCROLLAREA_H
#include <QScrollArea>
#include <QMouseEvent>
class ScrollArea : public QScrollArea
{
Q_OBJECT
private:
int x0;
int y0;
public:
ScrollArea(QWidget *parent);
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
signals:
void mouseMoved(int dx, int dy);
};
#endif // SCROLLAREA_H
scrollarea.cpp
ここをクリックして展開
#include "scrollarea.h"
ScrollArea::ScrollArea(QWidget *parent) : QScrollArea(parent)
{
this->x0 = 0;
this->y0 = 0;
}
void ScrollArea::mousePressEvent(QMouseEvent *event)
{
this->x0 = event->pos().x();
this->y0 = event->pos().y();
}
void ScrollArea::mouseMoveEvent(QMouseEvent *event)
{
emit this->mouseMoved(event->pos().x() - this->x0, event->pos().y() - this->y0);
this->x0 = event->pos().x();
this->y0 = event->pos().y();
}
pageview.h
ここをクリックして展開
#ifndef PAGEVIEW_H
#define PAGEVIEW_H
#include <QGraphicsView>
#include <QDebug>
#include <QMouseEvent>
#include <QtMath>
class PageView : public QGraphicsView
{
Q_OBJECT
public:
PageView(QWidget *parent);
signals:
void upFlicked();
void downFlicked();
void rightFlicked();
void leftFlicked();
private:
QPoint clickPos;
QPoint releasePos;
protected:
void resizeEvent(QResizeEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
};
#endif // PAGEVIEW_H
pageview.cpp
ここをクリックして展開
#include "pageview.h"
PageView::PageView(QWidget *parent) : QGraphicsView(parent)
{
QGraphicsScene *scene = new QGraphicsScene();
this->setScene(scene);
}
void PageView::resizeEvent(QResizeEvent *event)
{
QRectF itemsBoundingRect = this->scene()->itemsBoundingRect();
this->fitInView(itemsBoundingRect, Qt::KeepAspectRatio);
return QGraphicsView::resizeEvent(event);
}
void PageView::mousePressEvent(QMouseEvent *event)
{
clickPos = event->pos();
}
void PageView::mouseReleaseEvent(QMouseEvent *event)
{
releasePos = event->pos();
if (event->button() == Qt::LeftButton)
{
int dx = releasePos.x() - clickPos.x();
int dy = releasePos.y() - clickPos.y();
if ((abs(dx) > 50) || (abs(dy) > 50))
{
if (qFabs(dx) > qFabs(dy))
{
if (dx > 0) { emit PageView::rightFlicked(); }
else { emit PageView::leftFlicked(); }
}
else
{
if (dy > 0) { emit PageView::downFlicked(); }
else { emit PageView::upFlicked(); }
}
}
}
}
thumbnailview.h
ここをクリックして展開
#ifndef THUMBNAILVIEW_H
#define THUMBNAILVIEW_H
#include <QGraphicsView>
#include <QWidget>
#include <QTimer>
#include <QMouseEvent>
class ThumbnailView : public QGraphicsView
{
Q_OBJECT
private:
int x0;
int y0;
bool isMoving;
public:
ThumbnailView(QWidget *parent);
signals:
void clicked();
void mouseMoved(int dx, int dy);
private slots:
void clickTimeout();
protected:
void resizeEvent(QResizeEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
};
#endif // THUMBNAILVIEW_H
thumbnailview.cpp
ここをクリックして展開
#include "thumbnailview.h"
ThumbnailView::ThumbnailView(QWidget *parent) : QGraphicsView(parent)
{
QGraphicsScene *scene = new QGraphicsScene();
this->setScene(scene);
this->isMoving = false;
this->x0 = 0;
this->y0 = 0;
}
void ThumbnailView::resizeEvent(QResizeEvent *event)
{
QRectF itemsBoundingRect = this->scene()->itemsBoundingRect();
this->fitInView(itemsBoundingRect, Qt::KeepAspectRatio);
return QGraphicsView::resizeEvent(event);
}
void ThumbnailView::mouseReleaseEvent(QMouseEvent *event)
{
if (!this->isMoving)
{
emit ThumbnailView::clicked();
}
return QGraphicsView::mouseReleaseEvent(event);
}
void ThumbnailView::mousePressEvent(QMouseEvent *event)
{
this->x0 = event->pos().x();
this->y0 = event->pos().y();
this->isMoving = false;
QTimer::singleShot(200, this, &ThumbnailView::clickTimeout);
}
void ThumbnailView::mouseMoveEvent(QMouseEvent *event)
{
if (this->isMoving)
{
emit this->mouseMoved(event->pos().x() - this->x0, event->pos().y() - this->y0);
this->x0 = event->pos().x();
this->y0 = event->pos().y();
}
}
void ThumbnailView::clickTimeout()
{
this->isMoving = true;
}
toggletoolbutton.h
ここをクリックして展開
#ifndef TOGGLETOOLBUTTON_H
#define TOGGLETOOLBUTTON_H
#include <QToolButton>
class ToggleToolButton : public QToolButton
{
Q_OBJECT
public:
ToggleToolButton(int _number);
int number;
signals:
void clicked2(int number);
protected:
void mousePressEvent(QMouseEvent *event) override;
private slots:
void on_clicked();
};
#endif // TOGGLETOOLBUTTON_H
toggletoolbutton.cpp
ここをクリックして展開
#include "toggletoolbutton.h"
#include <QDebug>
ToggleToolButton::ToggleToolButton(int _number)
{
number = _number;
this->setCheckable(true);
this->setMinimumHeight(60);
this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
connect(this, &ToggleToolButton::clicked, this, &ToggleToolButton::on_clicked );
}
void ToggleToolButton::mousePressEvent(QMouseEvent *event)
{
if (this->isChecked()) { return; }
return QToolButton::mousePressEvent(event);
}
void ToggleToolButton::on_clicked()
{
qDebug() << number;
emit clicked2(number);
}