Qt6で作るコミックビューワー

2022/02/23 categories:Qt6| tags:Qt6|Qt6.2.3|C++|

以前作成したPyQt5のコミックビューワーっぽいアプリをC++に書き換えてみました。

実装した主な機能

動作の様子は以下の通りです。

フォルダを読み込むダイアログ

 フォルダを読み込むダイアログは、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を使うとジェスチャーを扱うことができるようです。今回書いたコードは以下のような処理にしました。

コードは以下の通りです。

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);
}

Share post

Related Posts

Comments

comments powered by Disqus