-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
508 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
set(PROJECT_SOURCES | ||
imagecarousel.cc | ||
imagecarousel.hpp | ||
imagecarouselwidget.hpp | ||
imagecarouselwidget.cc | ||
main.cc | ||
mainwindow.cc | ||
mainwindow.hpp) | ||
|
||
qt_add_executable(ImageCarousel MANUAL_FINALIZATION ${PROJECT_SOURCES}) | ||
target_link_libraries(ImageCarousel PRIVATE Qt6::Widgets) | ||
qt_finalize_executable(ImageCarousel) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
QT += core gui | ||
|
||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets | ||
|
||
CONFIG += c++17 | ||
|
||
# You can make your code fail to compile if it uses deprecated APIs. | ||
# In order to do so, uncomment the following line. | ||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 | ||
|
||
SOURCES += \ | ||
imagecarousel.cc \ | ||
imagecarouselwidget.cc \ | ||
main.cc \ | ||
mainwindow.cc | ||
|
||
HEADERS += \ | ||
imagecarousel.hpp \ | ||
imagecarouselwidget.hpp \ | ||
mainwindow.hpp | ||
|
||
# Default rules for deployment. | ||
qnx: target.path = /tmp/$${TARGET}/bin | ||
else: unix:!android: target.path = /opt/$${TARGET}/bin | ||
!isEmpty(target.path): INSTALLS += target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
#include "imagecarousel.hpp" | ||
|
||
#include <QGraphicsPixmapItem> | ||
#include <QTimer> | ||
|
||
class ImageCarousel::ImageCarouselPrivate | ||
{ | ||
public: | ||
explicit ImageCarouselPrivate(ImageCarousel *q) | ||
: q_ptr(q) | ||
{ | ||
timer = new QTimer(q); | ||
timer->setSingleShot(false); | ||
} | ||
|
||
ImageCarousel *q_ptr; | ||
|
||
QTimer *timer; | ||
int msec = 1000; | ||
int index = 0; | ||
QList<QGraphicsPixmapItem *> items; | ||
}; | ||
|
||
ImageCarousel::ImageCarousel(QWidget *parent) | ||
: QGraphicsView(parent) | ||
, d_ptr(new ImageCarouselPrivate(this)) | ||
{ | ||
setScene(new QGraphicsScene(this)); | ||
setViewportUpdateMode(SmartViewportUpdate); | ||
setFrameShape(QFrame::NoFrame); | ||
setRenderHint(QPainter::SmoothPixmapTransform); | ||
|
||
connect(d_ptr->timer, &QTimer::timeout, this, &ImageCarousel::next); | ||
} | ||
|
||
ImageCarousel::~ImageCarousel() = default; | ||
|
||
auto ImageCarousel::addImage(const QString &filename) -> bool | ||
{ | ||
auto pixmap = QPixmap(filename); | ||
if (pixmap.isNull()) { | ||
return false; | ||
} | ||
|
||
auto *item = new QGraphicsPixmapItem(pixmap); | ||
item->setVisible(false); | ||
scene()->addItem(item); | ||
d_ptr->items.append(item); | ||
|
||
if (d_ptr->items.count() == 1) { | ||
item->setVisible(true); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
auto ImageCarousel::addImages(const QStringList &filenames) -> int | ||
{ | ||
int count = 0; | ||
for (const auto &filename : qAsConst(filenames)) { | ||
if (addImage(filename)) { | ||
++count; | ||
} | ||
} | ||
return count; | ||
} | ||
|
||
void ImageCarousel::clearImages() | ||
{ | ||
for (auto item : qAsConst(d_ptr->items)) { | ||
scene()->removeItem(item); | ||
delete item; | ||
} | ||
d_ptr->items.clear(); | ||
} | ||
|
||
auto ImageCarousel::imageCount() const -> int | ||
{ | ||
return d_ptr->items.count(); | ||
} | ||
|
||
void ImageCarousel::start() | ||
{ | ||
d_ptr->timer->start(d_ptr->msec); | ||
} | ||
|
||
void ImageCarousel::stop() | ||
{ | ||
d_ptr->timer->stop(); | ||
} | ||
|
||
void ImageCarousel::setInterval(int msec) | ||
{ | ||
d_ptr->msec = msec; | ||
} | ||
|
||
auto ImageCarousel::interval() const -> int | ||
{ | ||
return d_ptr->msec; | ||
} | ||
|
||
void ImageCarousel::onImageChanged(int index) | ||
{ | ||
Q_ASSERT(index >= 0 && index < d_ptr->items.count()); | ||
|
||
d_ptr->items[d_ptr->index]->setVisible(false); | ||
d_ptr->index = index; | ||
d_ptr->items[d_ptr->index]->setVisible(true); | ||
|
||
resetItem(); | ||
} | ||
|
||
void ImageCarousel::next() | ||
{ | ||
if (d_ptr->items.isEmpty()) { | ||
return; | ||
} | ||
|
||
d_ptr->items[d_ptr->index]->setVisible(false); | ||
d_ptr->index = (d_ptr->index + 1) % d_ptr->items.count(); | ||
d_ptr->items[d_ptr->index]->setVisible(true); | ||
|
||
emit imageChanged(d_ptr->index); | ||
|
||
resetItem(); | ||
} | ||
|
||
void ImageCarousel::resetItem() | ||
{ | ||
auto item = d_ptr->items[d_ptr->index]; | ||
scene()->setSceneRect(item->boundingRect()); | ||
resetTransform(); | ||
auto size = item->pixmap().size(); | ||
if (size.width() > width() || size.height() > height()) { | ||
fitInView(item, Qt::KeepAspectRatio); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#ifndef IMAGECAROUSEL_HPP | ||
#define IMAGECAROUSEL_HPP | ||
|
||
// qt image carousel control class | ||
|
||
#include <QGraphicsView> | ||
|
||
class ImageCarousel : public QGraphicsView | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit ImageCarousel(QWidget *parent = nullptr); | ||
~ImageCarousel() override; | ||
|
||
auto addImage(const QString &filename) -> bool; | ||
auto addImages(const QStringList &filenames) -> int; | ||
void clearImages(); | ||
|
||
[[nodiscard]] auto imageCount() const -> int; | ||
|
||
void start(); | ||
void stop(); | ||
|
||
void setInterval(int msec); | ||
[[nodiscard]] auto interval() const -> int; | ||
|
||
public slots: | ||
void onImageChanged(int index); | ||
|
||
signals: | ||
void imageChanged(int index); | ||
|
||
private slots: | ||
void next(); | ||
|
||
private: | ||
void resetItem(); | ||
|
||
class ImageCarouselPrivate; | ||
QScopedPointer<ImageCarouselPrivate> d_ptr; | ||
}; | ||
|
||
#endif // IMAGECAROUSEL_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#include "imagecarouselwidget.hpp" | ||
#include "imagecarousel.hpp" | ||
|
||
#include <QtWidgets> | ||
|
||
class ImageCarouselWidget::ImageCarouselWidgetPrivate | ||
{ | ||
public: | ||
ImageCarouselWidgetPrivate(ImageCarouselWidget *q) | ||
: q_ptr{q} | ||
{ | ||
carousel = new ImageCarousel{q}; | ||
btnGroup = new QButtonGroup{q}; | ||
btnGroup->setExclusive(true); | ||
layout = new QVBoxLayout{q}; | ||
|
||
layout->addWidget(carousel); | ||
} | ||
~ImageCarouselWidgetPrivate() = default; | ||
|
||
void resetBtnWidget() | ||
{ | ||
auto btns = btnGroup->buttons(); | ||
for (auto btn : btns) { | ||
btnGroup->removeButton(btn); | ||
delete btn; | ||
} | ||
if (!btnWidget.isNull()) { | ||
delete btnWidget.data(); | ||
} | ||
btnWidget = new QWidget(q_ptr); | ||
layout->addWidget(btnWidget.data()); | ||
auto btnLayout = new QHBoxLayout{btnWidget.data()}; | ||
btnLayout->addStretch(); | ||
auto count = carousel->imageCount(); | ||
for (auto i = 0; i < count; ++i) { | ||
auto btn = new QRadioButton{btnWidget.data()}; | ||
btnLayout->addWidget(btn); | ||
btnGroup->addButton(btn, i); | ||
} | ||
btnLayout->addStretch(); | ||
} | ||
|
||
ImageCarouselWidget *q_ptr; | ||
|
||
ImageCarousel *carousel; | ||
QPointer<QWidget> btnWidget; | ||
QButtonGroup *btnGroup; | ||
QVBoxLayout *layout; | ||
}; | ||
|
||
ImageCarouselWidget::ImageCarouselWidget(QWidget *parent) | ||
: QWidget{parent} | ||
, d_ptr{new ImageCarouselWidgetPrivate{this}} | ||
{ | ||
buildConnect(); | ||
} | ||
|
||
ImageCarouselWidget::~ImageCarouselWidget() = default; | ||
|
||
void ImageCarouselWidget::addImage(const QString &filename) | ||
{ | ||
d_ptr->carousel->addImage(filename); | ||
|
||
d_ptr->resetBtnWidget(); | ||
} | ||
|
||
void ImageCarouselWidget::addImages(const QStringList &filenames) | ||
{ | ||
d_ptr->carousel->addImages(filenames); | ||
|
||
d_ptr->resetBtnWidget(); | ||
} | ||
|
||
void ImageCarouselWidget::clearImages() | ||
{ | ||
d_ptr->carousel->clearImages(); | ||
|
||
d_ptr->resetBtnWidget(); | ||
} | ||
|
||
void ImageCarouselWidget::start() | ||
{ | ||
d_ptr->carousel->start(); | ||
} | ||
|
||
void ImageCarouselWidget::stop() | ||
{ | ||
d_ptr->carousel->stop(); | ||
} | ||
|
||
void ImageCarouselWidget::setInterval(int msec) | ||
{ | ||
d_ptr->carousel->setInterval(msec); | ||
} | ||
|
||
auto ImageCarouselWidget::interval() const -> int | ||
{ | ||
return d_ptr->carousel->interval(); | ||
} | ||
|
||
void ImageCarouselWidget::onImageChanged(int index) | ||
{ | ||
auto btn = d_ptr->btnGroup->button(index); | ||
if (btn) { | ||
btn->setChecked(true); | ||
} | ||
} | ||
|
||
void ImageCarouselWidget::buildConnect() | ||
{ | ||
connect(d_ptr->carousel, | ||
&ImageCarousel::imageChanged, | ||
this, | ||
&ImageCarouselWidget::onImageChanged); | ||
connect(d_ptr->btnGroup, | ||
&QButtonGroup::idClicked, | ||
d_ptr->carousel, | ||
&ImageCarousel::onImageChanged); | ||
} |
Oops, something went wrong.